mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
1 Commits
feat/destr
...
feat/ai-la
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0c2913bbff |
@@ -277,6 +277,10 @@ class GD_CORE_API MetadataProvider {
|
||||
return &metadata == &badObjectInfo;
|
||||
}
|
||||
|
||||
static bool IsBadEffectMetadata(const gd::EffectMetadata& metadata) {
|
||||
return &metadata == &badEffectMetadata;
|
||||
}
|
||||
|
||||
virtual ~MetadataProvider();
|
||||
|
||||
private:
|
||||
|
@@ -1908,7 +1908,9 @@ module.exports = {
|
||||
.addEffect('AmbientLight')
|
||||
.setFullName(_('Ambient light'))
|
||||
.setDescription(
|
||||
_('A light that illuminates all objects from every direction.')
|
||||
_(
|
||||
'A light that illuminates all objects from every direction. Often used along with a Directional light (though a Hemisphere light can be used instead of an Ambient light).'
|
||||
)
|
||||
)
|
||||
.markAsNotWorkingForObjects()
|
||||
.markAsOnlyWorkingFor3D()
|
||||
@@ -1929,7 +1931,11 @@ module.exports = {
|
||||
const effect = extension
|
||||
.addEffect('DirectionalLight')
|
||||
.setFullName(_('Directional light'))
|
||||
.setDescription(_('A very far light source like the sun.'))
|
||||
.setDescription(
|
||||
_(
|
||||
"A very far light source like the sun. This is the light to use for casting shadows for 3D objects (other lights won't emit shadows). Often used along with a Hemisphere light."
|
||||
)
|
||||
)
|
||||
.markAsNotWorkingForObjects()
|
||||
.markAsOnlyWorkingFor3D()
|
||||
.addIncludeFile('Extensions/3D/DirectionalLight.js');
|
||||
@@ -2013,7 +2019,7 @@ module.exports = {
|
||||
.setFullName(_('Hemisphere light'))
|
||||
.setDescription(
|
||||
_(
|
||||
'A light that illuminates objects from every direction with a gradient.'
|
||||
'A light that illuminates objects from every direction with a gradient. Often used along with a Directional light.'
|
||||
)
|
||||
)
|
||||
.markAsNotWorkingForObjects()
|
||||
|
@@ -1143,6 +1143,7 @@ interface LayersContainer {
|
||||
boolean HasLayerNamed([Const] DOMString name);
|
||||
void RemoveLayer([Const] DOMString name);
|
||||
unsigned long GetLayersCount();
|
||||
unsigned long GetLayerPosition([Const] DOMString name);
|
||||
void SwapLayers(unsigned long firstLayerIndex, unsigned long secondLayerIndex);
|
||||
void MoveLayer(unsigned long oldIndex, unsigned long newIndex);
|
||||
void SerializeLayersTo([Ref] SerializerElement element);
|
||||
@@ -2932,6 +2933,7 @@ interface MetadataProvider {
|
||||
boolean STATIC_IsBadInstructionMetadata([Const, Ref] InstructionMetadata metadata);
|
||||
boolean STATIC_IsBadBehaviorMetadata([Const, Ref] BehaviorMetadata metadata);
|
||||
boolean STATIC_IsBadObjectMetadata([Const, Ref] ObjectMetadata metadata);
|
||||
boolean STATIC_IsBadEffectMetadata([Const, Ref] EffectMetadata metadata);
|
||||
};
|
||||
|
||||
enum ProjectDiagnostic_ErrorType {
|
||||
|
@@ -606,6 +606,7 @@ typedef std::vector<gd::PropertyDescriptorChoice> VectorPropertyDescriptorChoice
|
||||
#define STATIC_IsBadInstructionMetadata IsBadInstructionMetadata
|
||||
#define STATIC_IsBadBehaviorMetadata IsBadBehaviorMetadata
|
||||
#define STATIC_IsBadObjectMetadata IsBadObjectMetadata
|
||||
#define STATIC_IsBadEffectMetadata IsBadEffectMetadata
|
||||
|
||||
#define STATIC_RenameObjectInEvents RenameObjectInEvents
|
||||
#define STATIC_RemoveObjectInEvents RemoveObjectInEvents
|
||||
|
2
GDevelop.js/types.d.ts
vendored
2
GDevelop.js/types.d.ts
vendored
@@ -941,6 +941,7 @@ export class LayersContainer extends EmscriptenObject {
|
||||
hasLayerNamed(name: string): boolean;
|
||||
removeLayer(name: string): void;
|
||||
getLayersCount(): number;
|
||||
getLayerPosition(name: string): number;
|
||||
swapLayers(firstLayerIndex: number, secondLayerIndex: number): void;
|
||||
moveLayer(oldIndex: number, newIndex: number): void;
|
||||
serializeLayersTo(element: SerializerElement): void;
|
||||
@@ -2109,6 +2110,7 @@ export class MetadataProvider extends EmscriptenObject {
|
||||
static isBadInstructionMetadata(metadata: InstructionMetadata): boolean;
|
||||
static isBadBehaviorMetadata(metadata: BehaviorMetadata): boolean;
|
||||
static isBadObjectMetadata(metadata: ObjectMetadata): boolean;
|
||||
static isBadEffectMetadata(metadata: EffectMetadata): boolean;
|
||||
}
|
||||
|
||||
export class ProjectDiagnostic extends EmscriptenObject {
|
||||
|
@@ -7,6 +7,7 @@ declare class gdLayersContainer {
|
||||
hasLayerNamed(name: string): boolean;
|
||||
removeLayer(name: string): void;
|
||||
getLayersCount(): number;
|
||||
getLayerPosition(name: string): number;
|
||||
swapLayers(firstLayerIndex: number, secondLayerIndex: number): void;
|
||||
moveLayer(oldIndex: number, newIndex: number): void;
|
||||
serializeLayersTo(element: gdSerializerElement): void;
|
||||
|
@@ -26,6 +26,7 @@ declare class gdMetadataProvider {
|
||||
static isBadInstructionMetadata(metadata: gdInstructionMetadata): boolean;
|
||||
static isBadBehaviorMetadata(metadata: gdBehaviorMetadata): boolean;
|
||||
static isBadObjectMetadata(metadata: gdObjectMetadata): boolean;
|
||||
static isBadEffectMetadata(metadata: gdEffectMetadata): boolean;
|
||||
delete(): void;
|
||||
ptr: number;
|
||||
};
|
@@ -5,6 +5,7 @@ import { I18n } from '@lingui/react';
|
||||
import {
|
||||
type RenderEditorContainerPropsWithRef,
|
||||
type SceneEventsOutsideEditorChanges,
|
||||
type InstancesOutsideEditorChanges,
|
||||
} from '../MainFrame/EditorContainers/BaseEditor';
|
||||
import { type ObjectWithContext } from '../ObjectsList/EnumerateObjects';
|
||||
import Paper from '../UI/Paper';
|
||||
@@ -67,6 +68,7 @@ const useProcessFunctionCalls = ({
|
||||
getEditorFunctionCallResults,
|
||||
addEditorFunctionCallResults,
|
||||
onSceneEventsModifiedOutsideEditor,
|
||||
onInstancesModifiedOutsideEditor,
|
||||
onExtensionInstalled,
|
||||
}: {|
|
||||
i18n: I18nType,
|
||||
@@ -85,6 +87,9 @@ const useProcessFunctionCalls = ({
|
||||
onSceneEventsModifiedOutsideEditor: (
|
||||
changes: SceneEventsOutsideEditorChanges
|
||||
) => void,
|
||||
onInstancesModifiedOutsideEditor: (
|
||||
changes: InstancesOutsideEditorChanges
|
||||
) => void,
|
||||
onExtensionInstalled: (extensionNames: Array<string>) => void,
|
||||
|}) => {
|
||||
const { ensureExtensionInstalled } = useEnsureExtensionInstalled({
|
||||
@@ -159,6 +164,7 @@ const useProcessFunctionCalls = ({
|
||||
});
|
||||
},
|
||||
onSceneEventsModifiedOutsideEditor,
|
||||
onInstancesModifiedOutsideEditor,
|
||||
ensureExtensionInstalled,
|
||||
searchAndInstallAsset,
|
||||
});
|
||||
@@ -179,6 +185,7 @@ const useProcessFunctionCalls = ({
|
||||
searchAndInstallAsset,
|
||||
generateEvents,
|
||||
onSceneEventsModifiedOutsideEditor,
|
||||
onInstancesModifiedOutsideEditor,
|
||||
triggerSendEditorFunctionCallResults,
|
||||
editorCallbacks,
|
||||
]
|
||||
@@ -349,6 +356,9 @@ type Props = {|
|
||||
onSceneEventsModifiedOutsideEditor: (
|
||||
changes: SceneEventsOutsideEditorChanges
|
||||
) => void,
|
||||
onInstancesModifiedOutsideEditor: (
|
||||
changes: InstancesOutsideEditorChanges
|
||||
) => void,
|
||||
onExtensionInstalled: (extensionNames: Array<string>) => void,
|
||||
initialMode: 'chat' | 'agent' | null,
|
||||
initialAiRequestId: string | null,
|
||||
@@ -372,6 +382,9 @@ export type AskAiEditorInterface = {|
|
||||
onSceneEventsModifiedOutsideEditor: (
|
||||
changes: SceneEventsOutsideEditorChanges
|
||||
) => void,
|
||||
onInstancesModifiedOutsideEditor: (
|
||||
changes: InstancesOutsideEditorChanges
|
||||
) => void,
|
||||
startOrOpenChat: ({|
|
||||
mode: 'chat' | 'agent',
|
||||
aiRequestId: string | null,
|
||||
@@ -401,6 +414,7 @@ export const AskAiEditor = React.memo<Props>(
|
||||
onCreateProjectFromExample,
|
||||
onOpenLayout,
|
||||
onSceneEventsModifiedOutsideEditor,
|
||||
onInstancesModifiedOutsideEditor,
|
||||
onExtensionInstalled,
|
||||
initialMode,
|
||||
initialAiRequestId,
|
||||
@@ -518,6 +532,7 @@ export const AskAiEditor = React.memo<Props>(
|
||||
onSceneObjectEdited: noop,
|
||||
onSceneObjectsDeleted: noop,
|
||||
onSceneEventsModifiedOutsideEditor: noop,
|
||||
onInstancesModifiedOutsideEditor: noop,
|
||||
startOrOpenChat: onStartOrOpenChat,
|
||||
}));
|
||||
|
||||
@@ -655,6 +670,7 @@ export const AskAiEditor = React.memo<Props>(
|
||||
fileMetadata,
|
||||
storageProviderName,
|
||||
mode,
|
||||
toolsVersion: 'v2',
|
||||
aiConfiguration: {
|
||||
presetId: aiConfigurationPresetId,
|
||||
},
|
||||
@@ -944,6 +960,7 @@ export const AskAiEditor = React.memo<Props>(
|
||||
getEditorFunctionCallResults,
|
||||
addEditorFunctionCallResults,
|
||||
onSceneEventsModifiedOutsideEditor,
|
||||
onInstancesModifiedOutsideEditor,
|
||||
i18n,
|
||||
onExtensionInstalled,
|
||||
});
|
||||
@@ -1044,6 +1061,9 @@ export const renderAskAiEditorContainer = (
|
||||
onSceneEventsModifiedOutsideEditor={
|
||||
props.onSceneEventsModifiedOutsideEditor
|
||||
}
|
||||
onInstancesModifiedOutsideEditor={
|
||||
props.onInstancesModifiedOutsideEditor
|
||||
}
|
||||
onExtensionInstalled={props.onExtensionInstalled}
|
||||
initialMode={
|
||||
(props.extraEditorProps && props.extraEditorProps.mode) || null
|
||||
|
@@ -10,6 +10,7 @@ import {
|
||||
type AssetSearchAndInstallOptions,
|
||||
type AssetSearchAndInstallResult,
|
||||
type SceneEventsOutsideEditorChanges,
|
||||
type InstancesOutsideEditorChanges,
|
||||
} from '.';
|
||||
|
||||
export type EditorFunctionCallResult =
|
||||
@@ -39,6 +40,9 @@ export type ProcessEditorFunctionCallsOptions = {|
|
||||
onSceneEventsModifiedOutsideEditor: (
|
||||
changes: SceneEventsOutsideEditorChanges
|
||||
) => void,
|
||||
onInstancesModifiedOutsideEditor: (
|
||||
changes: InstancesOutsideEditorChanges
|
||||
) => void,
|
||||
ensureExtensionInstalled: (options: {|
|
||||
extensionName: string,
|
||||
|}) => Promise<void>,
|
||||
@@ -53,6 +57,7 @@ export const processEditorFunctionCalls = async ({
|
||||
editorCallbacks,
|
||||
generateEvents,
|
||||
onSceneEventsModifiedOutsideEditor,
|
||||
onInstancesModifiedOutsideEditor,
|
||||
ignore,
|
||||
ensureExtensionInstalled,
|
||||
searchAndInstallAsset,
|
||||
@@ -136,6 +141,7 @@ export const processEditorFunctionCalls = async ({
|
||||
args,
|
||||
generateEvents,
|
||||
onSceneEventsModifiedOutsideEditor,
|
||||
onInstancesModifiedOutsideEditor,
|
||||
ensureExtensionInstalled,
|
||||
searchAndInstallAsset,
|
||||
}
|
||||
|
@@ -32,6 +32,12 @@ export type ExpressionSummary = {|
|
||||
relevantForSceneEvents?: boolean,
|
||||
|};
|
||||
|
||||
export type PropertySummary = {|
|
||||
name: string,
|
||||
description: string,
|
||||
type: string,
|
||||
|};
|
||||
|
||||
export type ObjectSummary = {|
|
||||
name: string,
|
||||
fullName: string,
|
||||
@@ -51,6 +57,17 @@ export type BehaviorSummary = {|
|
||||
expressions: Array<ExpressionSummary>,
|
||||
|};
|
||||
|
||||
export type EffectSummary = {|
|
||||
name: string,
|
||||
fullName: string,
|
||||
description: string,
|
||||
notWorkingForObjects: boolean,
|
||||
onlyWorkingFor2D: boolean,
|
||||
onlyWorkingFor3D: boolean,
|
||||
unique: boolean,
|
||||
properties: Array<PropertySummary>,
|
||||
|};
|
||||
|
||||
export type ExtensionSummary = {|
|
||||
extensionName: string,
|
||||
extensionFullName: string,
|
||||
@@ -60,6 +77,7 @@ export type ExtensionSummary = {|
|
||||
freeExpressions: Array<ExpressionSummary>,
|
||||
objects: { [string]: ObjectSummary },
|
||||
behaviors: { [string]: BehaviorSummary },
|
||||
effects: { [string]: EffectSummary },
|
||||
|};
|
||||
|
||||
const normalizeType = (parameterType: string) => {
|
||||
@@ -102,6 +120,29 @@ const getParameterSummary = (
|
||||
return parameterSummary;
|
||||
};
|
||||
|
||||
const getPropertySummary = (
|
||||
propertyName: string,
|
||||
property: gdPropertyDescriptor
|
||||
) => {
|
||||
return {
|
||||
name: propertyName,
|
||||
description: property.getDescription(),
|
||||
type: property.getType(),
|
||||
};
|
||||
};
|
||||
|
||||
const getPropertiesSummary = (
|
||||
propertiesMetadata: gdMapStringPropertyDescriptor
|
||||
) => {
|
||||
return propertiesMetadata
|
||||
.keys()
|
||||
.toJSArray()
|
||||
.map(propertyName => {
|
||||
const property = propertiesMetadata.get(propertyName);
|
||||
return getPropertySummary(propertyName, property);
|
||||
});
|
||||
};
|
||||
|
||||
export const buildExtensionSummary = ({
|
||||
gd,
|
||||
extension,
|
||||
@@ -111,6 +152,7 @@ export const buildExtensionSummary = ({
|
||||
}): ExtensionSummary => {
|
||||
const objects: { [string]: ObjectSummary } = {};
|
||||
const behaviors: { [string]: BehaviorSummary } = {};
|
||||
const effects: { [string]: EffectSummary } = {};
|
||||
|
||||
const generateInstructionsSummaries = ({
|
||||
instructionsMetadata,
|
||||
@@ -254,6 +296,27 @@ export const buildExtensionSummary = ({
|
||||
|
||||
behaviors[behaviorType] = behaviorSummary;
|
||||
});
|
||||
extension
|
||||
.getExtensionEffectTypes()
|
||||
.toJSArray()
|
||||
.forEach(effectType => {
|
||||
const effectMetadata = extension.getEffectMetadata(effectType);
|
||||
if (gd.MetadataProvider.isBadEffectMetadata(effectMetadata)) {
|
||||
return;
|
||||
}
|
||||
const effectSummary: EffectSummary = {
|
||||
name: effectMetadata.getType(),
|
||||
fullName: effectMetadata.getFullName(),
|
||||
description: effectMetadata.getDescription(),
|
||||
notWorkingForObjects: effectMetadata.isMarkedAsNotWorkingForObjects(),
|
||||
onlyWorkingFor2D: effectMetadata.isMarkedAsOnlyWorkingFor2D(),
|
||||
onlyWorkingFor3D: effectMetadata.isMarkedAsOnlyWorkingFor3D(),
|
||||
unique: effectMetadata.isMarkedAsUnique(),
|
||||
properties: getPropertiesSummary(effectMetadata.getProperties()),
|
||||
};
|
||||
|
||||
effects[effectType] = effectSummary;
|
||||
});
|
||||
|
||||
return {
|
||||
extensionName: extension.getName(),
|
||||
@@ -275,5 +338,6 @@ export const buildExtensionSummary = ({
|
||||
],
|
||||
objects,
|
||||
behaviors,
|
||||
effects,
|
||||
};
|
||||
};
|
||||
|
@@ -894,6 +894,7 @@ describe('SimplifiedProject', () => {
|
||||
},
|
||||
},
|
||||
"description": "A fake extension with a fake behavior containing 2 properties.",
|
||||
"effects": Object {},
|
||||
"extensionFullName": "Fake extension with a fake behavior",
|
||||
"extensionName": "FakeBehavior",
|
||||
"freeActions": Array [],
|
||||
|
@@ -17,6 +17,7 @@ import { Trans } from '@lingui/macro';
|
||||
import Link from '../UI/Link';
|
||||
import {
|
||||
hexNumberToRGBArray,
|
||||
rgbColorToHex,
|
||||
rgbOrHexToHexNumber,
|
||||
} from '../Utils/ColorTransformer';
|
||||
import { type SimplifiedBehavior } from './SimplifiedProject/SimplifiedProject';
|
||||
@@ -63,10 +64,13 @@ export type EditorFunctionGenericOutput = {|
|
||||
properties?: any,
|
||||
sharedProperties?: any,
|
||||
instances?: any,
|
||||
layers?: any,
|
||||
behaviors?: Array<SimplifiedBehavior>,
|
||||
animationNames?: string,
|
||||
generatedEventsErrorDiagnostics?: string,
|
||||
aiGeneratedEventId?: string,
|
||||
propertiesLayersEffectsForSceneNamed?: string,
|
||||
warnings?: string,
|
||||
|};
|
||||
|
||||
export type EventsGenerationResult =
|
||||
@@ -123,6 +127,10 @@ export type SceneEventsOutsideEditorChanges = {|
|
||||
newOrChangedAiGeneratedEventIds: Set<string>,
|
||||
|};
|
||||
|
||||
export type InstancesOutsideEditorChanges = {|
|
||||
scene: gdLayout,
|
||||
|};
|
||||
|
||||
/**
|
||||
* A function that does something in the editor on the given project.
|
||||
*/
|
||||
@@ -146,6 +154,9 @@ export type EditorFunction = {|
|
||||
onSceneEventsModifiedOutsideEditor: (
|
||||
changes: SceneEventsOutsideEditorChanges
|
||||
) => void,
|
||||
onInstancesModifiedOutsideEditor: (
|
||||
changes: InstancesOutsideEditorChanges
|
||||
) => void,
|
||||
ensureExtensionInstalled: (options: {|
|
||||
extensionName: string,
|
||||
|}) => Promise<void>,
|
||||
@@ -1493,7 +1504,6 @@ const put2dInstances: EditorFunction = {
|
||||
// Create the array of existing instances to move/modify, and new instances to create.
|
||||
const modifiedAndCreatedInstances: Array<gdInitialInstance> = [];
|
||||
iterateOnInstances(initialInstances, instance => {
|
||||
if (instance.getLayer() !== layer_name) return;
|
||||
if (instance.getObjectName() !== object_name) return;
|
||||
if (
|
||||
existingInstanceIds.some(id =>
|
||||
@@ -1501,6 +1511,8 @@ const put2dInstances: EditorFunction = {
|
||||
)
|
||||
) {
|
||||
modifiedAndCreatedInstances.push(instance);
|
||||
// Take the opportunity to move to a new layer if specified.
|
||||
instance.setLayer(layer_name);
|
||||
}
|
||||
});
|
||||
for (let i = 0; i < newInstancesCount; i++) {
|
||||
@@ -1846,7 +1858,6 @@ const put3dInstances: EditorFunction = {
|
||||
// Create the array of existing instances to move/modify, and new instances to create.
|
||||
const modifiedAndCreatedInstances: Array<gdInitialInstance> = [];
|
||||
iterateOnInstances(initialInstances, instance => {
|
||||
if (instance.getLayer() !== layer_name) return;
|
||||
if (instance.getObjectName() !== object_name) return;
|
||||
if (
|
||||
existingInstanceIds.some(id =>
|
||||
@@ -1854,6 +1865,8 @@ const put3dInstances: EditorFunction = {
|
||||
)
|
||||
) {
|
||||
modifiedAndCreatedInstances.push(instance);
|
||||
// Take the opportunity to move to a new layer if specified.
|
||||
instance.setLayer(layer_name);
|
||||
}
|
||||
});
|
||||
for (let i = 0; i < newInstancesCount; i++) {
|
||||
@@ -2379,7 +2392,7 @@ const createScene: EditorFunction = {
|
||||
if (project.hasLayoutNamed(scene_name)) {
|
||||
const scene = project.getLayout(scene_name);
|
||||
if (include_ui_layer && !scene.hasLayerNamed('UI')) {
|
||||
scene.insertNewLayer('UI', 0);
|
||||
scene.insertNewLayer('UI', scene.getLayersCount());
|
||||
addDefaultLightToLayer(scene.getLayer('UI'));
|
||||
return makeGenericSuccess(
|
||||
`Scene with name "${scene_name}" already exists, no need to re-create it. A layer called "UI" was added to it.`
|
||||
@@ -2394,7 +2407,7 @@ const createScene: EditorFunction = {
|
||||
const scenesCount = project.getLayoutsCount();
|
||||
const scene = project.insertNewLayout(scene_name, scenesCount);
|
||||
if (include_ui_layer) {
|
||||
scene.insertNewLayer('UI', 0);
|
||||
scene.insertNewLayer('UI', scene.getLayersCount());
|
||||
}
|
||||
if (background_color) {
|
||||
const colorAsRgb = hexNumberToRGBArray(
|
||||
@@ -2438,6 +2451,581 @@ const deleteScene: EditorFunction = {
|
||||
},
|
||||
};
|
||||
|
||||
const serializeEffectProperties = (
|
||||
effect: gdEffect,
|
||||
effectMetadata: gdEffectMetadata
|
||||
) => {
|
||||
const effectProperties = effectMetadata.getProperties();
|
||||
const propertyNames = effectProperties.keys().toJSArray();
|
||||
return propertyNames
|
||||
.map(name => {
|
||||
const propertyDescriptor = effectProperties.get(name);
|
||||
if (shouldHideProperty(propertyDescriptor)) return null;
|
||||
|
||||
// Set the value of the property to what is stored in the effect.
|
||||
// If it's not set, none of these will be set and the "value" will be the default one
|
||||
// serialized by the property descriptor.
|
||||
let value = null;
|
||||
if (effect.hasDoubleParameter(name)) {
|
||||
value = effect.getDoubleParameter(name);
|
||||
} else if (effect.hasStringParameter(name)) {
|
||||
value = effect.getStringParameter(name);
|
||||
} else if (effect.hasBooleanParameter(name)) {
|
||||
value = effect.getBooleanParameter(name);
|
||||
}
|
||||
|
||||
if (value === null) {
|
||||
return serializeNamedProperty(name, propertyDescriptor);
|
||||
}
|
||||
|
||||
return {
|
||||
...serializeNamedProperty(name, propertyDescriptor),
|
||||
value,
|
||||
};
|
||||
})
|
||||
.filter(Boolean);
|
||||
};
|
||||
|
||||
const inspectScenePropertiesLayersEffects: EditorFunction = {
|
||||
renderForEditor: ({ args }) => {
|
||||
const scene_name = extractRequiredString(args, 'scene_name');
|
||||
|
||||
return {
|
||||
text: (
|
||||
<Trans>
|
||||
Inspecting scene properties, layers and effects for scene {scene_name}
|
||||
.
|
||||
</Trans>
|
||||
),
|
||||
};
|
||||
},
|
||||
launchFunction: async ({ project, args }) => {
|
||||
const scene_name = extractRequiredString(args, 'scene_name');
|
||||
|
||||
if (!project.hasLayoutNamed(scene_name)) {
|
||||
return makeGenericFailure(`Scene not found: "${scene_name}".`);
|
||||
}
|
||||
|
||||
const scene = project.getLayout(scene_name);
|
||||
const layersContainer = scene.getLayers();
|
||||
|
||||
return {
|
||||
success: true,
|
||||
propertiesLayersEffectsForSceneNamed: scene.getName(),
|
||||
properties: {
|
||||
backgroundColor: rgbColorToHex(
|
||||
scene.getBackgroundColorRed(),
|
||||
scene.getBackgroundColorGreen(),
|
||||
scene.getBackgroundColorBlue()
|
||||
),
|
||||
stopSoundsOnStartup: scene.stopSoundsOnStartup(),
|
||||
|
||||
// Also include some project related properties:
|
||||
gameResolutionWidth: project.getGameResolutionWidth(),
|
||||
gameResolutionHeight: project.getGameResolutionHeight(),
|
||||
gameOrientation: project.getOrientation(),
|
||||
gameScaleMode: project.getScaleMode(),
|
||||
gameName: project.getName(),
|
||||
},
|
||||
layers: mapFor(0, layersContainer.getLayersCount(), i => {
|
||||
const layer = layersContainer.getLayerAt(i);
|
||||
const effectsContainer = layer.getEffects();
|
||||
return {
|
||||
name: layer.getName(),
|
||||
position: i,
|
||||
effects: mapFor(0, effectsContainer.getEffectsCount(), j => {
|
||||
const effect = effectsContainer.getEffectAt(j);
|
||||
const effectMetadata = gd.MetadataProvider.getEffectMetadata(
|
||||
project.getCurrentPlatform(),
|
||||
effect.getEffectType()
|
||||
);
|
||||
|
||||
if (gd.MetadataProvider.isBadEffectMetadata(effectMetadata)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
effectName: effect.getName(),
|
||||
effectType: effect.getEffectType(),
|
||||
effectProperties: serializeEffectProperties(
|
||||
effect,
|
||||
effectMetadata
|
||||
),
|
||||
};
|
||||
}).filter(Boolean),
|
||||
};
|
||||
}),
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
const isFuzzyMatch = (string1: string, string2: string) => {
|
||||
const simplifiedString1 = string1.toLowerCase().replace(/\s|_|-/g, '');
|
||||
const simplifiedString2 = string2.toLowerCase().replace(/\s|_|-/g, '');
|
||||
|
||||
return simplifiedString1 === simplifiedString2;
|
||||
};
|
||||
|
||||
const changeScenePropertiesLayersEffects: EditorFunction = {
|
||||
renderForEditor: ({ args, shouldShowDetails }) => {
|
||||
const scene_name = extractRequiredString(args, 'scene_name');
|
||||
|
||||
const changed_properties = SafeExtractor.extractArrayProperty(
|
||||
args,
|
||||
'changed_properties'
|
||||
);
|
||||
const changed_layers = SafeExtractor.extractArrayProperty(
|
||||
args,
|
||||
'changed_layers'
|
||||
);
|
||||
const changed_layer_effects = SafeExtractor.extractArrayProperty(
|
||||
args,
|
||||
'changed_layer_effects'
|
||||
);
|
||||
|
||||
const changedPropertiesCount =
|
||||
(changed_properties && changed_properties.length) || 0;
|
||||
const changedLayersCount = (changed_layers && changed_layers.length) || 0;
|
||||
const changedLayerEffectsCount =
|
||||
(changed_layer_effects && changed_layer_effects.length) || 0;
|
||||
|
||||
return {
|
||||
text:
|
||||
changedPropertiesCount > 0 &&
|
||||
changedLayersCount > 0 &&
|
||||
changedLayerEffectsCount > 0 ? (
|
||||
<Trans>
|
||||
Changing some scene properties, layers and effects for scene{' '}
|
||||
{scene_name}.
|
||||
</Trans>
|
||||
) : changedPropertiesCount > 0 && changedLayersCount > 0 ? (
|
||||
<Trans>
|
||||
Changing some scene properties and layers for scene {scene_name}.
|
||||
</Trans>
|
||||
) : changedPropertiesCount > 0 && changedLayerEffectsCount > 0 ? (
|
||||
<Trans>
|
||||
Changing some scene properties and effects for scene {scene_name}.
|
||||
</Trans>
|
||||
) : changedLayerEffectsCount > 0 && changedLayersCount > 0 ? (
|
||||
<Trans>
|
||||
Changing some scene effects and layers for scene {scene_name}.
|
||||
</Trans>
|
||||
) : changedPropertiesCount > 0 ? (
|
||||
<Trans>Changing some scene properties for scene {scene_name}.</Trans>
|
||||
) : changedLayersCount > 0 ? (
|
||||
<Trans>Changing some scene layers for scene {scene_name}.</Trans>
|
||||
) : changedLayerEffectsCount > 0 ? (
|
||||
<Trans>Changing some scene effects for scene {scene_name}.</Trans>
|
||||
) : (
|
||||
<Trans>Unknown changes attempted for scene {scene_name}.</Trans>
|
||||
),
|
||||
};
|
||||
},
|
||||
launchFunction: async ({
|
||||
project,
|
||||
args,
|
||||
onInstancesModifiedOutsideEditor,
|
||||
}) => {
|
||||
const scene_name = extractRequiredString(args, 'scene_name');
|
||||
|
||||
if (!project.hasLayoutNamed(scene_name)) {
|
||||
return makeGenericFailure(`Scene not found: "${scene_name}".`);
|
||||
}
|
||||
const scene = project.getLayout(scene_name);
|
||||
|
||||
const changes = [];
|
||||
const warnings = [];
|
||||
|
||||
const changed_properties = SafeExtractor.extractArrayProperty(
|
||||
args,
|
||||
'changed_properties'
|
||||
);
|
||||
const changed_layers = SafeExtractor.extractArrayProperty(
|
||||
args,
|
||||
'changed_layers'
|
||||
);
|
||||
const changed_layer_effects = SafeExtractor.extractArrayProperty(
|
||||
args,
|
||||
'changed_layer_effects'
|
||||
);
|
||||
|
||||
if (changed_properties)
|
||||
changed_properties.forEach(changed_property => {
|
||||
const propertyName = SafeExtractor.extractStringProperty(
|
||||
changed_property,
|
||||
'property_name'
|
||||
);
|
||||
const newValue = SafeExtractor.extractStringProperty(
|
||||
changed_property,
|
||||
'new_value'
|
||||
);
|
||||
if (propertyName === null || newValue === null) {
|
||||
warnings.push(
|
||||
`Missing "property_name" or "new_value" in the changed_property object: ${JSON.stringify(
|
||||
changed_property
|
||||
)}. It was ignored and not changed.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isFuzzyMatch(propertyName, 'backgroundColor')) {
|
||||
const colorAsRgb = hexNumberToRGBArray(rgbOrHexToHexNumber(newValue));
|
||||
scene.setBackgroundColor(colorAsRgb[0], colorAsRgb[1], colorAsRgb[2]);
|
||||
changes.push('Modified the scene background color.');
|
||||
} else if (isFuzzyMatch(propertyName, 'gameResolutionWidth')) {
|
||||
project.setGameResolutionSize(
|
||||
parseInt(newValue),
|
||||
project.getGameResolutionHeight()
|
||||
);
|
||||
changes.push('Modified the game resolution width.');
|
||||
} else if (isFuzzyMatch(propertyName, 'stopSoundsOnStartup')) {
|
||||
scene.setStopSoundsOnStartup(newValue.toLowerCase() === 'true');
|
||||
changes.push(
|
||||
'Modified whether sounds should be stopped on scene startup.'
|
||||
);
|
||||
} else if (isFuzzyMatch(propertyName, 'gameResolutionHeight')) {
|
||||
project.setGameResolutionSize(
|
||||
project.getGameResolutionWidth(),
|
||||
parseInt(newValue)
|
||||
);
|
||||
changes.push('Modified the game resolution height.');
|
||||
} else if (isFuzzyMatch(propertyName, 'gameOrientation')) {
|
||||
project.setOrientation(newValue);
|
||||
changes.push('Modified the game orientation.');
|
||||
} else if (isFuzzyMatch(propertyName, 'gameScaleMode')) {
|
||||
project.setScaleMode(newValue);
|
||||
changes.push('Modified the game scale mode.');
|
||||
} else if (isFuzzyMatch(propertyName, 'gameName')) {
|
||||
project.setName(newValue);
|
||||
changes.push('Modified the game name.');
|
||||
} else {
|
||||
warnings.push(
|
||||
`Unknown property for the scene: "${propertyName}". It was ignored and not changed.`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
if (changed_layers) {
|
||||
changed_layers.forEach(changed_layer => {
|
||||
const layerName = SafeExtractor.extractStringProperty(
|
||||
changed_layer,
|
||||
'layer_name'
|
||||
);
|
||||
if (layerName === null) {
|
||||
warnings.push(
|
||||
`Missing "layer_name" in an item of changed_layers. It was ignored and not changed.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const new_layer_name = SafeExtractor.extractStringProperty(
|
||||
changed_layer,
|
||||
'new_layer_name'
|
||||
);
|
||||
const new_layer_position = SafeExtractor.extractNumberProperty(
|
||||
changed_layer,
|
||||
'new_layer_position'
|
||||
);
|
||||
const delete_this_layer = SafeExtractor.extractBooleanProperty(
|
||||
changed_layer,
|
||||
'delete_this_layer'
|
||||
);
|
||||
const move_instances_to_layer = SafeExtractor.extractStringProperty(
|
||||
changed_layer,
|
||||
'move_instances_to_layer'
|
||||
);
|
||||
|
||||
if (scene.hasLayerNamed(layerName)) {
|
||||
if (delete_this_layer) {
|
||||
if (move_instances_to_layer) {
|
||||
gd.WholeProjectRefactorer.mergeLayersInScene(
|
||||
project,
|
||||
scene,
|
||||
layerName,
|
||||
move_instances_to_layer
|
||||
);
|
||||
} else {
|
||||
// Note: some instances will be invalidated because of this.
|
||||
gd.WholeProjectRefactorer.removeLayerInScene(
|
||||
project,
|
||||
scene,
|
||||
layerName
|
||||
);
|
||||
}
|
||||
scene.getLayers().removeLayer(layerName);
|
||||
changes.push(
|
||||
`Removed layer "${layerName}" for scene "${scene.getName()}".`
|
||||
);
|
||||
} else {
|
||||
if (new_layer_name) {
|
||||
gd.WholeProjectRefactorer.renameLayerInScene(
|
||||
project,
|
||||
scene,
|
||||
layerName,
|
||||
new_layer_name
|
||||
);
|
||||
changes.push(
|
||||
`Renamed layer "${layerName}" to "${new_layer_name}" for scene "${scene.getName()}".`
|
||||
);
|
||||
}
|
||||
}
|
||||
if (new_layer_position !== null) {
|
||||
scene
|
||||
.getLayers()
|
||||
.moveLayer(
|
||||
scene.getLayers().getLayerPosition(layerName),
|
||||
new_layer_position
|
||||
);
|
||||
changes.push(
|
||||
`Moved layer "${layerName}" to position ${new_layer_position} for scene "${scene.getName()}".`
|
||||
);
|
||||
}
|
||||
|
||||
// /!\ Tell the editor that some instances have potentially been modified (and even removed).
|
||||
// This will force the instances editor to destroy and mount again the
|
||||
// renderers to avoid keeping any references to existing instances, and also drop any selection.
|
||||
onInstancesModifiedOutsideEditor({
|
||||
scene,
|
||||
});
|
||||
} else {
|
||||
scene
|
||||
.getLayers()
|
||||
.insertNewLayer(
|
||||
new_layer_name || layerName,
|
||||
new_layer_position === null
|
||||
? scene.getLayersCount()
|
||||
: new_layer_position
|
||||
);
|
||||
changes.push(
|
||||
`Created new layer "${new_layer_name ||
|
||||
layerName}" for scene "${scene.getName()}" at position ${new_layer_position ||
|
||||
0}.`
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (changed_layer_effects) {
|
||||
changed_layer_effects.forEach(changed_layer_effect => {
|
||||
const layerName = SafeExtractor.extractStringProperty(
|
||||
changed_layer_effect,
|
||||
'layer_name'
|
||||
);
|
||||
if (layerName === null) {
|
||||
warnings.push(
|
||||
`Missing "layer_name" in an item of changed_layer_effects. It was ignored and not changed.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!scene.hasLayerNamed(layerName)) {
|
||||
warnings.push(
|
||||
`Layer not found: "${layerName}". It was ignored and no effects on it were changed.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
const layer = scene.getLayers().getLayer(layerName);
|
||||
const effectsContainer = layer.getEffects();
|
||||
|
||||
const effectName = SafeExtractor.extractStringProperty(
|
||||
changed_layer_effect,
|
||||
'effect_name'
|
||||
);
|
||||
if (effectName === null) {
|
||||
warnings.push(
|
||||
`Missing "effect_name" in an item of changed_layer_effects. It was ignored and not changed.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
const effect_type = SafeExtractor.extractStringProperty(
|
||||
changed_layer_effect,
|
||||
'effect_type'
|
||||
);
|
||||
const new_effect_name = SafeExtractor.extractStringProperty(
|
||||
changed_layer_effect,
|
||||
'new_effect_name'
|
||||
);
|
||||
const new_effect_position = SafeExtractor.extractNumberProperty(
|
||||
changed_layer_effect,
|
||||
'new_effect_position'
|
||||
);
|
||||
const delete_this_effect = SafeExtractor.extractBooleanProperty(
|
||||
changed_layer_effect,
|
||||
'delete_this_effect'
|
||||
);
|
||||
let newlyCreatedEffect: gdEffect | null = null;
|
||||
|
||||
if (effectsContainer.hasEffectNamed(effectName)) {
|
||||
const effect = effectsContainer.getEffect(effectName);
|
||||
if (delete_this_effect) {
|
||||
effectsContainer.removeEffect(effectName);
|
||||
changes.push(
|
||||
`Removed "${effectName}" effect on layer "${layerName}".`
|
||||
);
|
||||
} else {
|
||||
if (new_effect_name) {
|
||||
effect.setName(new_effect_name);
|
||||
changes.push(
|
||||
`Renamed the "${effectName}" effect on layer "${layerName}" to "${new_effect_name}".`
|
||||
);
|
||||
}
|
||||
if (new_effect_position !== null) {
|
||||
effectsContainer.moveEffect(
|
||||
effectsContainer.getEffectPosition(effectName),
|
||||
new_effect_position
|
||||
);
|
||||
changes.push(
|
||||
`Moved the "${effectName}" effect on layer "${layerName}" to position ${new_effect_position}.`
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (effect_type) {
|
||||
const newEffectName = new_effect_name || effectName;
|
||||
const effectMetadata = gd.MetadataProvider.getEffectMetadata(
|
||||
project.getCurrentPlatform(),
|
||||
effect_type
|
||||
);
|
||||
if (gd.MetadataProvider.isBadEffectMetadata(effectMetadata)) {
|
||||
warnings.push(
|
||||
`Effect type "${effect_type}" is not a valid effect type. Effect "${newEffectName}" was NOT added.`
|
||||
);
|
||||
} else {
|
||||
newlyCreatedEffect = effectsContainer.insertNewEffect(
|
||||
newEffectName,
|
||||
new_effect_position || 0
|
||||
);
|
||||
newlyCreatedEffect.setEffectType(effect_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const changed_properties = SafeExtractor.extractArrayProperty(
|
||||
changed_layer_effect,
|
||||
'changed_properties'
|
||||
);
|
||||
if (changed_properties) {
|
||||
if (!effectsContainer.hasEffectNamed(effectName)) {
|
||||
warnings.push(
|
||||
`Effect not found: "${effectName}". It was ignored and not changed.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
const effect = effectsContainer.getEffect(effectName);
|
||||
const effectMetadata = gd.MetadataProvider.getEffectMetadata(
|
||||
project.getCurrentPlatform(),
|
||||
effect.getEffectType()
|
||||
);
|
||||
|
||||
if (gd.MetadataProvider.isBadEffectMetadata(effectMetadata)) {
|
||||
warnings.push(
|
||||
`Effect "${effectName}" is not a valid effect. It was ignored and not changed.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const effectProperties = effectMetadata.getProperties();
|
||||
|
||||
changed_properties.forEach(changed_property => {
|
||||
const propertyName = SafeExtractor.extractStringProperty(
|
||||
changed_property,
|
||||
'property_name'
|
||||
);
|
||||
const newValue = SafeExtractor.extractStringProperty(
|
||||
changed_property,
|
||||
'new_value'
|
||||
);
|
||||
if (propertyName === null || newValue === null) {
|
||||
warnings.push(
|
||||
`Missing "property_name" or "new_value" in an item of changed_properties. It was ignored and not changed. Make sure you follow the exact format for changing effect properties.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const { foundProperty } = findPropertyByName({
|
||||
properties: effectProperties,
|
||||
name: propertyName,
|
||||
});
|
||||
if (!foundProperty) {
|
||||
warnings.push(
|
||||
`Property not found: "${propertyName}" in effect "${effectName}". It was ignored and not changed. Make sure you only change existing effect properties.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const lowercasedType = foundProperty.getType().toLowerCase();
|
||||
if (lowercasedType === 'number') {
|
||||
effect.setDoubleParameter(
|
||||
propertyName,
|
||||
parseFloat(newValue) || 0
|
||||
);
|
||||
} else if (lowercasedType === 'boolean') {
|
||||
effect.setBooleanParameter(
|
||||
propertyName,
|
||||
newValue.toLowerCase() === 'true'
|
||||
);
|
||||
} else {
|
||||
effect.setStringParameter(propertyName, newValue);
|
||||
}
|
||||
|
||||
changes.push(
|
||||
`Modified "${propertyName}" property of the "${effectName}" effect to "${newValue}".`
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
if (newlyCreatedEffect) {
|
||||
const effectMetadata = gd.MetadataProvider.getEffectMetadata(
|
||||
project.getCurrentPlatform(),
|
||||
newlyCreatedEffect.getEffectType()
|
||||
);
|
||||
if (gd.MetadataProvider.isBadEffectMetadata(effectMetadata)) {
|
||||
// Should not happen.
|
||||
} else {
|
||||
changes.push(
|
||||
`Created new "${newlyCreatedEffect.getName()}" effect on layer "${layerName}" at position ${new_effect_position ||
|
||||
0}. It properties are: ${serializeEffectProperties(
|
||||
newlyCreatedEffect,
|
||||
effectMetadata
|
||||
)
|
||||
// This stringify might not give the prettiest output, this could be improved.
|
||||
.map(serializedProperty => JSON.stringify(serializedProperty))
|
||||
.join(', ')}.`
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (changes.length === 0 && warnings.length === 0) {
|
||||
return {
|
||||
success: false,
|
||||
message: 'No changes were made.',
|
||||
};
|
||||
} else if (changes.length === 0 && warnings.length > 0) {
|
||||
return {
|
||||
success: false,
|
||||
message:
|
||||
'No changes were made because of the issues listed in the warnings.',
|
||||
warnings: warnings.join('\n'),
|
||||
};
|
||||
} else if (changes.length > 0 && warnings.length === 0) {
|
||||
return {
|
||||
success: true,
|
||||
message: ['Successfully done the changes.', ...changes].join('\n'),
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
success: true,
|
||||
message: [
|
||||
'Successfully done some changes but some issues were found - see the warnings.',
|
||||
...changes,
|
||||
].join('\n'),
|
||||
warnings: warnings.join('\n'),
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const addOrEditVariable: EditorFunction = {
|
||||
renderForEditor: ({ args, shouldShowDetails }) => {
|
||||
const variable_name_or_path = extractRequiredString(
|
||||
@@ -2595,5 +3183,7 @@ export const editorFunctions: { [string]: EditorFunction } = {
|
||||
add_scene_events: addSceneEvents,
|
||||
create_scene: createScene,
|
||||
delete_scene: deleteScene,
|
||||
inspect_scene_properties_layers_effects: inspectScenePropertiesLayersEffects,
|
||||
change_scene_properties_layers_effects: changeScenePropertiesLayersEffects,
|
||||
add_or_edit_variable: addOrEditVariable,
|
||||
};
|
||||
|
@@ -37,6 +37,10 @@ export type SceneEventsOutsideEditorChanges = {|
|
||||
newOrChangedAiGeneratedEventIds: Set<string>,
|
||||
|};
|
||||
|
||||
export type InstancesOutsideEditorChanges = {|
|
||||
scene: gdLayout,
|
||||
|};
|
||||
|
||||
export type RenderEditorContainerProps = {|
|
||||
isActive: boolean,
|
||||
projectItemName: ?string,
|
||||
@@ -179,11 +183,14 @@ export type RenderEditorContainerProps = {|
|
||||
) => void,
|
||||
onSceneObjectsDeleted: (scene: gdLayout) => void,
|
||||
|
||||
onInstancesModifiedOutsideEditor: (
|
||||
changes: InstancesOutsideEditorChanges
|
||||
) => void,
|
||||
|
||||
// Events editing
|
||||
onSceneEventsModifiedOutsideEditor: (
|
||||
changes: SceneEventsOutsideEditorChanges
|
||||
) => void,
|
||||
|
||||
onExtractAsExternalLayout: (name: string) => void,
|
||||
onExtractAsEventBasedObject: (
|
||||
extensionName: string,
|
||||
|
@@ -4,6 +4,7 @@ import {
|
||||
type RenderEditorContainerProps,
|
||||
type RenderEditorContainerPropsWithRef,
|
||||
type SceneEventsOutsideEditorChanges,
|
||||
type InstancesOutsideEditorChanges,
|
||||
} from './BaseEditor';
|
||||
import { prepareInstancesEditorSettings } from '../../InstancesEditor/InstancesEditorSettings';
|
||||
import {
|
||||
@@ -115,6 +116,10 @@ export class CustomObjectEditorContainer extends React.Component<RenderEditorCon
|
||||
// No thing to be done.
|
||||
}
|
||||
|
||||
onInstancesModifiedOutsideEditor(changes: InstancesOutsideEditorChanges) {
|
||||
// No thing to be done.
|
||||
}
|
||||
|
||||
saveUiSettings = () => {
|
||||
// const layout = this.getCustomObject();
|
||||
// const editor = this.editor;
|
||||
|
@@ -7,6 +7,7 @@ import {
|
||||
type RenderEditorContainerProps,
|
||||
type RenderEditorContainerPropsWithRef,
|
||||
type SceneEventsOutsideEditorChanges,
|
||||
type InstancesOutsideEditorChanges,
|
||||
} from './BaseEditor';
|
||||
import SubscriptionChecker, {
|
||||
type SubscriptionCheckerInterface,
|
||||
@@ -66,6 +67,10 @@ export class DebuggerEditorContainer extends React.Component<
|
||||
// No thing to be done.
|
||||
}
|
||||
|
||||
onInstancesModifiedOutsideEditor(changes: InstancesOutsideEditorChanges) {
|
||||
// No thing to be done.
|
||||
}
|
||||
|
||||
// To be updated, see https://reactjs.org/docs/react-component.html#unsafe_componentwillreceiveprops.
|
||||
UNSAFE_componentWillReceiveProps() {
|
||||
this._checkUserHasSubscription();
|
||||
|
@@ -6,6 +6,7 @@ import {
|
||||
type RenderEditorContainerProps,
|
||||
type RenderEditorContainerPropsWithRef,
|
||||
type SceneEventsOutsideEditorChanges,
|
||||
type InstancesOutsideEditorChanges,
|
||||
} from './BaseEditor';
|
||||
import { ProjectScopedContainersAccessor } from '../../InstructionOrExpression/EventsScope';
|
||||
import { type ObjectWithContext } from '../../ObjectsList/EnumerateObjects';
|
||||
@@ -68,6 +69,10 @@ export class EventsEditorContainer extends React.Component<RenderEditorContainer
|
||||
}
|
||||
}
|
||||
|
||||
onInstancesModifiedOutsideEditor(changes: InstancesOutsideEditorChanges) {
|
||||
// No thing to be done.
|
||||
}
|
||||
|
||||
getLayout(): ?gdLayout {
|
||||
const { project, projectItemName } = this.props;
|
||||
if (
|
||||
|
@@ -5,6 +5,7 @@ import {
|
||||
type RenderEditorContainerProps,
|
||||
type RenderEditorContainerPropsWithRef,
|
||||
type SceneEventsOutsideEditorChanges,
|
||||
type InstancesOutsideEditorChanges,
|
||||
} from './BaseEditor';
|
||||
import { type ObjectWithContext } from '../../ObjectsList/EnumerateObjects';
|
||||
|
||||
@@ -55,6 +56,10 @@ export class EventsFunctionsExtensionEditorContainer extends React.Component<Ren
|
||||
// No thing to be done.
|
||||
}
|
||||
|
||||
onInstancesModifiedOutsideEditor(changes: InstancesOutsideEditorChanges) {
|
||||
// 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.
|
||||
|
@@ -8,6 +8,7 @@ import {
|
||||
type RenderEditorContainerProps,
|
||||
type RenderEditorContainerPropsWithRef,
|
||||
type SceneEventsOutsideEditorChanges,
|
||||
type InstancesOutsideEditorChanges,
|
||||
} from './BaseEditor';
|
||||
import ExternalPropertiesDialog, {
|
||||
type ExternalProperties,
|
||||
@@ -99,6 +100,10 @@ export class ExternalEventsEditorContainer extends React.Component<
|
||||
// No thing to be done.
|
||||
}
|
||||
|
||||
onInstancesModifiedOutsideEditor(changes: InstancesOutsideEditorChanges) {
|
||||
// No thing to be done.
|
||||
}
|
||||
|
||||
getExternalEvents(): ?gdExternalEvents {
|
||||
const { project, projectItemName } = this.props;
|
||||
if (!project || !projectItemName) return null;
|
||||
|
@@ -13,6 +13,7 @@ import {
|
||||
type RenderEditorContainerProps,
|
||||
type RenderEditorContainerPropsWithRef,
|
||||
type SceneEventsOutsideEditorChanges,
|
||||
type InstancesOutsideEditorChanges,
|
||||
} from './BaseEditor';
|
||||
import ExternalPropertiesDialog, {
|
||||
type ExternalProperties,
|
||||
@@ -157,6 +158,16 @@ export class ExternalLayoutEditorContainer extends React.Component<
|
||||
// No thing to be done.
|
||||
}
|
||||
|
||||
onInstancesModifiedOutsideEditor(changes: InstancesOutsideEditorChanges) {
|
||||
if (changes.scene !== this.getLayout()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.editor) {
|
||||
this.editor.onInstancesModifiedOutsideEditor();
|
||||
}
|
||||
}
|
||||
|
||||
getExternalLayout(): ?gdExternalLayout {
|
||||
const { project, projectItemName } = this.props;
|
||||
if (!project || !projectItemName) return null;
|
||||
|
@@ -5,6 +5,7 @@ import { type I18n as I18nType } from '@lingui/core';
|
||||
import {
|
||||
type RenderEditorContainerPropsWithRef,
|
||||
type SceneEventsOutsideEditorChanges,
|
||||
type InstancesOutsideEditorChanges,
|
||||
} from '../BaseEditor';
|
||||
import {
|
||||
type FileMetadataAndStorageProviderName,
|
||||
@@ -178,6 +179,9 @@ export type HomePageEditorInterface = {|
|
||||
onSceneEventsModifiedOutsideEditor: (
|
||||
scene: SceneEventsOutsideEditorChanges
|
||||
) => void,
|
||||
onInstancesModifiedOutsideEditor: (
|
||||
changes: InstancesOutsideEditorChanges
|
||||
) => void,
|
||||
|};
|
||||
|
||||
export const HomePage = React.memo<Props>(
|
||||
@@ -486,6 +490,13 @@ export const HomePage = React.memo<Props>(
|
||||
[]
|
||||
);
|
||||
|
||||
const onInstancesModifiedOutsideEditor = React.useCallback(
|
||||
(changes: InstancesOutsideEditorChanges) => {
|
||||
// No thing to be done.
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
React.useImperativeHandle(ref, () => ({
|
||||
getProject,
|
||||
updateToolbar,
|
||||
@@ -494,6 +505,7 @@ export const HomePage = React.memo<Props>(
|
||||
onSceneObjectEdited,
|
||||
onSceneObjectsDeleted,
|
||||
onSceneEventsModifiedOutsideEditor,
|
||||
onInstancesModifiedOutsideEditor,
|
||||
}));
|
||||
|
||||
// As the homepage is never unmounted, we need to ensure the games platform
|
||||
|
@@ -4,6 +4,7 @@ import {
|
||||
type RenderEditorContainerProps,
|
||||
type RenderEditorContainerPropsWithRef,
|
||||
type SceneEventsOutsideEditorChanges,
|
||||
type InstancesOutsideEditorChanges,
|
||||
} from './BaseEditor';
|
||||
import ResourcesEditor from '../../ResourcesEditor';
|
||||
import { type ObjectWithContext } from '../../ObjectsList/EnumerateObjects';
|
||||
@@ -50,6 +51,10 @@ export class ResourcesEditorContainer extends React.Component<RenderEditorContai
|
||||
// No thing to be done.
|
||||
}
|
||||
|
||||
onInstancesModifiedOutsideEditor(changes: InstancesOutsideEditorChanges) {
|
||||
// No thing to be done.
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: RenderEditorContainerProps) {
|
||||
if (
|
||||
this.editor &&
|
||||
|
@@ -10,6 +10,7 @@ import {
|
||||
type RenderEditorContainerProps,
|
||||
type RenderEditorContainerPropsWithRef,
|
||||
type SceneEventsOutsideEditorChanges,
|
||||
type InstancesOutsideEditorChanges,
|
||||
} from './BaseEditor';
|
||||
import { ProjectScopedContainersAccessor } from '../../InstructionOrExpression/EventsScope';
|
||||
import { type ObjectWithContext } from '../../ObjectsList/EnumerateObjects';
|
||||
@@ -98,6 +99,16 @@ export class SceneEditorContainer extends React.Component<RenderEditorContainerP
|
||||
// No thing to be done.
|
||||
}
|
||||
|
||||
onInstancesModifiedOutsideEditor(changes: InstancesOutsideEditorChanges) {
|
||||
if (changes.scene !== this.getLayout()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.editor) {
|
||||
this.editor.onInstancesModifiedOutsideEditor();
|
||||
}
|
||||
}
|
||||
|
||||
getLayout(): ?gdLayout {
|
||||
const { project, projectItemName } = this.props;
|
||||
if (
|
||||
|
@@ -24,7 +24,10 @@ import {
|
||||
saveUiSettings,
|
||||
} from './EditorTabs/EditorTabsHandler';
|
||||
import { type PreviewState } from './PreviewState';
|
||||
import { type SceneEventsOutsideEditorChanges } from './EditorContainers/BaseEditor';
|
||||
import {
|
||||
type SceneEventsOutsideEditorChanges,
|
||||
type InstancesOutsideEditorChanges,
|
||||
} from './EditorContainers/BaseEditor';
|
||||
import { type ResourceManagementProps } from '../ResourcesList/ResourceSource';
|
||||
import { type HotReloadPreviewButtonProps } from '../HotReload/HotReloadPreviewButton';
|
||||
import { type GamesList } from '../GameDashboard/UseGamesList';
|
||||
@@ -206,6 +209,9 @@ export type EditorTabsPaneCommonProps = {|
|
||||
onSceneEventsModifiedOutsideEditor: (
|
||||
changes: SceneEventsOutsideEditorChanges
|
||||
) => void,
|
||||
onInstancesModifiedOutsideEditor: (
|
||||
changes: InstancesOutsideEditorChanges
|
||||
) => void,
|
||||
onExtensionInstalled: (extensionNames: Array<string>) => void,
|
||||
gamesList: GamesList,
|
||||
|
||||
@@ -294,6 +300,7 @@ const EditorTabsPane = React.forwardRef<Props, {||}>((props, ref) => {
|
||||
onSceneObjectEdited,
|
||||
onSceneObjectsDeleted,
|
||||
onSceneEventsModifiedOutsideEditor,
|
||||
onInstancesModifiedOutsideEditor,
|
||||
onExtensionInstalled,
|
||||
gamesList,
|
||||
setEditorTabs,
|
||||
@@ -681,6 +688,7 @@ const EditorTabsPane = React.forwardRef<Props, {||}>((props, ref) => {
|
||||
onSceneObjectEdited: onSceneObjectEdited,
|
||||
onSceneObjectsDeleted: onSceneObjectsDeleted,
|
||||
onSceneEventsModifiedOutsideEditor: onSceneEventsModifiedOutsideEditor,
|
||||
onInstancesModifiedOutsideEditor: onInstancesModifiedOutsideEditor,
|
||||
onExtensionInstalled: onExtensionInstalled,
|
||||
gamesList,
|
||||
gamesPlatformFrameTools,
|
||||
|
@@ -58,6 +58,7 @@ import { renderResourcesEditorContainer } from './EditorContainers/ResourcesEdit
|
||||
import {
|
||||
type RenderEditorContainerPropsWithRef,
|
||||
type SceneEventsOutsideEditorChanges,
|
||||
type InstancesOutsideEditorChanges,
|
||||
} from './EditorContainers/BaseEditor';
|
||||
import { type Exporter } from '../ExportAndShare/ShareDialog';
|
||||
import ResourcesLoader from '../ResourcesLoader/index';
|
||||
@@ -2431,6 +2432,18 @@ const MainFrame = (props: Props) => {
|
||||
[state.editorTabs]
|
||||
);
|
||||
|
||||
const onInstancesModifiedOutsideEditor = React.useCallback(
|
||||
(changes: InstancesOutsideEditorChanges) => {
|
||||
for (const editor of getAllEditorTabs(state.editorTabs)) {
|
||||
const { editorRef } = editor;
|
||||
if (editorRef) {
|
||||
editorRef.onInstancesModifiedOutsideEditor(changes);
|
||||
}
|
||||
}
|
||||
},
|
||||
[state.editorTabs]
|
||||
);
|
||||
|
||||
const _onProjectItemModified = () => {
|
||||
triggerUnsavedChanges();
|
||||
forceUpdate();
|
||||
@@ -3872,6 +3885,7 @@ const MainFrame = (props: Props) => {
|
||||
onSceneObjectEdited: onSceneObjectEdited,
|
||||
onSceneObjectsDeleted: onSceneObjectsDeleted,
|
||||
onSceneEventsModifiedOutsideEditor: onSceneEventsModifiedOutsideEditor,
|
||||
onInstancesModifiedOutsideEditor: onInstancesModifiedOutsideEditor,
|
||||
onExtensionInstalled: onExtensionInstalled,
|
||||
gamesList: gamesList,
|
||||
};
|
||||
|
@@ -311,6 +311,18 @@ export default class SceneEditor extends React.Component<Props, State> {
|
||||
}
|
||||
};
|
||||
|
||||
onInstancesModifiedOutsideEditor = () => {
|
||||
// /!\ Drop the selection to avoid keeping any references to deleted instances.
|
||||
// This could be avoided if the selection used something like UUID to address instances.
|
||||
this.instancesSelection.clearSelection();
|
||||
|
||||
// /!\ Force the instances editor to destroy and mount again the
|
||||
// renderers to avoid keeping any references to existing instances
|
||||
if (this.editorDisplay)
|
||||
this.editorDisplay.instancesHandlers.forceRemountInstancesRenderers();
|
||||
this.updateToolbar();
|
||||
};
|
||||
|
||||
updateToolbar = () => {
|
||||
const { editorDisplay } = this;
|
||||
if (!editorDisplay) return;
|
||||
@@ -590,10 +602,8 @@ export default class SceneEditor extends React.Component<Props, State> {
|
||||
);
|
||||
|
||||
undo = () => {
|
||||
// TODO: Do not clear selection so that the user can actually see
|
||||
// the changes it is undoing (variable change, instance moved, etc.)
|
||||
// or find a way to display a sumup of the change such as "Variable XXX
|
||||
// in instance of Enemy changed to YYY"
|
||||
// /!\ Drop the selection to avoid keeping any references to deleted instances.
|
||||
// This could be avoided if the selection used something like UUID to address instances.
|
||||
this.instancesSelection.clearSelection();
|
||||
this.setState(
|
||||
{
|
||||
@@ -610,6 +620,8 @@ export default class SceneEditor extends React.Component<Props, State> {
|
||||
};
|
||||
|
||||
redo = () => {
|
||||
// /!\ Drop the selection to avoid keeping any references to deleted instances.
|
||||
// This could be avoided if the selection used something like UUID to address instances.
|
||||
this.instancesSelection.clearSelection();
|
||||
this.setState(
|
||||
{
|
||||
|
@@ -328,6 +328,7 @@ export const createAiRequest = async (
|
||||
gameId,
|
||||
fileMetadata,
|
||||
storageProviderName,
|
||||
toolsVersion,
|
||||
}: {|
|
||||
userId: string,
|
||||
userRequest: string,
|
||||
@@ -346,6 +347,7 @@ export const createAiRequest = async (
|
||||
gameId?: string,
|
||||
},
|
||||
storageProviderName: ?string,
|
||||
toolsVersion: string,
|
||||
|}
|
||||
): Promise<AiRequest> => {
|
||||
const authorizationHeader = await getAuthorizationHeader();
|
||||
@@ -363,6 +365,7 @@ export const createAiRequest = async (
|
||||
gameId,
|
||||
fileMetadata,
|
||||
storageProviderName,
|
||||
toolsVersion,
|
||||
},
|
||||
{
|
||||
params: {
|
||||
|
Reference in New Issue
Block a user