mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Fill empty behavior parameters in actions/conditions when a behavior is attached to an object (#6633)
This commit is contained in:
65
Core/GDCore/IDE/Events/BehaviorParametersFiller.cpp
Normal file
65
Core/GDCore/IDE/Events/BehaviorParametersFiller.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2024 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "BehaviorParametersFiller.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Instruction.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
bool BehaviorParametersFiller::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 ¶meterMetadata,
|
||||
const gd::Expression ¶meterValue, size_t parameterIndex,
|
||||
const gd::String &lastObjectName) {
|
||||
if (parameterMetadata.GetValueTypeMetadata().IsBehavior() &&
|
||||
parameterValue.GetPlainString().length() == 0) {
|
||||
|
||||
auto &expectedBehaviorTypeName =
|
||||
parameterMetadata.GetValueTypeMetadata().GetExtraInfo();
|
||||
|
||||
auto &objectsContainersList =
|
||||
projectScopedContainers.GetObjectsContainersList();
|
||||
auto behaviorNames =
|
||||
objectsContainersList.GetBehaviorsOfObject(lastObjectName, true);
|
||||
|
||||
gd::String foundBehaviorName = "";
|
||||
for (auto &behaviorName : behaviorNames) {
|
||||
auto behaviorTypeName =
|
||||
objectsContainersList.GetTypeOfBehavior(behaviorName, false);
|
||||
if (behaviorTypeName == expectedBehaviorTypeName) {
|
||||
foundBehaviorName = behaviorName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundBehaviorName.empty()) {
|
||||
instruction.SetParameter(parameterIndex,
|
||||
gd::Expression(foundBehaviorName));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
BehaviorParametersFiller::~BehaviorParametersFiller() {}
|
||||
|
||||
} // namespace gd
|
45
Core/GDCore/IDE/Events/BehaviorParametersFiller.h
Normal file
45
Core/GDCore/IDE/Events/BehaviorParametersFiller.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2024 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace gd {
|
||||
class Instruction;
|
||||
class Platform;
|
||||
class ProjectScopedContainers;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Fill empty behavior parameters with any behavior that matches the
|
||||
* required behavior type.
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API BehaviorParametersFiller : public ArbitraryEventsWorker {
|
||||
public:
|
||||
BehaviorParametersFiller(
|
||||
const gd::Platform &platform_,
|
||||
const gd::ProjectScopedContainers &projectScopedContainers_)
|
||||
: platform(platform_),
|
||||
projectScopedContainers(projectScopedContainers_){};
|
||||
virtual ~BehaviorParametersFiller();
|
||||
|
||||
private:
|
||||
bool DoVisitInstruction(gd::Instruction &instruction,
|
||||
bool isCondition) override;
|
||||
|
||||
const gd::Platform &platform;
|
||||
const gd::ProjectScopedContainers &projectScopedContainers;
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -26,6 +26,7 @@
|
||||
#include "GDCore/IDE/Events/InstructionsTypeRenamer.h"
|
||||
#include "GDCore/IDE/Events/LinkEventTargetRenamer.h"
|
||||
#include "GDCore/IDE/Events/ProjectElementRenamer.h"
|
||||
#include "GDCore/IDE/Events/BehaviorParametersFiller.h"
|
||||
#include "GDCore/IDE/EventsFunctionTools.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryBehaviorSharedDataWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryEventBasedBehaviorsWorker.h"
|
||||
@@ -1537,6 +1538,16 @@ void WholeProjectRefactorer::ObjectRemovedInLayout(
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::BehaviorsAddedToObjectInLayout(
|
||||
gd::Project &project, gd::Layout &layout, const gd::String &objectName) {
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
|
||||
gd::BehaviorParametersFiller behaviorParameterFiller(
|
||||
project.GetCurrentPlatform(), projectScopedContainers);
|
||||
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
|
||||
project, layout, behaviorParameterFiller);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
|
||||
gd::Project &project, gd::Layout &layout, const gd::String &oldName,
|
||||
const gd::String &newName, bool isObjectGroup) {
|
||||
@@ -1801,6 +1812,17 @@ void WholeProjectRefactorer::GlobalObjectRemoved(
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::BehaviorsAddedToGlobalObject(
|
||||
gd::Project &project, const gd::String &objectName) {
|
||||
for (std::size_t i = 0; i < project.GetLayoutsCount(); ++i) {
|
||||
gd::Layout &layout = project.GetLayout(i);
|
||||
if (layout.HasObjectNamed(objectName))
|
||||
continue;
|
||||
|
||||
BehaviorsAddedToObjectInLayout(project, layout, objectName);
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RemoveLayer(gd::Project &project,
|
||||
gd::Layout &layout,
|
||||
const gd::String &layerName) {
|
||||
|
@@ -395,6 +395,18 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
gd::Layout& layout,
|
||||
const gd::String& objectName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project after behaviors are added to an object in a
|
||||
* layout.
|
||||
*
|
||||
* This will update the layout, all external events associated with it.
|
||||
* The refactor is actually applied to all objects because it allow to handle
|
||||
* groups.
|
||||
*/
|
||||
static void BehaviorsAddedToObjectInLayout(gd::Project &project,
|
||||
gd::Layout &layout,
|
||||
const gd::String &objectName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project after an object is removed in an events-based
|
||||
* object.
|
||||
@@ -467,6 +479,16 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
static void GlobalObjectRemoved(gd::Project& project,
|
||||
const gd::String& objectName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project after behaviors are added a global object.
|
||||
*
|
||||
* This will update all the layouts, all external events associated with them.
|
||||
* The refactor is actually applied to all objects because it allow to handle
|
||||
* groups.
|
||||
*/
|
||||
void BehaviorsAddedToGlobalObject(gd::Project &project,
|
||||
const gd::String &objectName);
|
||||
|
||||
/**
|
||||
* \brief Return the set of all the types of the objects that are using the
|
||||
* given behavior.
|
||||
|
@@ -1475,6 +1475,41 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Behaviors added to an object (in layout)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
auto &scene = project.InsertNewLayout("Scene", 0);
|
||||
auto &object =
|
||||
scene.InsertNewObject(project, "MyExtension::Sprite", "Object", 0);
|
||||
|
||||
gd::StandardEvent &event =
|
||||
dynamic_cast<gd::StandardEvent &>(scene.GetEvents().InsertNewEvent(
|
||||
project, "BuiltinCommonInstructions::Standard"));
|
||||
// Add a behavior instruction using an object that doesn't have the
|
||||
// behavior.
|
||||
{
|
||||
gd::Instruction action;
|
||||
action.SetType("MyExtension::BehaviorDoSomething");
|
||||
action.SetParametersCount(3);
|
||||
action.SetParameter(0, gd::Expression("Object"));
|
||||
// The behavior parameter is left empty.
|
||||
action.SetParameter(1, gd::Expression(""));
|
||||
action.SetParameter(2, gd::Expression("0"));
|
||||
event.GetActions().Insert(action);
|
||||
}
|
||||
|
||||
// Attach the behavior to the object.
|
||||
object.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
|
||||
gd::WholeProjectRefactorer::BehaviorsAddedToObjectInLayout(project, scene,
|
||||
"Object");
|
||||
|
||||
// The behavior parameter is now filled.
|
||||
REQUIRE(event.GetActions()[0].GetParameter(1).GetPlainString() ==
|
||||
"MyBehavior");
|
||||
}
|
||||
|
||||
SECTION("Object renamed (in events function)") {
|
||||
SECTION("Group") {
|
||||
gd::Project project;
|
||||
|
@@ -2438,6 +2438,10 @@ interface WholeProjectRefactorer {
|
||||
[Ref] Project project,
|
||||
[Ref] Layout layout,
|
||||
[Const] DOMString objectName);
|
||||
void STATIC_BehaviorsAddedToObjectInLayout(
|
||||
[Ref] Project project,
|
||||
[Ref] Layout layout,
|
||||
[Const] DOMString objectName);
|
||||
void STATIC_ObjectOrGroupRenamedInEventsFunction([Ref] Project project, [Ref] EventsFunction eventsFunction, [Ref] ObjectsContainer globalObjectsContainer, [Ref] ObjectsContainer objectsContainer, [Const] DOMString oldName, [Const] DOMString newName, boolean isObjectGroup);
|
||||
void STATIC_ObjectRemovedInEventsFunction(
|
||||
[Ref] Project project,
|
||||
@@ -2456,6 +2460,9 @@ interface WholeProjectRefactorer {
|
||||
void STATIC_GlobalObjectRemoved(
|
||||
[Ref] Project project,
|
||||
[Const] DOMString objectName);
|
||||
void STATIC_BehaviorsAddedToGlobalObject(
|
||||
[Ref] Project project,
|
||||
[Const] DOMString objectName);
|
||||
[Value] SetString STATIC_GetAllObjectTypesUsingEventsBasedBehavior([Const, Ref] Project project, [Const, Ref] EventsFunctionsExtension eventsFunctionsExtension, [Const, Ref] EventsBasedBehavior eventsBasedBehavior);
|
||||
void STATIC_EnsureBehaviorEventsFunctionsProperParameters([Const, Ref] EventsFunctionsExtension eventsFunctionsExtension, [Const, Ref] EventsBasedBehavior eventsBasedBehavior);
|
||||
void STATIC_EnsureObjectEventsFunctionsProperParameters([Const, Ref] EventsFunctionsExtension eventsFunctionsExtension, [Const, Ref] EventsBasedObject eventsBasedObject);
|
||||
|
@@ -644,6 +644,7 @@ typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
|
||||
#define STATIC_Date Date
|
||||
#define STATIC_ObjectOrGroupRenamedInLayout ObjectOrGroupRenamedInLayout
|
||||
#define STATIC_ObjectRemovedInLayout ObjectRemovedInLayout
|
||||
#define STATIC_BehaviorsAddedToObjectInLayout BehaviorsAddedToObjectInLayout
|
||||
#define STATIC_ObjectRemovedInEventsFunction \
|
||||
ObjectRemovedInEventsFunction
|
||||
#define STATIC_ObjectOrGroupRenamedInEventsFunction \
|
||||
@@ -654,6 +655,7 @@ typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
|
||||
ObjectOrGroupRenamedInEventsBasedObject
|
||||
#define STATIC_GlobalObjectOrGroupRenamed GlobalObjectOrGroupRenamed
|
||||
#define STATIC_GlobalObjectRemoved GlobalObjectRemoved
|
||||
#define STATIC_BehaviorsAddedToGlobalObject BehaviorsAddedToGlobalObject
|
||||
#define STATIC_GetAllObjectTypesUsingEventsBasedBehavior \
|
||||
GetAllObjectTypesUsingEventsBasedBehavior
|
||||
#define STATIC_EnsureBehaviorEventsFunctionsProperParameters \
|
||||
|
2
GDevelop.js/types.d.ts
vendored
2
GDevelop.js/types.d.ts
vendored
@@ -1829,12 +1829,14 @@ export class WholeProjectRefactorer extends EmscriptenObject {
|
||||
static renameObjectEffect(project: Project, layout: Layout, gdObject: gdObject, oldName: string, newName: string): void;
|
||||
static objectOrGroupRenamedInLayout(project: Project, layout: Layout, oldName: string, newName: string, isObjectGroup: boolean): void;
|
||||
static objectRemovedInLayout(project: Project, layout: Layout, objectName: string): void;
|
||||
static behaviorsAddedToObjectInLayout(project: Project, layout: Layout, objectName: string): void;
|
||||
static objectOrGroupRenamedInEventsFunction(project: Project, eventsFunction: EventsFunction, globalObjectsContainer: ObjectsContainer, objectsContainer: ObjectsContainer, oldName: string, newName: string, isObjectGroup: boolean): void;
|
||||
static objectRemovedInEventsFunction(project: Project, eventsFunction: EventsFunction, globalObjectsContainer: ObjectsContainer, objectsContainer: ObjectsContainer, objectName: string): void;
|
||||
static objectOrGroupRenamedInEventsBasedObject(project: Project, globalObjectsContainer: ObjectsContainer, eventsBasedObject: EventsBasedObject, oldName: string, newName: string, isObjectGroup: boolean): void;
|
||||
static objectRemovedInEventsBasedObject(project: Project, eventsBasedObject: EventsBasedObject, globalObjectsContainer: ObjectsContainer, objectsContainer: ObjectsContainer, objectName: string): void;
|
||||
static globalObjectOrGroupRenamed(project: Project, oldName: string, newName: string, isObjectGroup: boolean): void;
|
||||
static globalObjectRemoved(project: Project, objectName: string): void;
|
||||
static behaviorsAddedToGlobalObject(project: Project, objectName: string): void;
|
||||
static getAllObjectTypesUsingEventsBasedBehavior(project: Project, eventsFunctionsExtension: EventsFunctionsExtension, eventsBasedBehavior: EventsBasedBehavior): SetString;
|
||||
static ensureBehaviorEventsFunctionsProperParameters(eventsFunctionsExtension: EventsFunctionsExtension, eventsBasedBehavior: EventsBasedBehavior): void;
|
||||
static ensureObjectEventsFunctionsProperParameters(eventsFunctionsExtension: EventsFunctionsExtension, eventsBasedObject: EventsBasedObject): void;
|
||||
|
@@ -25,12 +25,14 @@ declare class gdWholeProjectRefactorer {
|
||||
static renameObjectEffect(project: gdProject, layout: gdLayout, gdObject: gdObject, oldName: string, newName: string): void;
|
||||
static objectOrGroupRenamedInLayout(project: gdProject, layout: gdLayout, oldName: string, newName: string, isObjectGroup: boolean): void;
|
||||
static objectRemovedInLayout(project: gdProject, layout: gdLayout, objectName: string): void;
|
||||
static behaviorsAddedToObjectInLayout(project: gdProject, layout: gdLayout, objectName: string): void;
|
||||
static objectOrGroupRenamedInEventsFunction(project: gdProject, eventsFunction: gdEventsFunction, globalObjectsContainer: gdObjectsContainer, objectsContainer: gdObjectsContainer, oldName: string, newName: string, isObjectGroup: boolean): void;
|
||||
static objectRemovedInEventsFunction(project: gdProject, eventsFunction: gdEventsFunction, globalObjectsContainer: gdObjectsContainer, objectsContainer: gdObjectsContainer, objectName: string): void;
|
||||
static objectOrGroupRenamedInEventsBasedObject(project: gdProject, globalObjectsContainer: gdObjectsContainer, eventsBasedObject: gdEventsBasedObject, oldName: string, newName: string, isObjectGroup: boolean): void;
|
||||
static objectRemovedInEventsBasedObject(project: gdProject, eventsBasedObject: gdEventsBasedObject, globalObjectsContainer: gdObjectsContainer, objectsContainer: gdObjectsContainer, objectName: string): void;
|
||||
static globalObjectOrGroupRenamed(project: gdProject, oldName: string, newName: string, isObjectGroup: boolean): void;
|
||||
static globalObjectRemoved(project: gdProject, objectName: string): void;
|
||||
static behaviorsAddedToGlobalObject(project: gdProject, objectName: string): void;
|
||||
static getAllObjectTypesUsingEventsBasedBehavior(project: gdProject, eventsFunctionsExtension: gdEventsFunctionsExtension, eventsBasedBehavior: gdEventsBasedBehavior): gdSetString;
|
||||
static ensureBehaviorEventsFunctionsProperParameters(eventsFunctionsExtension: gdEventsFunctionsExtension, eventsBasedBehavior: gdEventsBasedBehavior): void;
|
||||
static ensureObjectEventsFunctionsProperParameters(eventsFunctionsExtension: gdEventsFunctionsExtension, eventsBasedObject: gdEventsBasedObject): void;
|
||||
|
@@ -1832,6 +1832,18 @@ export default class SceneEditor extends React.Component<Props, State> {
|
||||
this.reloadResourcesFor(
|
||||
editedObjectWithContext.object
|
||||
);
|
||||
if (editedObjectWithContext.global) {
|
||||
gd.WholeProjectRefactorer.behaviorsAddedToGlobalObject(
|
||||
project,
|
||||
editedObjectWithContext.object.getName()
|
||||
);
|
||||
} else {
|
||||
gd.WholeProjectRefactorer.behaviorsAddedToObjectInLayout(
|
||||
project,
|
||||
layout,
|
||||
editedObjectWithContext.object.getName()
|
||||
);
|
||||
}
|
||||
}
|
||||
this.editObject(null);
|
||||
this.updateBehaviorsSharedData();
|
||||
|
Reference in New Issue
Block a user