Skip to content

Commit

Permalink
Ensure behaviors are compatible with an object before pasting them
Browse files Browse the repository at this point in the history
  • Loading branch information
D8H committed Jan 23, 2025
1 parent 56ab2fd commit c2b869d
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 0 deletions.
57 changes: 57 additions & 0 deletions Core/GDCore/Project/ObjectTools.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* GDevelop Core
* Copyright 2008-2025 Florian Rival ([email protected]). All rights
* reserved. This project is released under the MIT License.
*/
#include "ObjectTools.h"

#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Platform.h"

namespace gd {

bool ObjectTools::IsBehaviorCompatibleWithObject(
const gd::Platform &platform, const gd::String &objectType,
const gd::String &behaviorType,
std::unordered_set<gd::String> coveredBehaviorType) {
bool isBehaviorTypeAlreadyCovered =
!coveredBehaviorType.insert(behaviorType).second;
if (isBehaviorTypeAlreadyCovered) {
return true;
}
const gd::BehaviorMetadata &behaviorMetadata =
MetadataProvider::GetBehaviorMetadata(platform, behaviorType);
if (MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
// Should not happen because the behavior was added successfully (so its
// metadata are valid) - but double check anyway and bail out if the
// behavior metadata are invalid.
return false;
}
if (!behaviorMetadata.GetObjectType().empty() &&
behaviorMetadata.GetObjectType() != objectType) {
return false;
}
for (const gd::String &requiredBehaviorType :
behaviorMetadata.GetRequiredBehaviorTypes()) {
const gd::BehaviorMetadata &requiredBehaviorMetadata =
gd::MetadataProvider::GetBehaviorMetadata(platform, requiredBehaviorType);
if (requiredBehaviorMetadata.IsHidden()) {
const gd::ObjectMetadata &objectMetadata =
gd::MetadataProvider::GetObjectMetadata(platform, objectType);
if (objectMetadata.GetDefaultBehaviors().find(requiredBehaviorType) ==
objectMetadata.GetDefaultBehaviors().end()) {
// A capability is missing in the object.
return false;
}
}
if (!gd::ObjectTools::IsBehaviorCompatibleWithObject(
platform, objectType, requiredBehaviorType, coveredBehaviorType)) {
return false;
}
}
return true;
}

} // namespace gd
35 changes: 35 additions & 0 deletions Core/GDCore/Project/ObjectTools.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* GDevelop Core
* Copyright 2008-2025 Florian Rival ([email protected]). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once

#include "GDCore/String.h"
#include <unordered_set>

namespace gd {
class Platform;
class Object;
} // namespace gd

namespace gd {

class GD_CORE_API ObjectTools {
public:
static bool IsBehaviorCompatibleWithObject(const gd::Platform &platform,
const gd::String &objectType,
const gd::String &behaviorType) {
std::unordered_set<gd::String> coveredBehaviorType;
return IsBehaviorCompatibleWithObject(platform, objectType, behaviorType,
coveredBehaviorType);
}

private:
static bool IsBehaviorCompatibleWithObject(
const gd::Platform &platform, const gd::String &objectType,
const gd::String &behaviorType,
std::unordered_set<gd::String> coveredBehaviorType);
};

} // namespace gd
7 changes: 7 additions & 0 deletions GDevelop.js/Bindings/Bindings.idl
Original file line number Diff line number Diff line change
Expand Up @@ -2786,6 +2786,13 @@ interface WholeProjectRefactorer {
[Value] SetString STATIC_FindAllLeaderboardIds([Ref] Project project);
};

interface ObjectTools {
boolean STATIC_IsBehaviorCompatibleWithObject(
[Const, Ref] Platform platform,
[Const] DOMString objectType,
[Const] DOMString behaviorType);
};

interface EventsBasedObjectDependencyFinder {
boolean STATIC_IsDependentFromEventsBasedObject(
[Const, Ref] Project project,
Expand Down
2 changes: 2 additions & 0 deletions GDevelop.js/Bindings/Wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
#include <GDCore/Project/MeasurementUnitElement.h>
#include <GDCore/Project/NamedPropertyDescriptor.h>
#include <GDCore/Project/Object.h>
#include <GDCore/Project/ObjectTools.h>
#include <GDCore/Project/ObjectFolderOrObject.h>
#include <GDCore/Project/ObjectConfiguration.h>
#include <GDCore/Project/Project.h>
Expand Down Expand Up @@ -658,6 +659,7 @@ typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
#define STATIC_FindInvalidRequiredBehaviorProperties \
FindInvalidRequiredBehaviorProperties
#define STATIC_GetBehaviorsWithType GetBehaviorsWithType
#define STATIC_IsBehaviorCompatibleWithObject IsBehaviorCompatibleWithObject
#define STATIC_FixInvalidRequiredBehaviorProperties \
FixInvalidRequiredBehaviorProperties
#define STATIC_RemoveLayerInScene RemoveLayerInScene
Expand Down
4 changes: 4 additions & 0 deletions GDevelop.js/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1985,6 +1985,10 @@ export class WholeProjectRefactorer extends EmscriptenObject {
static findAllLeaderboardIds(project: Project): SetString;
}

export class ObjectTools extends EmscriptenObject {
static isBehaviorCompatibleWithObject(platform: Platform, objectType: string, behaviorType: string): boolean;
}

export class EventsBasedObjectDependencyFinder extends EmscriptenObject {
static isDependentFromEventsBasedObject(project: Project, eventsBasedObject: EventsBasedObject, dependency: EventsBasedObject): boolean;
}
Expand Down
6 changes: 6 additions & 0 deletions GDevelop.js/types/gdobjecttools.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdObjectTools {
static isBehaviorCompatibleWithObject(platform: gdPlatform, objectType: string, behaviorType: string): boolean;
delete(): void;
ptr: number;
};
1 change: 1 addition & 0 deletions GDevelop.js/types/libgdevelop.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ declare class libGDevelop {
ResourceExposer: Class<gdResourceExposer>;
VariablesChangeset: Class<gdVariablesChangeset>;
WholeProjectRefactorer: Class<gdWholeProjectRefactorer>;
ObjectTools: Class<gdObjectTools>;
EventsBasedObjectDependencyFinder: Class<gdEventsBasedObjectDependencyFinder>;
PropertyFunctionGenerator: Class<gdPropertyFunctionGenerator>;
UsedExtensionsResult: Class<gdUsedExtensionsResult>;
Expand Down
9 changes: 9 additions & 0 deletions newIDE/app/src/BehaviorsEditor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,15 @@ export const useManageObjectBehaviors = ({
if (!name || !type || !serializedBehavior) {
return;
}
if (
!gd.ObjectTools.isBehaviorCompatibleWithObject(
project.getCurrentPlatform(),
object.getType(),
type
)
) {
return;
}

const behaviorMetadata = gd.MetadataProvider.getBehaviorMetadata(
project.getCurrentPlatform(),
Expand Down

0 comments on commit c2b869d

Please sign in to comment.