Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,163 +30,172 @@ type Props = {|
eventsFunctionsExtensionOpener: ?EventsFunctionsExtensionOpener,
|};

type State = EventsFunctionsExtensionsState;

/**
* Allow children components to request the loading (or unloading) of
* the events functions extensions of the project.
* Useful when dealing with events functions extensions (new extension created,
* removed, pasted, installed, etc...).
*/
export default class EventsFunctionsExtensionsProvider extends React.Component<
Props,
State
> {
_eventsFunctionCodeWriter: ?EventsFunctionCodeWriter = this.props.makeEventsFunctionCodeWriter(
{
onWriteFile: this._onWriteFile.bind(this),
}
export const EventsFunctionsExtensionsProvider = ({
children,
i18n,
makeEventsFunctionCodeWriter,
eventsFunctionsExtensionWriter,
eventsFunctionsExtensionOpener,
}: Props) => {
const [
eventsFunctionsExtensionsError,
setEventsFunctionsExtensionsError,
] = React.useState<Error | null>(null);
const includeFileHashs = React.useRef<{ [string]: number }>({});
const lastLoadPromise = React.useRef<?Promise<void>>(null);

const onWriteFile = React.useCallback(
({ includeFile, content }: IncludeFileContent) => {
includeFileHashs.current[includeFile] = xxhashjs
.h32(content, 0xabcd)
.toNumber();
},
[]
);

const eventsFunctionCodeWriter: ?EventsFunctionCodeWriter = React.useMemo(
() => makeEventsFunctionCodeWriter({ onWriteFile }),
[onWriteFile, makeEventsFunctionCodeWriter]
);
_includeFileHashs: { [string]: number } = {};
_lastLoadPromise: ?Promise<void> = null;
state = {
eventsFunctionsExtensionsError: null,
loadProjectEventsFunctionsExtensions: this._loadProjectEventsFunctionsExtensions.bind(
this
),
unloadProjectEventsFunctionsExtensions: this._unloadProjectEventsFunctionsExtensions.bind(
this
),
unloadProjectEventsFunctionsExtension: this._unloadProjectEventsFunctionsExtension.bind(
this
),
reloadProjectEventsFunctionsExtensions: this._reloadProjectEventsFunctionsExtensions.bind(
this
),
reloadProjectEventsFunctionsExtensionMetadata: this._reloadProjectEventsFunctionsExtensionMetadata.bind(
this
),
ensureLoadFinished: this._ensureLoadFinished.bind(this),
getEventsFunctionsExtensionWriter: () =>
this.props.eventsFunctionsExtensionWriter,
getEventsFunctionsExtensionOpener: () =>
this.props.eventsFunctionsExtensionOpener,
getIncludeFileHashs: () => this._includeFileHashs,
};

_onWriteFile({ includeFile, content }: IncludeFileContent) {
this._includeFileHashs[includeFile] = xxhashjs
.h32(content, 0xabcd)
.toNumber();
}

_ensureLoadFinished(): Promise<void> {
if (this._lastLoadPromise) {

const ensureLoadFinished = React.useCallback((): Promise<void> => {
if (lastLoadPromise.current) {
console.info(
'Waiting on the events functions extensions to finish loading...'
);
} else {
console.info('Events functions extensions are ready.');
}

return this._lastLoadPromise
? this._lastLoadPromise.then(() => {
return lastLoadPromise.current
? lastLoadPromise.current.then(() => {
console.info('Events functions extensions finished loading.');
})
: Promise.resolve();
}
}, []);

const _loadProjectEventsFunctionsExtensions = React.useCallback(
(project: ?gdProject): Promise<void> => {
if (!project || !eventsFunctionCodeWriter) return Promise.resolve();

const previousLastLoadPromise =
lastLoadPromise.current || Promise.resolve();

lastLoadPromise.current = previousLastLoadPromise
.then(() =>
loadProjectEventsFunctionsExtensions(
project,
eventsFunctionCodeWriter,
i18n
)
)
.then(() => setEventsFunctionsExtensionsError(null))
.catch((eventsFunctionsExtensionsError: Error) => {
setEventsFunctionsExtensionsError(eventsFunctionsExtensionsError);
showErrorBox({
message: i18n._(
t`An error has occurred during functions generation. If GDevelop is installed, verify that nothing is preventing GDevelop from writing on disk. If you're running GDevelop online, verify your internet connection and refresh functions from the Project Manager.`
),
rawError: eventsFunctionsExtensionsError,
errorId: 'events-functions-extensions-load-error',
});
})
.then(() => {
lastLoadPromise.current = null;
});

_loadProjectEventsFunctionsExtensions(project: ?gdProject): Promise<void> {
const { i18n } = this.props;
const eventsFunctionCodeWriter = this._eventsFunctionCodeWriter;
if (!project || !eventsFunctionCodeWriter) return Promise.resolve();
return lastLoadPromise.current;
},
[eventsFunctionCodeWriter, i18n]
);

const lastLoadPromise = this._lastLoadPromise || Promise.resolve();
const _reloadProjectEventsFunctionsExtensionMetadata = React.useCallback(
(project: ?gdProject, extension: gdEventsFunctionsExtension): void => {
if (!project || !eventsFunctionCodeWriter) return;

this._lastLoadPromise = lastLoadPromise
.then(() =>
loadProjectEventsFunctionsExtensions(
try {
reloadProjectEventsFunctionsExtensionMetadata(
project,
extension,
eventsFunctionCodeWriter,
i18n
)
)
.then(() =>
this.setState({
eventsFunctionsExtensionsError: null,
})
)
.catch((eventsFunctionsExtensionsError: Error) => {
this.setState({
eventsFunctionsExtensionsError,
});
);
} catch (eventsFunctionsExtensionsError) {
setEventsFunctionsExtensionsError(eventsFunctionsExtensionsError);
showErrorBox({
message: i18n._(
t`An error has occurred during functions generation. If GDevelop is installed, verify that nothing is preventing GDevelop from writing on disk. If you're running GDevelop online, verify your internet connection and refresh functions from the Project Manager.`
),
rawError: eventsFunctionsExtensionsError,
errorId: 'events-functions-extensions-load-error',
});
})
.then(() => {
this._lastLoadPromise = null;
});

return this._lastLoadPromise;
}

_reloadProjectEventsFunctionsExtensionMetadata(
project: ?gdProject,
extension: gdEventsFunctionsExtension
): void {
const { i18n } = this.props;
const eventsFunctionCodeWriter = this._eventsFunctionCodeWriter;
if (!project || !eventsFunctionCodeWriter) return;

try {
reloadProjectEventsFunctionsExtensionMetadata(
project,
extension,
eventsFunctionCodeWriter,
i18n
);
} catch (eventsFunctionsExtensionsError) {
this.setState({
eventsFunctionsExtensionsError,
});
showErrorBox({
message: i18n._(
t`An error has occurred during functions generation. If GDevelop is installed, verify that nothing is preventing GDevelop from writing on disk. If you're running GDevelop online, verify your internet connection and refresh functions from the Project Manager.`
),
rawError: eventsFunctionsExtensionsError,
errorId: 'events-functions-extensions-load-error',
});
}
}

_unloadProjectEventsFunctionsExtensions(project: gdProject) {
unloadProjectEventsFunctionsExtensions(project);
}

_unloadProjectEventsFunctionsExtension(
project: gdProject,
extensionName: string
) {
unloadProjectEventsFunctionsExtension(project, extensionName);
}

_reloadProjectEventsFunctionsExtensions(project: ?gdProject): Promise<void> {
if (project) {
this._unloadProjectEventsFunctionsExtensions(project);
}
return this._loadProjectEventsFunctionsExtensions(project);
}

render() {
return (
<EventsFunctionsExtensionsContext.Provider value={this.state}>
{this.props.children}
</EventsFunctionsExtensionsContext.Provider>
);
}
}
}
},
[eventsFunctionCodeWriter, i18n]
);

const _unloadProjectEventsFunctionsExtensions = React.useCallback(
(project: gdProject) => {
unloadProjectEventsFunctionsExtensions(project);
},
[]
);

const _unloadProjectEventsFunctionsExtension = React.useCallback(
(project: gdProject, extensionName: string) => {
unloadProjectEventsFunctionsExtension(project, extensionName);
},
[]
);

const _reloadProjectEventsFunctionsExtensions = React.useCallback(
(project: ?gdProject): Promise<void> => {
if (project) {
_unloadProjectEventsFunctionsExtensions(project);
}
return _loadProjectEventsFunctionsExtensions(project);
},
[
_loadProjectEventsFunctionsExtensions,
_unloadProjectEventsFunctionsExtensions,
]
);

const state = React.useMemo<EventsFunctionsExtensionsState>(
() => ({
eventsFunctionsExtensionsError,
loadProjectEventsFunctionsExtensions: _loadProjectEventsFunctionsExtensions,
unloadProjectEventsFunctionsExtensions: _unloadProjectEventsFunctionsExtensions,
unloadProjectEventsFunctionsExtension: _unloadProjectEventsFunctionsExtension,
reloadProjectEventsFunctionsExtensions: _reloadProjectEventsFunctionsExtensions,
reloadProjectEventsFunctionsExtensionMetadata: _reloadProjectEventsFunctionsExtensionMetadata,
ensureLoadFinished,
getEventsFunctionsExtensionWriter: () => eventsFunctionsExtensionWriter,
getEventsFunctionsExtensionOpener: () => eventsFunctionsExtensionOpener,
getIncludeFileHashs: () => includeFileHashs.current,
}),
[
ensureLoadFinished,
_loadProjectEventsFunctionsExtensions,
_reloadProjectEventsFunctionsExtensionMetadata,
_reloadProjectEventsFunctionsExtensions,
_unloadProjectEventsFunctionsExtension,
_unloadProjectEventsFunctionsExtensions,
eventsFunctionsExtensionOpener,
eventsFunctionsExtensionWriter,
eventsFunctionsExtensionsError,
]
);

return (
<EventsFunctionsExtensionsContext.Provider value={state}>
{children}
</EventsFunctionsExtensionsContext.Provider>
);
};
2 changes: 1 addition & 1 deletion newIDE/app/src/MainFrame/Providers.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import PreferencesContext from './Preferences/PreferencesContext';
import GDI18nProvider from '../Utils/i18n/GDI18nProvider';
import { I18n } from '@lingui/react';
import { type I18n as I18nType } from '@lingui/core';
import EventsFunctionsExtensionsProvider from '../EventsFunctionsExtensionsLoader/EventsFunctionsExtensionsProvider';
import { EventsFunctionsExtensionsProvider } from '../EventsFunctionsExtensionsLoader/EventsFunctionsExtensionsProvider';
import {
type EventsFunctionCodeWriter,
type EventsFunctionCodeWriterCallbacks,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { action } from '@storybook/addon-actions';
import paperDecorator from '../../../PaperDecorator';
import ExtensionsSearchDialog from '../../../../AssetStore/ExtensionStore/ExtensionsSearchDialog';
import { I18n } from '@lingui/react';
import EventsFunctionsExtensionsProvider from '../../../../EventsFunctionsExtensionsLoader/EventsFunctionsExtensionsProvider';
import { EventsFunctionsExtensionsProvider } from '../../../../EventsFunctionsExtensionsLoader/EventsFunctionsExtensionsProvider';
import { ExtensionStoreStateProvider } from '../../../../AssetStore/ExtensionStore/ExtensionStoreContext';
import { testProject } from '../../../GDevelopJsInitializerDecorator';
import { GDevelopAssetApi } from '../../../../Utils/GDevelopServices/ApiConfigs';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import fakeResourceManagementProps from '../../FakeResourceManagement';
import { testProject } from '../../GDevelopJsInitializerDecorator';

import OptionsEditorDialog from '../../../EventsFunctionsExtensionEditor/OptionsEditorDialog';
import EventsFunctionsExtensionsProvider from '../../../EventsFunctionsExtensionsLoader/EventsFunctionsExtensionsProvider';
import { EventsFunctionsExtensionsProvider } from '../../../EventsFunctionsExtensionsLoader/EventsFunctionsExtensionsProvider';

export default {
title: 'EventsFunctionsExtensionEditor/OptionsEditorDialog',
Expand Down