Update InstanceData to avoid old data to override new ones when changing of tab.

This commit is contained in:
Davy Hélard
2025-05-18 14:07:22 +02:00
parent 2edd127d68
commit 4adb7295bd
4 changed files with 227 additions and 125 deletions

View File

@@ -104,27 +104,19 @@ namespace gdjs {
);
return;
}
if (!eventsBasedObjectData.defaultVariant) {
eventsBasedObjectData.defaultVariant = {
...eventsBasedObjectData,
name: '',
};
}
let usedVariantData: EventsBasedObjectVariantData =
eventsBasedObjectData.defaultVariant;
if (customObjectData.variant) {
for (
let variantIndex = 0;
variantIndex < eventsBasedObjectData.variants.length;
variantIndex++
) {
const variantData = eventsBasedObjectData.variants[variantIndex];
if (variantData.name === customObjectData.variant) {
usedVariantData = variantData;
break;
}
}
const usedVariantData: EventsBasedObjectVariantData | null =
this.getRuntimeScene()
.getGame()
.getEventsBasedObjectVariantData(
customObjectData.type,
customObjectData.variant
);
if (!usedVariantData) {
// This can't actually happen.
logger.error(
`Unknown variant "${customObjectData.variant}" for object "${customObjectData.type}".`
);
return;
}
this._isInnerAreaFollowingParentSize =

View File

@@ -127,12 +127,15 @@ namespace gdjs {
width: runtimeObject.getWidth(),
height: runtimeObject.getHeight(),
depth: runtimeObject.getDepth(),
locked: false, // TODO
// TODO: how to transmit/should we transmit other properties?
numberProperties: [],
stringProperties: [],
initialVariables: [],
// @ts-ignore
defaultWidth: runtimeObject.getOriginalWidth(),
defaultHeight: runtimeObject.getOriginalHeight(),
defaultDepth: runtimeObject.getOriginalDepth(),
locked: false, // TODO
// TODO: how to transmit/should we transmit other properties?
};
return instanceData;
@@ -160,7 +163,7 @@ namespace gdjs {
if (index < 0) {
this._selectedObjects.push(object);
} else {
this._selectedObjects.splice(index);
this._selectedObjects.splice(index, 1);
}
}
@@ -289,6 +292,7 @@ namespace gdjs {
private _runtimeGame: RuntimeGame;
private _editedInstanceContainer: gdjs.RuntimeInstanceContainer | null =
null;
private _editedInstanceDataList: InstanceData[] = [];
//@ts-ignore
private _tempVector2d: THREE.Vector2 =
typeof THREE === 'undefined' ? null : new THREE.Vector2();
@@ -328,6 +332,10 @@ namespace gdjs {
private _lastCursorY: number = 0;
private _wasMouseRightButtonPressed = false;
private _isLeftButtonPressed = false;
private _pressedOriginalCursorX = 0;
private _pressedOriginalCursorY = 0;
// Dragged new object:
private _draggedNewObject: gdjs.RuntimeObject | null = null;
@@ -335,6 +343,10 @@ namespace gdjs {
this._runtimeGame = game;
}
setEditedInstanceDataList(editedInstanceDataList: InstanceData[]) {
this._editedInstanceDataList = editedInstanceDataList;
}
setEditedInstanceContainer(
editedInstanceContainer: gdjs.RuntimeInstanceContainer | null
) {
@@ -855,7 +867,7 @@ namespace gdjs {
if (shouldDeleteSelection(inputManager)) {
const removedObjects = this._selection.getSelectedObjects();
removedObjects.forEach((object) => {
object.deleteFromScene(editedInstanceContainer);
object.deleteFromScene();
});
this._selection.clear();
this._sendSelectionUpdate({
@@ -1101,7 +1113,19 @@ namespace gdjs {
const updatedInstances = this._selection
.getSelectedObjects()
.map((object) => getInstanceDataFromRuntimeObject(object))
.map((object) => {
const instance = getInstanceDataFromRuntimeObject(object);
if (instance) {
// Avoid to clear these properties when assigning it to the old InstanceData.
// @ts-ignore
delete instance.initialVariables;
// @ts-ignore
delete instance.numberProperties;
// @ts-ignore
delete instance.stringProperties;
}
return instance;
})
.filter(isDefined);
const addedInstances =
@@ -1111,22 +1135,56 @@ namespace gdjs {
.filter(isDefined)
: [];
const removedInstances =
options && options.removedObjects ? options.removedObjects : [];
this._removeInstances(removedInstances);
this._updateInstances(updatedInstances);
this._addInstances(addedInstances);
debuggerClient.sendInstanceChanges({
updatedInstances,
addedInstances,
selectedInstances: getPersistentUuidsFromObjects(
this._selection.getSelectedObjects()
),
removedInstances:
options && options.removedObjects
? getPersistentUuidsFromObjects(options.removedObjects)
: [],
removedInstances: getPersistentUuidsFromObjects(removedInstances),
});
}
private _isLeftButtonPressed = false;
private _pressedOriginalCursorX = 0;
private _pressedOriginalCursorY = 0;
private _removeInstances(
removedInstances: Array<{ persistentUuid: string | null }>
) {
for (const removedInstance of removedInstances) {
// TODO: Might be worth indexing instances data
const instanceIndex = this._editedInstanceDataList.findIndex(
(instance) =>
instance.persistentUuid === removedInstance.persistentUuid
);
if (instanceIndex >= 0) {
this._editedInstanceDataList.splice(instanceIndex, 1);
}
}
}
private _updateInstances(updatedInstances: Array<InstanceData>) {
for (const updatedInstance of updatedInstances) {
// TODO: Might be worth indexing instances data
const oldInstance = this._editedInstanceDataList.find(
(oldInstance) =>
oldInstance.persistentUuid === updatedInstance.persistentUuid
);
if (oldInstance) {
Object.assign(oldInstance, updatedInstance);
}
}
}
private _addInstances(addedInstances: Array<InstanceData>) {
for (const addedInstance of addedInstances) {
this._editedInstanceDataList.push(addedInstance);
}
}
private _handleContextMenu() {
const inputManager = this._runtimeGame.getInputManager();
@@ -1161,7 +1219,7 @@ namespace gdjs {
if (!editedInstanceContainer) return;
if (this._draggedNewObject) {
this._draggedNewObject.deleteFromScene(editedInstanceContainer);
this._draggedNewObject.deleteFromScene();
this._draggedNewObject = null;
}
}
@@ -1236,7 +1294,7 @@ namespace gdjs {
}
if (this._draggedNewObject && this._draggedNewObject.getName() !== name) {
this._draggedNewObject.deleteFromScene(editedInstanceContainer);
this._draggedNewObject.deleteFromScene();
this._draggedNewObject = null;
}
@@ -1349,6 +1407,7 @@ namespace gdjs {
runtimeObject.extraInitializationFromInitialInstance(instance);
}
});
this._updateInstances(instances);
this._forceUpdateSelectionControls();
}
@@ -1357,14 +1416,16 @@ namespace gdjs {
if (!editedInstanceContainer) return;
editedInstanceContainer.createObjectsFrom(instances, 0, 0, 0, true);
this._addInstances(instances);
}
deleteSelection() {
const editedInstanceContainer = this._getEditedInstanceContainer();
if (!editedInstanceContainer) return;
this._removeInstances(this._selection.getSelectedObjects());
for (const object of this._selection.getSelectedObjects()) {
object.deleteFromScene(editedInstanceContainer);
object.deleteFromScene();
}
this._selection.clear();
}

View File

@@ -306,62 +306,12 @@ namespace gdjs {
return;
}
const runtimeGameOptions = this._runtimegame.getAdditionalOptions();
if (runtimeGameOptions.initialRuntimeGameStatus) {
// Skip changing the scene if we're already on the state that is being requested.
if (
runtimeGameOptions.initialRuntimeGameStatus.sceneName ===
sceneName &&
runtimeGameOptions.initialRuntimeGameStatus
.injectedExternalLayoutName === externalLayoutName &&
runtimeGameOptions.initialRuntimeGameStatus
.eventsBasedObjectType === eventsBasedObjectType &&
runtimeGameOptions.initialRuntimeGameStatus
.eventsBasedObjectVariantName === eventsBasedObjectVariantName
) {
return;
}
}
if (eventsBasedObjectType) {
const sceneAndCustomObject = runtimeGame._createSceneWithCustomObject(
eventsBasedObjectType,
eventsBasedObjectVariantName
);
if (sceneAndCustomObject) {
const { scene, customObjectInstanceContainer } =
sceneAndCustomObject;
runtimeGame.getSceneStack().setEditedRuntimeScene(scene);
if (runtimeGame._inGameEditor) {
runtimeGame._inGameEditor.setEditedInstanceContainer(
customObjectInstanceContainer
);
}
}
} else {
runtimeGame.getSceneStack().replace({
sceneName,
externalLayoutName,
skipCreatingInstancesFromScene: !!externalLayoutName,
clear: true,
});
if (runtimeGame._inGameEditor) {
runtimeGame._inGameEditor.setEditedInstanceContainer(null);
}
}
// Update initialRuntimeGameStatus so that a hard reload
// will come back to the same state, and so that we can check later
// if the game is already on the state that is being requested.
runtimeGameOptions.initialRuntimeGameStatus = {
isPaused: runtimeGame.isPaused(),
isInGameEdition: runtimeGame.isInGameEdition(),
sceneName: sceneName,
injectedExternalLayoutName: externalLayoutName,
skipCreatingInstancesFromScene: !!externalLayoutName,
this._runtimegame._switchToSceneOrVariant(
sceneName,
externalLayoutName,
eventsBasedObjectType,
eventsBasedObjectVariantName,
};
eventsBasedObjectVariantName
)
} else if (data.command === 'updateInstances') {
if (runtimeGame._inGameEditor)
runtimeGame._inGameEditor.reloadInstances(data.payload.instances);

View File

@@ -532,6 +532,35 @@ namespace gdjs {
return eventsBasedObjectData;
}
getEventsBasedObjectVariantData(
type: string,
variantName: string
): EventsBasedObjectVariantData | null {
const eventsBasedObjectData = this.getEventsBasedObjectData(type);
if (!eventsBasedObjectData) {
return null;
}
if (!eventsBasedObjectData.defaultVariant) {
eventsBasedObjectData.defaultVariant = {
...eventsBasedObjectData,
name: '',
};
}
let usedVariantData: EventsBasedObjectVariantData =
eventsBasedObjectData.defaultVariant;
for (
let variantIndex = 0;
variantIndex < eventsBasedObjectData.variants.length;
variantIndex++
) {
const variantData = eventsBasedObjectData.variants[variantIndex];
if (variantData.name === variantName) {
usedVariantData = variantData;
}
}
return usedVariantData;
}
/**
* Get the data associated to a scene.
*
@@ -975,41 +1004,23 @@ namespace gdjs {
return;
}
this._forceGameResolutionUpdate();
// Load the first scene
if (
this._options.initialRuntimeGameStatus &&
this._options.initialRuntimeGameStatus.eventsBasedObjectType
) {
const sceneAndCustomObject = this._createSceneWithCustomObject(
this._options.initialRuntimeGameStatus.eventsBasedObjectType,
this._options.initialRuntimeGameStatus
.eventsBasedObjectVariantName || ''
);
if (sceneAndCustomObject) {
const { scene, customObjectInstanceContainer } =
sceneAndCustomObject;
this._sceneStack.setEditedRuntimeScene(scene);
if (this._inGameEditor) {
this._inGameEditor.setEditedInstanceContainer(
customObjectInstanceContainer
);
}
}
} else {
this._sceneStack.push({
sceneName: this._getFirstSceneName(),
externalLayoutName:
this._options.initialRuntimeGameStatus
?.injectedExternalLayoutName || undefined,
skipCreatingInstancesFromScene:
this._options.initialRuntimeGameStatus
?.skipCreatingInstancesFromScene || false,
});
if (this._inGameEditor) {
this._inGameEditor.setEditedInstanceContainer(null);
}
}
const sceneName = this._getFirstSceneName();
const externalLayoutName =
this._options.initialRuntimeGameStatus
?.injectedExternalLayoutName || null;
const eventsBasedObjectType =
this._options.initialRuntimeGameStatus?.eventsBasedObjectType || null;
const eventsBasedObjectVariantName =
this._options.initialRuntimeGameStatus?.eventsBasedObjectVariantName || null;
this._switchToSceneOrVariant(
sceneName,
externalLayoutName,
eventsBasedObjectType,
eventsBasedObjectVariantName
);
this._watermark.displayAtStartup();
//Uncomment to profile the first x frames of the game.
@@ -1116,6 +1127,94 @@ namespace gdjs {
}
}
_switchToSceneOrVariant(
sceneName: string | null,
externalLayoutName: string | null,
eventsBasedObjectType: string | null,
eventsBasedObjectVariantName: string | null
) {
const runtimeGameOptions = this.getAdditionalOptions();
if (runtimeGameOptions.initialRuntimeGameStatus) {
// Skip changing the scene if we're already on the state that is being requested.
if (
runtimeGameOptions.initialRuntimeGameStatus.sceneName === sceneName &&
runtimeGameOptions.initialRuntimeGameStatus
.injectedExternalLayoutName === externalLayoutName &&
runtimeGameOptions.initialRuntimeGameStatus.eventsBasedObjectType ===
eventsBasedObjectType &&
runtimeGameOptions.initialRuntimeGameStatus
.eventsBasedObjectVariantName === eventsBasedObjectVariantName
) {
return;
}
}
let editedInstanceDataList: Array<InstanceData> | null = null;
if (eventsBasedObjectType) {
const sceneAndCustomObject = this._createSceneWithCustomObject(
eventsBasedObjectType,
eventsBasedObjectVariantName || ""
);
if (sceneAndCustomObject) {
const { scene, customObjectInstanceContainer } = sceneAndCustomObject;
this.getSceneStack().setEditedRuntimeScene(scene);
if (this._inGameEditor) {
this._inGameEditor.setEditedInstanceContainer(
customObjectInstanceContainer
);
const eventsBasedObjectVariantData =
this.getEventsBasedObjectVariantData(
eventsBasedObjectType,
eventsBasedObjectVariantName || ""
);
if (eventsBasedObjectVariantData) {
editedInstanceDataList = eventsBasedObjectVariantData.instances;
}
}
}
} else if (sceneName) {
this.getSceneStack().replace({
sceneName,
externalLayoutName: externalLayoutName === null ? undefined : externalLayoutName,
skipCreatingInstancesFromScene: !!externalLayoutName,
clear: true,
});
if (this._inGameEditor) {
this._inGameEditor.setEditedInstanceContainer(null);
if (externalLayoutName) {
const externalLayoutData =
this.getExternalLayoutData(externalLayoutName);
if (externalLayoutData) {
editedInstanceDataList = externalLayoutData.instances;
}
} else {
const sceneAndExtensionsData =
this.getSceneAndExtensionsData(sceneName);
if (sceneAndExtensionsData) {
editedInstanceDataList =
sceneAndExtensionsData.sceneData.instances;
}
}
}
}
if (this._inGameEditor && editedInstanceDataList) {
this._inGameEditor.setEditedInstanceDataList(editedInstanceDataList);
}
// Update initialRuntimeGameStatus so that a hard reload
// will come back to the same state, and so that we can check later
// if the game is already on the state that is being requested.
runtimeGameOptions.initialRuntimeGameStatus = {
isPaused: this.isPaused(),
isInGameEdition: this.isInGameEdition(),
sceneName: sceneName,
injectedExternalLayoutName: externalLayoutName,
skipCreatingInstancesFromScene: !!externalLayoutName,
eventsBasedObjectType,
eventsBasedObjectVariantName,
};
}
_createSceneWithCustomObject(
eventsBasedObjectType: string,
eventsBasedObjectVariantName: string