From 62d66c30afaae8773ed280fa60bbdb57aac97e27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davy=20H=C3=A9lard?= Date: Sat, 25 Nov 2023 21:22:34 +0100 Subject: [PATCH 1/7] [Object stack] Fix a crash when an object is deleted before any stack exists - The "move" actions can now move serveral stacks at once. --- extensions/reviewed/ObjectStack.json | 440 ++++++++++++------- scripts/lib/ExtensionsValidatorExceptions.js | 3 +- 2 files changed, 275 insertions(+), 168 deletions(-) diff --git a/extensions/reviewed/ObjectStack.json b/extensions/reviewed/ObjectStack.json index 6ad6d7b9..3e03a8af 100644 --- a/extensions/reviewed/ObjectStack.json +++ b/extensions/reviewed/ObjectStack.json @@ -8,7 +8,7 @@ "name": "ObjectStack", "previewIconUrl": "https://resources.gdevelop-app.com/assets/Icons/Line Hero Pack/Master/SVG/Videogames/Videogames_cards_game_solitaire_poker_blackjack_casino.svg", "shortDescription": "An ordered list of objects and a shuffle action.", - "version": "0.1.1", + "version": "0.2.0", "description": [ "It provides:", "* Actions to modify a stack of objects", @@ -40,6 +40,183 @@ ], "dependencies": [], "eventsFunctions": [ + { + "description": "Define helper classes JavaScript code.", + "fullName": "Define helper classes", + "functionType": "Action", + "name": "DefineHelperClasses", + "private": true, + "sentence": "Define helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs._objectStackExtension) {", + " return;", + "}", + "", + "class ObjectStack {", + " /**", + " * @type {Array}", + " */", + " stack = [];", + "", + " /**", + " * Make contains(), remove() and unicity checks more efficients.", + " * @type {Set}", + " */", + " objectSet = new Set();", + "", + " /**", + " * @param {gdjs.RuntimeObject} object", + " */", + " addOnTop(object) {", + " if (this.objectSet.has(object)) {", + " return false;", + " }", + " this.stack.push(object);", + " this.objectSet.add(object);", + " return true;", + " }", + "", + " /**", + " * @param {gdjs.RuntimeObject} object", + " * @param {number} height", + " */", + " insert(object, height) {", + " if (!this.objectSet.has(object)) {", + " this.stack.splice(height, 0, object);", + " this.objectSet.add(object);", + " runtimeScene.__objectStacks_allUsedObjects.add(object);", + " }", + " }", + "", + " /**", + " * @param {gdjs.RuntimeObject} object", + " */", + " remove(object) {", + " if (this.objectSet.has(object)) {", + " // The top element is likely to be removed from the stack.", + " // Make its removal O(1)", + " if (object === this.stack[stack.length - 1]) {", + " this.stack.pop();", + " }", + " else {", + " const index = this.stack.indexOf(object);", + " if (index >= 0) {", + " this.stack.splice(index, 1);", + " }", + " }", + " this.objectSet.delete(object);", + " }", + " }", + "", + " clear() {", + " this.stack.length = 0;", + " this.objectSet.clear();", + " }", + "", + " /**", + " * @param {number} insertHeight", + " * @param {ObjectStack} otherObjectStack", + " * @param {number} lowerBound", + " * @param {number} upperBound", + " */", + " takeInto(insertHeight, otherObjectStack, lowerBound, upperBound) {", + " const otherStack = otherObjectStack.stack;", + " const otherObjectSet = otherObjectStack.objectSet;", + "", + " upperBound = Math.min(upperBound, otherStack.length - 1);", + " for (let height = lowerBound; height <= upperBound; height++) {", + " const insertedObject = otherStack[height];", + " this.stack.splice(insertHeight, 0, insertedObject);", + " objectSet.add(insertedObject);", + " insertHeight++;", + " }", + " if (lowerBound <= upperBound) {", + " for (let height = lowerBound; height <= upperBound; height++) {", + " otherObjectSet.delete(otherStack[height]);", + " }", + " otherStack.splice(lowerBound, upperBound - lowerBound + 1);", + " }", + " }", + "", + " suffle() {", + " // Fisher–Yates shuffle", + " for (let i = stack.length - 1; i >= 1; i--) {", + " // TODO use a seed", + " const j = Math.floor(Math.random() * (i + 1));", + " const swap = this.stack[i];", + " this.stack[i] = this.stack[j]", + " this.stack[j] = swap;", + " }", + " }", + "", + " /**", + " * @param {gdjs.RuntimeObject} object", + " */", + " heightOf(object) {", + " return this.stack.indexOf(object);", + " }", + "", + " height() {", + " return this.stack.length;", + " }", + "", + " isEmpty() {", + " return this.stack.length === 0;", + " }", + "", + " /**", + " * @param {gdjs.RuntimeObject} object", + " * @param {number} lowerBound", + " * @param {number} upperBound", + " */", + " containsBetween(object, lowerBound, upperBound) {", + " upperBound = Math.min(upperBound, stack.length - 1);", + " for (let i = lowerBound; i <= upperBound; i++) {", + " if (stack[i] === element) {", + " return true;", + " }", + " }", + " return false;", + " }", + "", + " /**", + " * @param {gdjs.RuntimeObject} object", + " * @param {number} height", + " */", + " containsAt(object, height) {", + " return stack[height] === element;", + " }", + "", + " /**", + " * @param {gdjs.RuntimeObject} object", + " */", + " hasOnTop(object) {", + " return stack.length > 0 && stack[stack.length - 1] === object;", + " }", + "", + " /**", + " * @param {gdjs.RuntimeObject} object", + " */", + " contains(object) {", + " return objectSet.has(object);", + " }", + "}", + "", + "gdjs._objectStackExtension = {", + " ObjectStack", + "}" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true + } + ], + "parameters": [], + "objectGroups": [] + }, { "description": "Check if the stack contains the object between a range. The lower and upper bounds are included.", "fullName": "Contain between a range", @@ -60,21 +237,13 @@ "let upperBound = eventsFunctionContext.getArgument(\"UpperBound\");", "", "eventsFunctionContext.returnValue = gdjs.evtTools.object.twoListsTest(", - " (stackObject, element, stackBehaviorName) => {", + " (stackObject, element) => {", " const behavior = stackObject.getBehavior(stackBehaviorName);", - " /** @type {gdjs.RuntimeObject[]} */", - " const stack = behavior.objectStack;", - " let found = false;", - " upperBound = Math.min(upperBound, stack.length - 1);", - " for (let i = lowerBound; i <= upperBound && !found; i++) {", - " found = stack[i] === element;", - " }", - " return found;", + " return behavior.objectStack.containsBetween(element, lowerBound, upperBound);", " },", " stackObjectsLists,", " elementObjectsLists,", - " false,", - " stackBehaviorName", + " false", ");" ], "parameterObjects": "Object", @@ -129,27 +298,19 @@ "/** @type {Hashtable} */", "const elementObjectsLists = eventsFunctionContext.getObjectsLists(\"Element\");", "", - "// This code is duplicated from ContainsBetween because the picking wouldn't pass from one function to the other.", - "const lowerBound = Math.max(0, eventsFunctionContext.getArgument(\"Height\"));", - "let upperBound = eventsFunctionContext.getArgument(\"Height\");", + "const height = eventsFunctionContext.getArgument(\"Height\");", "", + "// This code is duplicated from ContainsBetween because the picking wouldn't pass from one function to the other.", "eventsFunctionContext.returnValue = gdjs.evtTools.object.twoListsTest(", - " (stackObject, element, stackBehaviorName) => {", + " (stackObject, element) => {", " const behavior = stackObject.getBehavior(stackBehaviorName);", - " /** @type {gdjs.RuntimeObject[]} */", - " const stack = behavior.objectStack;", - " let found = false;", - " upperBound = Math.min(upperBound, stack.length - 1);", - " for (let i = lowerBound; i <= upperBound && !found; i++) {", - " found = stack[i] === element;", - " }", - " return found;", + " return behavior.objectStack.containsAt(element, height);", " },", " stackObjectsLists,", " elementObjectsLists,", - " false,", - " stackBehaviorName", - ");" + " false", + ");", + "" ], "parameterObjects": "Object", "useStrict": true, @@ -199,16 +360,13 @@ "const elementObjectsLists = eventsFunctionContext.getObjectsLists(\"Element\");", "", "eventsFunctionContext.returnValue = gdjs.evtTools.object.twoListsTest(", - " (stackObject, element, stackBehaviorName) => {", + " (stackObject, element) => {", " const behavior = stackObject.getBehavior(stackBehaviorName);", - " /** @type {gdjs.RuntimeObject[]} */", - " const stack = behavior.objectStack;", - " return stack.length > 0 && stack[stack.length - 1] === element;", + " return behavior.objectStack.hasOnTop(element);", " },", " stackObjectsLists,", " elementObjectsLists,", - " false,", - " stackBehaviorName", + " false", ");" ], "parameterObjects": "Object", @@ -254,16 +412,13 @@ "const elementObjectsLists = eventsFunctionContext.getObjectsLists(\"Element\");", "", "eventsFunctionContext.returnValue = gdjs.evtTools.object.twoListsTest(", - " (stackObject, element, stackBehaviorName) => {", + " (stackObject, element) => {", " const behavior = stackObject.getBehavior(stackBehaviorName);", - " /** @type {Map */", - " const objectSet = behavior.objectSet;", - " return objectSet.has(element);", + " return behavior.objectStack.contains(element);", " },", " stackObjectsLists,", " elementObjectsLists,", - " false,", - " stackBehaviorName", + " false", ");" ], "parameterObjects": "Object", @@ -305,43 +460,52 @@ "name": "onCreated", "sentence": "", "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "ObjectStack::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, { "type": "BuiltinCommonInstructions::JsCode", "inlineCode": [ + "const ObjectStack = gdjs._objectStackExtension.ObjectStack;", + "", "const object = objects[0];", "const behaviorName = eventsFunctionContext.getBehaviorName(\"Behavior\");", "const behavior = object.getBehavior(behaviorName);", "", - "behavior.objectStack = [];", - "// Make contains(), remove() and unicity checks more efficients.", - "behavior.objectSet = new Set();", + "behavior.objectStack = new ObjectStack();", "", - "if (!runtimeScene.__allObjectStacks) {", - " runtimeScene.__allObjectStacks = new Set();", - " // Its only use is to have a O(1) check for", - " // deleted objects that have never been in a stack.", - " runtimeScene.__objectStacks_allUsedObjects = new Set();", + "if (!runtimeScene._objectStackExtension) {", + " runtimeScene._objectStackExtension = {", + " allObjectStacks = new Set(),", + " // Its only use is to have a O(1) check for", + " // deleted objects that have never been in a stack.", + " allUsedObjects = new Set()", + " };", " // Remove from deleted objects from stacks.", " gdjs.registerObjectDeletedFromSceneCallback(function (runtimeScene, obj) {", - " if (runtimeScene.__objectStacks_allUsedObjects.has(obj)) {", - " runtimeScene.__objectStacks_allUsedObjects.delete(obj);", - " for (const behavior of runtimeScene.__allObjectStacks) {", - " /** @type {gdjs.RuntimeObject[]} */", - " const stack = behavior.objectStack;", - " /** @type {Map */", - " const objectSet = behavior.objectSet;", - " if (objectSet.has(obj)) {", - " // There should be only one occurrence, but check the whole array just in case.", - " for (let index = stack.indexOf(obj); index >= 0; index = stack.indexOf(obj, index)) {", - " stack.splice(index, 1);", - " }", - " objectSet.delete(obj);", - " }", + " const extension = runtimeScene._objectStackExtension;", + " if (extension.allUsedObjects.has(obj)) {", + " extension.allUsedObjects.delete(obj);", + " for (const behavior of extension.allObjectStacks) {", + " behavior.objectStack.remove(obj);", " }", " }", " });", "}", - "runtimeScene.__allObjectStacks.add(behavior);" + "runtimeScene._objectStackExtension.allObjectStacks.add(behavior);", + "" ], "parameterObjects": "Object", "useStrict": true, @@ -376,12 +540,12 @@ "const behaviorName = eventsFunctionContext.getBehaviorName(\"Behavior\");", "const behavior = object.getBehavior(behaviorName);", "", - "runtimeScene.__allObjectStacks.delete(behavior);", + "runtimeScene._objectStackExtension.allObjectStacks.delete(behavior);", "" ], "parameterObjects": "Object", "useStrict": true, - "eventsSheetExpanded": false + "eventsSheetExpanded": true } ], "parameters": [ @@ -414,15 +578,11 @@ "const behavior = object.getBehavior(behaviorName);", "const elements = eventsFunctionContext.getObjects(\"Elements\");", "", - "/** @type {gdjs.RuntimeObject[]} */", "const stack = behavior.objectStack;", - "/** @type {Map */", - "const objectSet = behavior.objectSet;", "for (const element of elements) {", - " if (!objectSet.has(element)) {", - " stack.push(element);", - " behavior.objectSet.add(element);", - " runtimeScene.__objectStacks_allUsedObjects.add(element);", + " const isAdded = stack.addOnTop(element);", + " if (isAdded) {", + " runtimeScene.__objectStacks_allUsedObjects.add(object);", " }", "}" ], @@ -467,19 +627,16 @@ "const elements = eventsFunctionContext.getObjects(\"Elements\");", "const height = eventsFunctionContext.getArgument(\"Height\");", "", - "/** @type {gdjs.RuntimeObject[]} */", - "const stack = behavior.objectStack;", - "/** @type {Map */", - "const objectSet = behavior.objectSet;", "if (height < 0 || height > stack.length) {", " console.error(`Tried to insert in the stack at ${height} where the stack is ${stack.length} height.`);", " return;", "}", + "", + "const stack = behavior.objectStack;", "for (const element of elements) {", - " if (!objectSet.has(element)) {", - " stack.splice(height, 0, element);", - " objectSet.add(element);", - " runtimeScene.__objectStacks_allUsedObjects.add(element);", + " const isAdded = stack.insert(element, height);", + " if (isAdded) {", + " runtimeScene.__objectStacks_allUsedObjects.add(object);", " }", "}" ], @@ -528,25 +685,9 @@ "const behavior = object.getBehavior(behaviorName);", "const elements = eventsFunctionContext.getObjects(\"Elements\");", "", - "/** @type {gdjs.RuntimeObject[]} */", "const stack = behavior.objectStack;", - "/** @type {Map */", - "const objectSet = behavior.objectSet;", "for (const element of elements) {", - " if (objectSet.has(element)) {", - " // The top element is likely to be removed from the stack.", - " // Make its removal O(1)", - " if (element === stack[stack.length - 1]) {", - " stack.pop();", - " }", - " else {", - " const index = stack.indexOf(element);", - " if (index >= 0) {", - " stack.splice(index, 1);", - " }", - " }", - " objectSet.delete(element);", - " }", + " const isAdded = stack.remove(element);", "}" ], "parameterObjects": "Object", @@ -588,13 +729,7 @@ "const behaviorName = eventsFunctionContext.getBehaviorName(\"Behavior\");", "const behavior = object.getBehavior(behaviorName);", "", - "/** @type {gdjs.RuntimeObject[]} */", - "const stack = behavior.objectStack;", - "/** @type {Map */", - "const objectSet = behavior.objectSet;", - "", - "stack.length = 0;", - "objectSet.clear();" + "behavior.objectStack.clear();" ], "parameterObjects": "Object", "useStrict": true, @@ -617,7 +752,7 @@ "objectGroups": [] }, { - "description": "Move the object from a stack into another.", + "description": "Move the objects from a stack into another.", "fullName": "Move into the stack", "functionType": "Action", "name": "MoveInto", @@ -629,38 +764,15 @@ "const object = objects[0];", "const behaviorName = eventsFunctionContext.getBehaviorName(\"Behavior\");", "const behavior = object.getBehavior(behaviorName);", - "const stacks = eventsFunctionContext.getObjects(\"Stack\");", - "const stackBehaviorName = eventsFunctionContext.getBehaviorName(\"StackBehavior\");", - "let insertHeight = eventsFunctionContext.getArgument(\"Height\");", + "const otherStacks = eventsFunctionContext.getObjects(\"Stack\");", + "const otherStackBehaviorName = eventsFunctionContext.getBehaviorName(\"StackBehavior\");", + "const insertHeight = eventsFunctionContext.getArgument(\"Height\");", "const lowerBound = Math.max(0, eventsFunctionContext.getArgument(\"LowerBound\"));", - "let upperBound = eventsFunctionContext.getArgument(\"UpperBound\");", + "const upperBound = eventsFunctionContext.getArgument(\"UpperBound\");", "", - "if (stacks && stacks.length > 0) {", - " /** @type {gdjs.RuntimeObject[]} */", - " const otherStack = stacks[0].getBehavior(stackBehaviorName).objectStack;", - " /** @type {Map */", - " const otherObjectSet = stacks[0].getBehavior(stackBehaviorName).objectSet;", - " /** @type {gdjs.RuntimeObject[]} */", - " const stack = behavior.objectStack;", - " /** @type {Map */", - " const objectSet = behavior.objectSet;", - " if (insertHeight < 0 || insertHeight > stack.length) {", - " console.error(`Tried to insert in the stack at ${insertHeight} where the stack is ${stack.length} height.`);", - " return;", - " }", - " upperBound = Math.min(upperBound, otherStack.length - 1);", - " for (let height = lowerBound; height <= upperBound; height++) {", - " const insertedElement = otherStack[height];", - " stack.splice(insertHeight, 0, insertedElement);", - " objectSet.add(insertedElement);", - " insertHeight++;", - " }", - " if (lowerBound <= upperBound) {", - " for (let height = lowerBound; height <= upperBound; height++) {", - " otherObjectSet.delete(otherStack[height]);", - " }", - " otherStack.splice(lowerBound, upperBound - lowerBound + 1);", - " }", + "for (const otherStack of otherStacks) {", + " const otherObjectStack = otherStack.getBehavior(otherStackBehaviorName);", + " behavior.objectStack.takeInto(insertHeight, otherObjectStack, lowerBound, upperBound);", "}" ], "parameterObjects": "Object", @@ -838,17 +950,7 @@ "const behaviorName = eventsFunctionContext.getBehaviorName(\"Behavior\");", "const behavior = object.getBehavior(behaviorName);", "", - "/** @type {gdjs.RuntimeObject[]} */", - "const stack = behavior.objectStack;", - "", - "// Fisher–Yates shuffle", - "for (let i = stack.length - 1; i >= 1; i--) {", - " // TODO use a seed", - " const j = Math.floor(Math.random() * (i + 1));", - " const swap = stack[i];", - " stack[i] = stack[j]", - " stack[j] = swap;", - "}" + "behavior.objectStack.shuffle();" ], "parameterObjects": "Object", "useStrict": true, @@ -884,9 +986,7 @@ "const behavior = objects[0].getBehavior(behaviorName);", "const elements = eventsFunctionContext.getObjects(\"Elements\");", "", - "/** @type {gdjs.RuntimeObject[]} */", - "const stack = behavior.objectStack;", - "eventsFunctionContext.returnValue = stack.indexOf(elements[0]);" + "eventsFunctionContext.returnValue = behavior.objectStack.heightOf(elements[0]);" ], "parameterObjects": "Object", "useStrict": true, @@ -929,9 +1029,7 @@ "const behaviorName = eventsFunctionContext.getBehaviorName(\"Behavior\");", "const behavior = objects[0].getBehavior(behaviorName);", "", - "/** @type {gdjs.RuntimeObject[]} */", - "const stack = behavior.objectStack;", - "eventsFunctionContext.returnValue = stack.length;", + "eventsFunctionContext.returnValue = behavior.objectStack.height();", "" ], "parameterObjects": "Object", @@ -966,19 +1064,31 @@ "sentence": "_PARAM0_ has _PARAM2_ objects in its stack", "events": [ { - "type": "BuiltinCommonInstructions::JsCode", - "inlineCode": [ - "const behaviorName = eventsFunctionContext.getBehaviorName(\"Behavior\");", - "const behavior = objects[0].getBehavior(behaviorName);", - "const height = eventsFunctionContext.getArgument(\"Height\");", - "", - "/** @type {gdjs.RuntimeObject[]} */", - "const stack = behavior.objectStack;", - "eventsFunctionContext.returnValue = stack.length === height;" + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "ObjectStack::ObjectStack::Height" + }, + "parameters": [ + "Object", + "Behavior", + "=", + "Height", + "" + ] + } ], - "parameterObjects": "Object", - "useStrict": true, - "eventsSheetExpanded": true + "actions": [ + { + "type": { + "value": "SetReturnBoolean" + }, + "parameters": [ + "True" + ] + } + ] } ], "parameters": [ @@ -1015,9 +1125,7 @@ "const behaviorName = eventsFunctionContext.getBehaviorName(\"Behavior\");", "const behavior = object.getBehavior(behaviorName);", "", - "/** @type {gdjs.RuntimeObject[]} */", - "const stack = behavior.objectStack;", - "eventsFunctionContext.returnValue = stack.length === 0;" + "eventsFunctionContext.returnValue = behavior.objectStack.isEmpty();" ], "parameterObjects": "Object", "useStrict": true, diff --git a/scripts/lib/ExtensionsValidatorExceptions.js b/scripts/lib/ExtensionsValidatorExceptions.js index a8154089..5b0c77db 100644 --- a/scripts/lib/ExtensionsValidatorExceptions.js +++ b/scripts/lib/ExtensionsValidatorExceptions.js @@ -305,8 +305,7 @@ const extensionsAllowedProperties = { ], gdjsEvtToolsAllowedProperties: ['object'], runtimeSceneAllowedProperties: [ - '__allObjectStacks', - '__objectStacks_allUsedObjects', + '_objectStackExtension', ], javaScriptObjectAllowedProperties: [], }, From 02de848cce06ec59c937c0579a8635075341770b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davy=20H=C3=A9lard?= Date: Sat, 25 Nov 2023 21:31:21 +0100 Subject: [PATCH 2/7] Typo --- extensions/reviewed/ObjectStack.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/reviewed/ObjectStack.json b/extensions/reviewed/ObjectStack.json index 3e03a8af..5e5c54af 100644 --- a/extensions/reviewed/ObjectStack.json +++ b/extensions/reviewed/ObjectStack.json @@ -582,7 +582,7 @@ "for (const element of elements) {", " const isAdded = stack.addOnTop(element);", " if (isAdded) {", - " runtimeScene.__objectStacks_allUsedObjects.add(object);", + " runtimeScene._objectStackExtension.allUsedObjects.add(object);", " }", "}" ], @@ -636,7 +636,7 @@ "for (const element of elements) {", " const isAdded = stack.insert(element, height);", " if (isAdded) {", - " runtimeScene.__objectStacks_allUsedObjects.add(object);", + " runtimeScene._objectStackExtension.allUsedObjects.add(object);", " }", "}" ], From 624cc6edc0f9eccaaad17f013f831b29c7f5df99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davy=20H=C3=A9lard?= Date: Sat, 25 Nov 2023 21:35:22 +0100 Subject: [PATCH 3/7] Fix JS usage declaration. --- extensions/reviewed/ObjectStack.json | 9 +++++---- scripts/lib/ExtensionsValidatorExceptions.js | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/extensions/reviewed/ObjectStack.json b/extensions/reviewed/ObjectStack.json index 5e5c54af..3a0ddce1 100644 --- a/extensions/reviewed/ObjectStack.json +++ b/extensions/reviewed/ObjectStack.json @@ -84,11 +84,12 @@ " * @param {number} height", " */", " insert(object, height) {", - " if (!this.objectSet.has(object)) {", - " this.stack.splice(height, 0, object);", - " this.objectSet.add(object);", - " runtimeScene.__objectStacks_allUsedObjects.add(object);", + " if (this.objectSet.has(object)) {", + " return false;", " }", + " this.stack.splice(height, 0, object);", + " this.objectSet.add(object);", + " return true;", " }", "", " /**", diff --git a/scripts/lib/ExtensionsValidatorExceptions.js b/scripts/lib/ExtensionsValidatorExceptions.js index 5b0c77db..19412131 100644 --- a/scripts/lib/ExtensionsValidatorExceptions.js +++ b/scripts/lib/ExtensionsValidatorExceptions.js @@ -300,6 +300,7 @@ const extensionsAllowedProperties = { }, ObjectStack: { gdjsAllowedProperties: [ + '_objectStackExtension', 'registerObjectDeletedFromSceneCallback', 'RuntimeObject', ], From b576c456caacccd34869949da15217046d4b0147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davy=20H=C3=A9lard?= Date: Sat, 25 Nov 2023 21:46:39 +0100 Subject: [PATCH 4/7] Format. --- scripts/lib/ExtensionsValidatorExceptions.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/lib/ExtensionsValidatorExceptions.js b/scripts/lib/ExtensionsValidatorExceptions.js index 19412131..a82171dd 100644 --- a/scripts/lib/ExtensionsValidatorExceptions.js +++ b/scripts/lib/ExtensionsValidatorExceptions.js @@ -305,9 +305,7 @@ const extensionsAllowedProperties = { 'RuntimeObject', ], gdjsEvtToolsAllowedProperties: ['object'], - runtimeSceneAllowedProperties: [ - '_objectStackExtension', - ], + runtimeSceneAllowedProperties: ['_objectStackExtension'], javaScriptObjectAllowedProperties: [], }, ParticleEmitter3D: { From a7a25d730f951a15c6cfd021b0e42b0ed1a12a56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davy=20H=C3=A9lard?= Date: Sun, 26 Nov 2023 17:14:43 +0100 Subject: [PATCH 5/7] Fix some syntax errors. --- extensions/reviewed/ObjectStack.json | 44 +++++++++++++--------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/extensions/reviewed/ObjectStack.json b/extensions/reviewed/ObjectStack.json index 3a0ddce1..49ca920c 100644 --- a/extensions/reviewed/ObjectStack.json +++ b/extensions/reviewed/ObjectStack.json @@ -99,7 +99,7 @@ " if (this.objectSet.has(object)) {", " // The top element is likely to be removed from the stack.", " // Make its removal O(1)", - " if (object === this.stack[stack.length - 1]) {", + " if (object === this.stack[this.stack.length - 1]) {", " this.stack.pop();", " }", " else {", @@ -119,26 +119,23 @@ "", " /**", " * @param {number} insertHeight", - " * @param {ObjectStack} otherObjectStack", + " * @param {ObjectStack} other", " * @param {number} lowerBound", " * @param {number} upperBound", " */", - " takeInto(insertHeight, otherObjectStack, lowerBound, upperBound) {", - " const otherStack = otherObjectStack.stack;", - " const otherObjectSet = otherObjectStack.objectSet;", - "", - " upperBound = Math.min(upperBound, otherStack.length - 1);", + " takeInto(insertHeight, other, lowerBound, upperBound) {", + " upperBound = Math.min(upperBound, other.stack.length - 1);", " for (let height = lowerBound; height <= upperBound; height++) {", - " const insertedObject = otherStack[height];", + " const insertedObject = other.stack[height];", " this.stack.splice(insertHeight, 0, insertedObject);", - " objectSet.add(insertedObject);", + " this.objectSet.add(insertedObject);", " insertHeight++;", " }", " if (lowerBound <= upperBound) {", " for (let height = lowerBound; height <= upperBound; height++) {", - " otherObjectSet.delete(otherStack[height]);", + " other.objectSet.delete(other.stack[height]);", " }", - " otherStack.splice(lowerBound, upperBound - lowerBound + 1);", + " other.stack.splice(lowerBound, upperBound - lowerBound + 1);", " }", " }", "", @@ -174,9 +171,9 @@ " * @param {number} upperBound", " */", " containsBetween(object, lowerBound, upperBound) {", - " upperBound = Math.min(upperBound, stack.length - 1);", + " upperBound = Math.min(upperBound, this.stack.length - 1);", " for (let i = lowerBound; i <= upperBound; i++) {", - " if (stack[i] === element) {", + " if (this.stack[i] === object) {", " return true;", " }", " }", @@ -188,21 +185,21 @@ " * @param {number} height", " */", " containsAt(object, height) {", - " return stack[height] === element;", + " return this.stack[height] === object;", " }", "", " /**", " * @param {gdjs.RuntimeObject} object", " */", " hasOnTop(object) {", - " return stack.length > 0 && stack[stack.length - 1] === object;", + " return this.stack.length > 0 && this.stack[this.stack.length - 1] === object;", " }", "", " /**", " * @param {gdjs.RuntimeObject} object", " */", " contains(object) {", - " return objectSet.has(object);", + " return this.objectSet.has(object);", " }", "}", "", @@ -489,10 +486,10 @@ "", "if (!runtimeScene._objectStackExtension) {", " runtimeScene._objectStackExtension = {", - " allObjectStacks = new Set(),", + " allObjectStacks: new Set(),", " // Its only use is to have a O(1) check for", " // deleted objects that have never been in a stack.", - " allUsedObjects = new Set()", + " allUsedObjects: new Set()", " };", " // Remove from deleted objects from stacks.", " gdjs.registerObjectDeletedFromSceneCallback(function (runtimeScene, obj) {", @@ -626,14 +623,15 @@ "const behaviorName = eventsFunctionContext.getBehaviorName(\"Behavior\");", "const behavior = object.getBehavior(behaviorName);", "const elements = eventsFunctionContext.getObjects(\"Elements\");", - "const height = eventsFunctionContext.getArgument(\"Height\");", + "let height = eventsFunctionContext.getArgument(\"Height\");", + "", + "const stack = behavior.objectStack;", "", - "if (height < 0 || height > stack.length) {", + "if (height < 0 || height > stack.height()) {", " console.error(`Tried to insert in the stack at ${height} where the stack is ${stack.length} height.`);", - " return;", + " height = Math.min(0, Math.max(stack.height(), height))", "}", "", - "const stack = behavior.objectStack;", "for (const element of elements) {", " const isAdded = stack.insert(element, height);", " if (isAdded) {", @@ -772,7 +770,7 @@ "const upperBound = eventsFunctionContext.getArgument(\"UpperBound\");", "", "for (const otherStack of otherStacks) {", - " const otherObjectStack = otherStack.getBehavior(otherStackBehaviorName);", + " const otherObjectStack = otherStack.getBehavior(otherStackBehaviorName).objectStack;", " behavior.objectStack.takeInto(insertHeight, otherObjectStack, lowerBound, upperBound);", "}" ], From d08bc924e00f3bd9ac2ba4fb7b93fc3bf7245def Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davy=20H=C3=A9lard?= Date: Sun, 26 Nov 2023 18:11:09 +0100 Subject: [PATCH 6/7] Typo --- extensions/reviewed/ObjectStack.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/reviewed/ObjectStack.json b/extensions/reviewed/ObjectStack.json index 49ca920c..12b4d10a 100644 --- a/extensions/reviewed/ObjectStack.json +++ b/extensions/reviewed/ObjectStack.json @@ -139,9 +139,9 @@ " }", " }", "", - " suffle() {", + " shuffle() {", " // Fisher–Yates shuffle", - " for (let i = stack.length - 1; i >= 1; i--) {", + " for (let i = this.stack.length - 1; i >= 1; i--) {", " // TODO use a seed", " const j = Math.floor(Math.random() * (i + 1));", " const swap = this.stack[i];", From 7f0585df76452494e545f2c211e6666226370076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davy=20H=C3=A9lard?= Date: Sun, 26 Nov 2023 22:12:09 +0100 Subject: [PATCH 7/7] Fix object deletion handling. --- extensions/reviewed/ObjectStack.json | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/extensions/reviewed/ObjectStack.json b/extensions/reviewed/ObjectStack.json index 12b4d10a..54e4fc4b 100644 --- a/extensions/reviewed/ObjectStack.json +++ b/extensions/reviewed/ObjectStack.json @@ -55,6 +55,20 @@ " return;", "}", "", + "// Remove from deleted objects from stacks.", + "gdjs.registerObjectDeletedFromSceneCallback(function (runtimeScene, obj) {", + " const extension = runtimeScene._objectStackExtension;", + " if (!extension) {", + " return;", + " }", + " if (extension.allUsedObjects.has(obj)) {", + " extension.allUsedObjects.delete(obj);", + " for (const objectStack of extension.allObjectStacks) {", + " objectStack.remove(obj);", + " }", + " }", + "});", + "", "class ObjectStack {", " /**", " * @type {Array}", @@ -491,18 +505,8 @@ " // deleted objects that have never been in a stack.", " allUsedObjects: new Set()", " };", - " // Remove from deleted objects from stacks.", - " gdjs.registerObjectDeletedFromSceneCallback(function (runtimeScene, obj) {", - " const extension = runtimeScene._objectStackExtension;", - " if (extension.allUsedObjects.has(obj)) {", - " extension.allUsedObjects.delete(obj);", - " for (const behavior of extension.allObjectStacks) {", - " behavior.objectStack.remove(obj);", - " }", - " }", - " });", "}", - "runtimeScene._objectStackExtension.allObjectStacks.add(behavior);", + "runtimeScene._objectStackExtension.allObjectStacks.add(behavior.objectStack);", "" ], "parameterObjects": "Object",