mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Fix error accessing deleted objects after an object is deleted from a scene (#7612)
This commit is contained in:
@@ -227,7 +227,7 @@ module.exports = {
|
||||
|
||||
behaviorProperties
|
||||
.getOrCreate('object3D')
|
||||
.setValue(behaviorContent.getChild('Object3D').getStringValue())
|
||||
.setValue(behaviorContent.getChild('object3D').getStringValue())
|
||||
.setType('Behavior')
|
||||
.setLabel('3D capability')
|
||||
.setQuickCustomizationVisibility(gd.QuickCustomization.Hidden)
|
||||
|
@@ -59,6 +59,7 @@ export type AskAiEditorInterface = {|
|
||||
scene: gdLayout,
|
||||
objectWithContext: ObjectWithContext
|
||||
) => void,
|
||||
onSceneObjectsDeleted: (scene: gdLayout) => void,
|
||||
|};
|
||||
|
||||
const noop = () => {};
|
||||
@@ -109,6 +110,7 @@ export const AskAi = React.memo<Props>(
|
||||
forceUpdateEditor: noop,
|
||||
onEventsBasedObjectChildrenEdited: noop,
|
||||
onSceneObjectEdited: noop,
|
||||
onSceneObjectsDeleted: noop,
|
||||
}));
|
||||
|
||||
const aiRequestChatRef = React.useRef<AiRequestChatInterface | null>(
|
||||
|
@@ -151,6 +151,7 @@ export type RenderEditorContainerProps = {|
|
||||
scene: gdLayout,
|
||||
objectWithContext: ObjectWithContext
|
||||
) => void,
|
||||
onSceneObjectsDeleted: (scene: gdLayout) => void,
|
||||
|
||||
onExtractAsExternalLayout: (name: string) => void,
|
||||
onExtractAsEventBasedObject: (
|
||||
|
@@ -237,9 +237,15 @@ export class CustomObjectEditorContainer extends React.Component<RenderEditorCon
|
||||
onObjectEdited={() =>
|
||||
this.props.onEventsBasedObjectChildrenEdited(eventsBasedObject)
|
||||
}
|
||||
onObjectsDeleted={() =>
|
||||
this.props.onEventsBasedObjectChildrenEdited(eventsBasedObject)
|
||||
}
|
||||
onObjectGroupEdited={() =>
|
||||
this.props.onEventsBasedObjectChildrenEdited(eventsBasedObject)
|
||||
}
|
||||
onObjectGroupsDeleted={() =>
|
||||
this.props.onEventsBasedObjectChildrenEdited(eventsBasedObject)
|
||||
}
|
||||
onEventsBasedObjectChildrenEdited={
|
||||
this.props.onEventsBasedObjectChildrenEdited
|
||||
}
|
||||
|
@@ -57,6 +57,10 @@ export class DebuggerEditorContainer extends React.Component<
|
||||
// No thing to be done.
|
||||
}
|
||||
|
||||
onSceneObjectsDeleted(scene: gdLayout) {
|
||||
// No thing to be done.
|
||||
}
|
||||
|
||||
// To be updated, see https://reactjs.org/docs/react-component.html#unsafe_componentwillreceiveprops.
|
||||
UNSAFE_componentWillReceiveProps() {
|
||||
this._checkUserHasSubscription();
|
||||
|
@@ -53,6 +53,10 @@ export class EventsEditorContainer extends React.Component<RenderEditorContainer
|
||||
// No thing to be done.
|
||||
}
|
||||
|
||||
onSceneObjectsDeleted(scene: gdLayout) {
|
||||
// No thing to be done.
|
||||
}
|
||||
|
||||
getLayout(): ?gdLayout {
|
||||
const { project, projectItemName } = this.props;
|
||||
if (
|
||||
|
@@ -46,6 +46,10 @@ export class EventsFunctionsExtensionEditorContainer extends React.Component<Ren
|
||||
// No thing to be done.
|
||||
}
|
||||
|
||||
onSceneObjectsDeleted(scene: gdLayout) {
|
||||
// No thing to be done.
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps: RenderEditorContainerProps) {
|
||||
// We stop updates when the component is inactive.
|
||||
// If it's active, was active or becoming active again we let update propagate.
|
||||
|
@@ -90,6 +90,10 @@ export class ExternalEventsEditorContainer extends React.Component<
|
||||
// No thing to be done.
|
||||
}
|
||||
|
||||
onSceneObjectsDeleted(scene: gdLayout) {
|
||||
// No thing to be done.
|
||||
}
|
||||
|
||||
getExternalEvents(): ?gdExternalEvents {
|
||||
const { project, projectItemName } = this.props;
|
||||
if (!project || !projectItemName) return null;
|
||||
|
@@ -138,6 +138,20 @@ export class ExternalLayoutEditorContainer extends React.Component<
|
||||
}
|
||||
}
|
||||
|
||||
onSceneObjectsDeleted(scene: gdLayout) {
|
||||
const { editor } = this;
|
||||
const externalLayout = this.getExternalLayout();
|
||||
if (!externalLayout) {
|
||||
return;
|
||||
}
|
||||
if (externalLayout.getAssociatedLayout() !== scene.getName()) {
|
||||
return;
|
||||
}
|
||||
if (editor) {
|
||||
editor.forceUpdateObjectsList();
|
||||
}
|
||||
}
|
||||
|
||||
getExternalLayout(): ?gdExternalLayout {
|
||||
const { project, projectItemName } = this.props;
|
||||
if (!project || !projectItemName) return null;
|
||||
@@ -266,8 +280,10 @@ export class ExternalLayoutEditorContainer extends React.Component<
|
||||
onObjectEdited={objectWithContext =>
|
||||
this.props.onSceneObjectEdited(layout, objectWithContext)
|
||||
}
|
||||
onObjectsDeleted={() => this.props.onSceneObjectsDeleted(layout)}
|
||||
// It's only used to refresh events-based object variants.
|
||||
onObjectGroupEdited={() => {}}
|
||||
onObjectGroupsDeleted={() => {}}
|
||||
// Nothing to do as events-based objects can't have external layout.
|
||||
onEventsBasedObjectChildrenEdited={() => {}}
|
||||
onExtensionInstalled={this.props.onExtensionInstalled}
|
||||
|
@@ -169,6 +169,7 @@ export type HomePageEditorInterface = {|
|
||||
scene: gdLayout,
|
||||
objectWithContext: ObjectWithContext
|
||||
) => void,
|
||||
onSceneObjectsDeleted: (scene: gdLayout) => void,
|
||||
|};
|
||||
|
||||
export const HomePage = React.memo<Props>(
|
||||
@@ -482,12 +483,17 @@ export const HomePage = React.memo<Props>(
|
||||
[]
|
||||
);
|
||||
|
||||
const onSceneObjectsDeleted = React.useCallback((scene: gdLayout) => {
|
||||
// No thing to be done.
|
||||
}, []);
|
||||
|
||||
React.useImperativeHandle(ref, () => ({
|
||||
getProject,
|
||||
updateToolbar,
|
||||
forceUpdateEditor,
|
||||
onEventsBasedObjectChildrenEdited,
|
||||
onSceneObjectEdited,
|
||||
onSceneObjectsDeleted,
|
||||
}));
|
||||
|
||||
const onUserSurveyStarted = React.useCallback(() => {
|
||||
|
@@ -41,6 +41,10 @@ export class ResourcesEditorContainer extends React.Component<RenderEditorContai
|
||||
// No thing to be done.
|
||||
}
|
||||
|
||||
onSceneObjectsDeleted(scene: gdLayout) {
|
||||
// No thing to be done.
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: RenderEditorContainerProps) {
|
||||
if (
|
||||
this.editor &&
|
||||
|
@@ -79,6 +79,20 @@ export class SceneEditorContainer extends React.Component<RenderEditorContainerP
|
||||
}
|
||||
}
|
||||
|
||||
onSceneObjectsDeleted(scene: gdLayout) {
|
||||
const layout = this.getLayout();
|
||||
if (!layout) {
|
||||
return;
|
||||
}
|
||||
if (layout !== scene) {
|
||||
return;
|
||||
}
|
||||
const { editor } = this;
|
||||
if (editor) {
|
||||
editor.forceUpdateObjectsList();
|
||||
}
|
||||
}
|
||||
|
||||
getLayout(): ?gdLayout {
|
||||
const { project, projectItemName } = this.props;
|
||||
if (
|
||||
@@ -160,8 +174,10 @@ export class SceneEditorContainer extends React.Component<RenderEditorContainerP
|
||||
onObjectEdited={objectWithContext =>
|
||||
this.props.onSceneObjectEdited(layout, objectWithContext)
|
||||
}
|
||||
onObjectsDeleted={() => this.props.onSceneObjectsDeleted(layout)}
|
||||
// It's only used to refresh events-based object variants.
|
||||
onObjectGroupEdited={() => {}}
|
||||
onObjectGroupsDeleted={() => {}}
|
||||
// Nothing to do as scenes are not events-based objects.
|
||||
onEventsBasedObjectChildrenEdited={() => {}}
|
||||
/>
|
||||
|
@@ -2350,6 +2350,18 @@ const MainFrame = (props: Props) => {
|
||||
[state.editorTabs]
|
||||
);
|
||||
|
||||
const onSceneObjectsDeleted = React.useCallback(
|
||||
(scene: gdLayout) => {
|
||||
for (const editor of state.editorTabs.editors) {
|
||||
const { editorRef } = editor;
|
||||
if (editorRef) {
|
||||
editorRef.onSceneObjectsDeleted(scene);
|
||||
}
|
||||
}
|
||||
},
|
||||
[state.editorTabs]
|
||||
);
|
||||
|
||||
const _onProjectItemModified = () => {
|
||||
triggerUnsavedChanges();
|
||||
forceUpdate();
|
||||
@@ -4048,6 +4060,7 @@ const MainFrame = (props: Props) => {
|
||||
onDeleteEventsBasedObjectVariant: deleteEventsBasedObjectVariant,
|
||||
onEventsBasedObjectChildrenEdited: onEventsBasedObjectChildrenEdited,
|
||||
onSceneObjectEdited: onSceneObjectEdited,
|
||||
onSceneObjectsDeleted: onSceneObjectsDeleted,
|
||||
onExtensionInstalled: onExtensionInstalled,
|
||||
gamesList,
|
||||
gamesPlatformFrameTools,
|
||||
|
@@ -119,6 +119,9 @@ type Props = {|
|
||||
eventsBasedObject: gdEventsBasedObject
|
||||
) => void,
|
||||
|
||||
onObjectsDeleted: () => void,
|
||||
onObjectGroupsDeleted: () => void,
|
||||
|
||||
setToolbar: (?React.Node) => void,
|
||||
resourceManagementProps: ResourceManagementProps,
|
||||
isActive: boolean,
|
||||
@@ -973,7 +976,7 @@ export default class SceneEditor extends React.Component<Props, State> {
|
||||
objectsWithContext: ObjectWithContext[],
|
||||
done: boolean => void
|
||||
) => {
|
||||
const { project, layout, eventsBasedObject, onObjectEdited } = this.props;
|
||||
const { project, layout, eventsBasedObject, onObjectsDeleted } = this.props;
|
||||
|
||||
objectsWithContext.forEach(objectWithContext => {
|
||||
const { object, global } = objectWithContext;
|
||||
@@ -1005,12 +1008,11 @@ export default class SceneEditor extends React.Component<Props, State> {
|
||||
}
|
||||
});
|
||||
|
||||
// Note: done() actually does the deletion of the objects,
|
||||
// so ensure objectsWithContext are not used after this call.
|
||||
done(true);
|
||||
onObjectsDeleted();
|
||||
|
||||
objectsWithContext.forEach(objectWithContext => {
|
||||
// TODO Avoid to do this N times.
|
||||
onObjectEdited(objectWithContext);
|
||||
});
|
||||
// We modified the selection, so force an update of editors dealing with it.
|
||||
this.forceUpdatePropertiesEditor();
|
||||
this.updateToolbar();
|
||||
@@ -1207,8 +1209,10 @@ export default class SceneEditor extends React.Component<Props, State> {
|
||||
groupWithContext: GroupWithContext,
|
||||
done: boolean => void
|
||||
) => {
|
||||
// done() actually does the deletion of the object group,
|
||||
// so ensure groupWithContext is not used after this call.
|
||||
done(true);
|
||||
this.props.onObjectGroupEdited(groupWithContext);
|
||||
this.props.onObjectGroupsDeleted();
|
||||
};
|
||||
|
||||
_onRenameObjectGroup = (
|
||||
|
Reference in New Issue
Block a user