mirror of
https://github.com/Heretek-AI/GDevelop.git
synced 2026-07-25 04:15:49 -04:00
Fix property value loss when renaming a property in the extension editor (#8211)
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
#include "BehaviorPropertyRenamer.h"
|
||||
|
||||
#include "GDCore/Events/Instruction.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/IDE/WholeProjectRefactorer.h"
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
void BehaviorPropertyRenamer::DoVisitBehavior(gd::Behavior &behavior) {
|
||||
if (behavior.GetTypeName() == behaviorType) {
|
||||
behavior.RenameProperty(oldName, newName);
|
||||
}
|
||||
};
|
||||
|
||||
BehaviorPropertyRenamer::~BehaviorPropertyRenamer() {}
|
||||
|
||||
} // namespace gd
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2026 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <set>
|
||||
|
||||
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class Object;
|
||||
class Behavior;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Rename a property in behaviors of all objects.
|
||||
*/
|
||||
class GD_CORE_API BehaviorPropertyRenamer : public ArbitraryObjectsWorker {
|
||||
public:
|
||||
BehaviorPropertyRenamer(const gd::String &behaviorType_,
|
||||
const gd::String &oldName_,
|
||||
const gd::String &newName_)
|
||||
: behaviorType(behaviorType_), oldName(oldName_), newName(newName_){};
|
||||
virtual ~BehaviorPropertyRenamer();
|
||||
|
||||
private:
|
||||
void DoVisitBehavior(gd::Behavior &behavior) override;
|
||||
|
||||
gd::String behaviorType;
|
||||
gd::String oldName;
|
||||
gd::String newName;
|
||||
};
|
||||
|
||||
}; // namespace gd
|
||||
@@ -4,8 +4,7 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef GDCORE_BEHAVIORTYPERENAMER_H
|
||||
#define GDCORE_BEHAVIORTYPERENAMER_H
|
||||
#pragma once
|
||||
#include <set>
|
||||
|
||||
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
|
||||
@@ -34,5 +33,3 @@ class GD_CORE_API BehaviorTypeRenamer : public ArbitraryObjectsWorker {
|
||||
};
|
||||
|
||||
}; // namespace gd
|
||||
|
||||
#endif // GDCORE_BEHAVIORTYPERENAMER_H
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#include "ObjectPropertyRenamer.h"
|
||||
|
||||
#include "GDCore/Events/Instruction.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/IDE/WholeProjectRefactorer.h"
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
void ObjectPropertyRenamer::DoVisitObject(gd::Object &object) {
|
||||
if (object.GetType() == objectType) {
|
||||
object.GetConfiguration().RenameProperty(oldName, newName);
|
||||
}
|
||||
};
|
||||
|
||||
ObjectPropertyRenamer::~ObjectPropertyRenamer() {}
|
||||
|
||||
} // namespace gd
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2026 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <set>
|
||||
|
||||
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class Object;
|
||||
class Behavior;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Rename a property in all custom objects of a given type.
|
||||
*/
|
||||
class GD_CORE_API ObjectPropertyRenamer : public ArbitraryObjectsWorker {
|
||||
public:
|
||||
ObjectPropertyRenamer(const gd::String &objectType_,
|
||||
const gd::String &oldName_, const gd::String &newName_)
|
||||
: objectType(objectType_), oldName(oldName_), newName(newName_){};
|
||||
virtual ~ObjectPropertyRenamer();
|
||||
|
||||
private:
|
||||
void DoVisitObject(gd::Object &object) override;
|
||||
|
||||
gd::String objectType;
|
||||
gd::String oldName;
|
||||
gd::String newName;
|
||||
};
|
||||
|
||||
}; // namespace gd
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "GDCore/IDE/EventBasedObjectBrowser.h"
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/IDE/Events/BehaviorParametersFiller.h"
|
||||
#include "GDCore/IDE/Events/BehaviorPropertyRenamer.h"
|
||||
#include "GDCore/IDE/Events/BehaviorTypeRenamer.h"
|
||||
#include "GDCore/IDE/Events/CustomObjectTypeRenamer.h"
|
||||
#include "GDCore/IDE/Events/EventsBehaviorRenamer.h"
|
||||
@@ -30,6 +31,7 @@
|
||||
#include "GDCore/IDE/Events/InstructionsTypeRenamer.h"
|
||||
#include "GDCore/IDE/Events/LinkEventTargetRenamer.h"
|
||||
#include "GDCore/IDE/Events/LeaderboardIdRenamer.h"
|
||||
#include "GDCore/IDE/Events/ObjectPropertyRenamer.h"
|
||||
#include "GDCore/IDE/Events/ProjectElementRenamer.h"
|
||||
#include "GDCore/IDE/Project/BehaviorObjectTypeRenamer.h"
|
||||
#include "GDCore/IDE/Project/BehaviorsSharedDataBehaviorTypeRenamer.h"
|
||||
@@ -1021,6 +1023,14 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
|
||||
auto &properties = eventsBasedBehavior.GetPropertyDescriptors();
|
||||
if (!properties.Has(oldPropertyName))
|
||||
return;
|
||||
const auto &behaviorType = gd::PlatformExtension::GetBehaviorFullType(
|
||||
eventsFunctionsExtension.GetName(), eventsBasedBehavior.GetName());
|
||||
|
||||
// Rename the property in behaviors of all objects.
|
||||
const WholeProjectBrowser projectBrowser;
|
||||
auto behaviorPropertyRenamer = gd::BehaviorPropertyRenamer(
|
||||
behaviorType, oldPropertyName, newPropertyName);
|
||||
projectBrowser.ExposeObjects(project, behaviorPropertyRenamer);
|
||||
|
||||
if (properties.Get(oldPropertyName).GetType() == "Behavior") {
|
||||
// This is a property representing another behavior that must exist on the
|
||||
@@ -1049,8 +1059,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
|
||||
gd::ExpressionsRenamer expressionRenamer =
|
||||
gd::ExpressionsRenamer(project.GetCurrentPlatform());
|
||||
expressionRenamer.SetReplacedBehaviorExpression(
|
||||
gd::PlatformExtension::GetBehaviorFullType(
|
||||
eventsFunctionsExtension.GetName(), eventsBasedBehavior.GetName()),
|
||||
behaviorType,
|
||||
EventsBasedBehavior::GetPropertyExpressionName(oldPropertyName),
|
||||
EventsBasedBehavior::GetPropertyExpressionName(newPropertyName));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
|
||||
@@ -1173,6 +1182,14 @@ void WholeProjectRefactorer::RenameEventsBasedObjectProperty(
|
||||
auto &properties = eventsBasedObject.GetPropertyDescriptors();
|
||||
if (!properties.Has(oldPropertyName))
|
||||
return;
|
||||
const auto &objectType = gd::PlatformExtension::GetObjectFullType(
|
||||
eventsFunctionsExtension.GetName(), eventsBasedObject.GetName());
|
||||
|
||||
// Rename the property in all custom objects of this type.
|
||||
const WholeProjectBrowser projectBrowser;
|
||||
auto objectPropertyRenamer =
|
||||
gd::ObjectPropertyRenamer(objectType, oldPropertyName, newPropertyName);
|
||||
projectBrowser.ExposeObjects(project, objectPropertyRenamer);
|
||||
|
||||
// Properties that represent primitive values will be used through
|
||||
// their related actions/conditions/expressions. Rename these.
|
||||
@@ -1185,8 +1202,7 @@ void WholeProjectRefactorer::RenameEventsBasedObjectProperty(
|
||||
gd::ExpressionsRenamer expressionRenamer =
|
||||
gd::ExpressionsRenamer(project.GetCurrentPlatform());
|
||||
expressionRenamer.SetReplacedObjectExpression(
|
||||
gd::PlatformExtension::GetObjectFullType(
|
||||
eventsFunctionsExtension.GetName(), eventsBasedObject.GetName()),
|
||||
objectType,
|
||||
EventsBasedObject::GetPropertyExpressionName(oldPropertyName),
|
||||
EventsBasedObject::GetPropertyExpressionName(newPropertyName));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
|
||||
|
||||
@@ -87,6 +87,17 @@ class GD_CORE_API BehaviorConfigurationContainer {
|
||||
return UpdateProperty(content, name, value);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Called when the IDE wants to rename a custom property of the object
|
||||
* configuration.
|
||||
*
|
||||
* \return false if properties can't be renamed
|
||||
*/
|
||||
virtual bool RenameProperty(const gd::String &oldName,
|
||||
const gd::String &newName) {
|
||||
return RenameProperty(content, oldName, newName);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Called to initialize the content with the default properties
|
||||
* for the behavior.
|
||||
@@ -199,6 +210,18 @@ class GD_CORE_API BehaviorConfigurationContainer {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Called when the IDE wants to rename a custom property of the object
|
||||
* configuration.
|
||||
*
|
||||
* \return false if properties can't be renamed
|
||||
*/
|
||||
virtual bool RenameProperty(gd::SerializerElement &behaviorContent,
|
||||
const gd::String &oldName,
|
||||
const gd::String &newName) {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Called to initialize the content with the default properties
|
||||
* for the behavior.
|
||||
|
||||
@@ -58,3 +58,17 @@ bool CustomBehavior::UpdateProperty(gd::SerializerElement &behaviorContent,
|
||||
propertyName,
|
||||
newValue);
|
||||
}
|
||||
|
||||
bool CustomBehavior::RenameProperty(gd::SerializerElement &behaviorContent,
|
||||
const gd::String &oldName,
|
||||
const gd::String &newName) {
|
||||
if (!project.HasEventsBasedBehavior(GetTypeName())) {
|
||||
return false;
|
||||
}
|
||||
const auto &eventsBasedBehavior =
|
||||
project.GetEventsBasedBehavior(GetTypeName());
|
||||
const auto &properties = eventsBasedBehavior.GetPropertyDescriptors();
|
||||
|
||||
return gd::CustomConfigurationHelper::RenameProperty(
|
||||
properties, behaviorContent, oldName, newName);
|
||||
}
|
||||
|
||||
@@ -37,6 +37,9 @@ protected:
|
||||
bool UpdateProperty(gd::SerializerElement &behaviorContent,
|
||||
const gd::String &name, const gd::String &value) override;
|
||||
void InitializeContent(gd::SerializerElement &behaviorContent) override;
|
||||
bool RenameProperty(gd::SerializerElement &behaviorContent,
|
||||
const gd::String &oldName,
|
||||
const gd::String &newName) override;
|
||||
|
||||
private:
|
||||
const Project &project; ///< The project is used to get the
|
||||
|
||||
@@ -102,5 +102,19 @@ bool CustomConfigurationHelper::UpdateProperty(
|
||||
element.SetBoolValue(newValue == "1");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CustomConfigurationHelper::RenameProperty(
|
||||
const gd::PropertiesContainer &properties,
|
||||
gd::SerializerElement &configurationContent, const gd::String &oldName,
|
||||
const gd::String &newName) {
|
||||
if (!configurationContent.HasChild(oldName)) {
|
||||
return false;
|
||||
}
|
||||
auto &oldElement = configurationContent.GetChild(oldName);
|
||||
auto &newElement = configurationContent.AddChild(newName);
|
||||
newElement = oldElement;
|
||||
configurationContent.RemoveChild(oldName);
|
||||
return true;
|
||||
}
|
||||
@@ -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_CUSTOMCONFIGURATIONHELPER_H
|
||||
#define GDCORE_CUSTOMCONFIGURATIONHELPER_H
|
||||
#pragma once
|
||||
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||
@@ -38,7 +37,10 @@ public:
|
||||
gd::SerializerElement &behaviorContent,
|
||||
const gd::String &name,
|
||||
const gd::String &value);
|
||||
|
||||
static bool RenameProperty(const gd::PropertiesContainer &properties,
|
||||
gd::SerializerElement &behaviorContent,
|
||||
const gd::String &oldName,
|
||||
const gd::String &newName);
|
||||
};
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_CUSTOMCONFIGURATIONHELPER_H
|
||||
@@ -131,6 +131,20 @@ bool CustomObjectConfiguration::UpdateProperty(const gd::String& propertyName,
|
||||
newValue);
|
||||
}
|
||||
|
||||
bool CustomObjectConfiguration::RenameProperty(const gd::String& oldName, const gd::String& newName) {
|
||||
if (!project->HasEventsBasedObject(GetType())) {
|
||||
return false;
|
||||
}
|
||||
const auto &eventsBasedObject = project->GetEventsBasedObject(GetType());
|
||||
const auto &properties = eventsBasedObject.GetPropertyDescriptors();
|
||||
|
||||
return gd::CustomConfigurationHelper::RenameProperty(
|
||||
properties,
|
||||
objectContent,
|
||||
oldName,
|
||||
newName);
|
||||
};
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor>
|
||||
CustomObjectConfiguration::GetInitialInstanceProperties(
|
||||
const gd::InitialInstance &initialInstance) {
|
||||
|
||||
@@ -57,6 +57,7 @@ public:
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetProperties() const override;
|
||||
bool UpdateProperty(const gd::String& name, const gd::String& value) override;
|
||||
bool RenameProperty(const gd::String& oldName, const gd::String& newName) override;
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetInitialInstanceProperties(
|
||||
const gd::InitialInstance& instance) override;
|
||||
@@ -66,6 +67,7 @@ public:
|
||||
|
||||
void ExposeResources(gd::ArbitraryResourceWorker& worker) override;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Get the name of the events-based object variant used by this custom object.
|
||||
*/
|
||||
|
||||
@@ -99,6 +99,17 @@ class GD_CORE_API ObjectConfiguration {
|
||||
virtual bool UpdateProperty(const gd::String& name, const gd::String& value) {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Called when the IDE wants to rename a custom property of the object
|
||||
* configuration.
|
||||
*
|
||||
* \return false if properties can't be renamed
|
||||
*/
|
||||
virtual bool RenameProperty(const gd::String &oldName,
|
||||
const gd::String &newName) {
|
||||
return false;
|
||||
};
|
||||
///@}
|
||||
|
||||
/** \name Drawing and editing initial instances
|
||||
|
||||
@@ -1053,16 +1053,19 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
|
||||
// Add a property:
|
||||
eventsBasedBehavior.GetPropertyDescriptors()
|
||||
.InsertNew("MyProperty", 0)
|
||||
.SetType("Number");
|
||||
.SetType("Number")
|
||||
.SetValue("0");
|
||||
// Add a shared property:
|
||||
eventsBasedBehavior.GetSharedPropertyDescriptors()
|
||||
.InsertNew("MySharedProperty", 0)
|
||||
.SetType("Number");
|
||||
.SetType("Number")
|
||||
.SetValue("0");
|
||||
// The same name is used for another shared property to ensure there is no name
|
||||
// collision.
|
||||
eventsBasedBehavior.GetSharedPropertyDescriptors()
|
||||
.InsertNew("MyProperty", 0)
|
||||
.SetType("Number");
|
||||
.SetType("Number")
|
||||
.SetValue("0");
|
||||
}
|
||||
|
||||
// Add a events based object
|
||||
@@ -3660,6 +3663,37 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
"MyExtension::GetVariableAsNumber(MyVariable.MyChild[MyRenamedProperty])");
|
||||
}
|
||||
|
||||
SECTION("(Events based behavior) property renamed (in objects)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
auto &eventsBasedBehavior =
|
||||
eventsExtension.GetEventsBasedBehaviors().Get("MyEventsBasedBehavior");
|
||||
REQUIRE(eventsBasedBehavior.GetPropertyDescriptors().Has("MyProperty"));
|
||||
auto &property =
|
||||
eventsBasedBehavior.GetPropertyDescriptors().Get("MyProperty");
|
||||
|
||||
auto &layout = project.GetLayout("Scene");
|
||||
auto &object = layout.GetObjects().GetObject("ObjectWithMyBehavior");
|
||||
auto &behavior = object.GetBehavior("MyBehavior");
|
||||
behavior.UpdateProperty("MyProperty", "123");
|
||||
{
|
||||
auto properties = behavior.GetProperties();
|
||||
REQUIRE(properties.find("MyProperty") != properties.end());
|
||||
REQUIRE(properties.at("MyProperty").GetValue() == "123");
|
||||
}
|
||||
|
||||
gd::WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
|
||||
project, eventsExtension, eventsBasedBehavior, "MyProperty",
|
||||
"MyRenamedProperty");
|
||||
property.SetName("MyRenamedProperty");
|
||||
|
||||
auto properties = behavior.GetProperties();
|
||||
REQUIRE(properties.find("MyRenamedProperty") != properties.end());
|
||||
REQUIRE(properties.at("MyRenamedProperty").GetValue() == "123");
|
||||
}
|
||||
|
||||
SECTION("(Events based behavior) property renamed (in variable setter)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
@@ -3924,6 +3958,37 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
"MyExtension::GetVariableAsNumber(MyVariable.MyChild[MyRenamedProperty])");
|
||||
}
|
||||
|
||||
SECTION("(Events based object) property renamed (in objects)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
auto &eventsBasedObject =
|
||||
eventsExtension.GetEventsBasedObjects().Get("MyEventsBasedObject");
|
||||
REQUIRE(eventsBasedObject.GetPropertyDescriptors().Has("MyProperty"));
|
||||
auto &property =
|
||||
eventsBasedObject.GetPropertyDescriptors().Get("MyProperty");
|
||||
|
||||
auto &layout = project.GetLayout("Scene");
|
||||
auto &object = layout.GetObjects().GetObject("MyCustomObject");
|
||||
auto &objectConfiguration = object.GetConfiguration();
|
||||
objectConfiguration.UpdateProperty("MyProperty", "123");
|
||||
{
|
||||
auto properties = objectConfiguration.GetProperties();
|
||||
REQUIRE(properties.find("MyProperty") != properties.end());
|
||||
REQUIRE(properties.at("MyProperty").GetValue() == "123");
|
||||
}
|
||||
|
||||
gd::WholeProjectRefactorer::RenameEventsBasedObjectProperty(
|
||||
project, eventsExtension, eventsBasedObject, "MyProperty",
|
||||
"MyRenamedProperty");
|
||||
property.SetName("MyRenamedProperty");
|
||||
|
||||
auto properties = objectConfiguration.GetProperties();
|
||||
REQUIRE(properties.find("MyRenamedProperty") != properties.end());
|
||||
REQUIRE(properties.at("MyRenamedProperty").GetValue() == "123");
|
||||
}
|
||||
|
||||
SECTION("(Events based object) property renamed (in variable setter)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
|
||||
Reference in New Issue
Block a user