Files
GDevelop/GDevelop.js/__tests__/GDJSFunctionAsyncCodeGenerationIntegrationTests.js

3646 lines
123 KiB
JavaScript

const initializeGDevelopJs = require('../../Binaries/embuild/GDevelop.js/libGD.js');
const {
generateCompiledEventsForEventsFunction,
generateCompiledEventsFromSerializedEvents,
generateCompiledEventsForSerializedEventsBasedExtension,
} = require('../TestUtils/CodeGenerationHelpers.js');
const { makeMinimalGDJSMock } = require('../TestUtils/GDJSMocks');
const { makeTestExtensions } = require('../TestUtils/TestExtensions');
describe('libGD.js - GDJS Async Code Generation integration tests', function () {
let gd = null;
beforeAll(async () => {
gd = await initializeGDevelopJs();
makeTestExtensions(gd);
});
describe('Basics', () => {
it('generates a working function with asynchronous actions', function () {
const eventsSerializerElement = gd.Serializer.fromJSON(
JSON.stringify([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [],
actions: [
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'ModVarScene' },
parameters: ['SuccessVariable', '+', '1'],
},
],
},
])
);
const runCompiledEvents = generateCompiledEventsFromSerializedEvents(
gd,
eventsSerializerElement
);
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
runCompiledEvents(gdjs, runtimeScene, []);
expect(runtimeScene.getVariables().has('SuccessVariable')).toBe(false);
// Process the tasks (but the task is not finished yet).
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
expect(runtimeScene.getVariables().has('SuccessVariable')).toBe(false);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
expect(
runtimeScene.getVariables().get('SuccessVariable').getAsNumber()
).toBe(1);
});
it('generates a working function with an optionally asynchronous action, that is not set as async', function () {
const eventsSerializerElement = gd.Serializer.fromJSON(
JSON.stringify([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [],
actions: [
{
type: {
value: 'FakeOptionallyAsyncAction::DoOptionallyAsyncAction',
},
parameters: ['1.5'],
},
{
type: { value: 'ModVarScene' },
parameters: ['SuccessVariable', '+', '1'],
},
],
},
])
);
const runCompiledEvents = generateCompiledEventsFromSerializedEvents(
gd,
eventsSerializerElement
);
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
runCompiledEvents(gdjs, runtimeScene, []);
// Nothing is async, the actions are all executed.
expect(runtimeScene.getVariables().has('SuccessVariable')).toBe(true);
});
it('generates a working function with an optionally asynchronous action, that is set as async', function () {
const eventsSerializerElement = gd.Serializer.fromJSON(
JSON.stringify([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [],
actions: [
{
type: {
value: 'FakeOptionallyAsyncAction::DoOptionallyAsyncAction',
await: true,
},
parameters: ['1.5'],
},
{
type: { value: 'ModVarScene' },
parameters: ['SuccessVariable', '+', '1'],
},
],
},
])
);
const runCompiledEvents = generateCompiledEventsFromSerializedEvents(
gd,
eventsSerializerElement
);
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
runCompiledEvents(gdjs, runtimeScene, []);
expect(runtimeScene.getVariables().has('SuccessVariable')).toBe(false);
// Process the tasks (but the task is not finished yet).
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
expect(runtimeScene.getVariables().has('SuccessVariable')).toBe(false);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
expect(
runtimeScene.getVariables().get('SuccessVariable').getAsNumber()
).toBe(1);
});
it('generates a working function with two asynchronous actions', function () {
// Create events using the Trigger Once condition.
const eventsSerializerElement = gd.Serializer.fromJSON(
JSON.stringify([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [],
actions: [
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'ModVarScene' },
parameters: ['SuccessVariable', '+', '1'],
},
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'ModVarScene' },
parameters: ['SuccessVariable', '+', '2'],
},
],
},
])
);
const runCompiledEvents = generateCompiledEventsFromSerializedEvents(
gd,
eventsSerializerElement
);
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
runCompiledEvents(gdjs, runtimeScene, []);
expect(runtimeScene.getVariables().has('SuccessVariable')).toBe(false);
// Process the tasks (but the task is not finished yet).
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
expect(runtimeScene.getVariables().has('SuccessVariable')).toBe(false);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
expect(
runtimeScene.getVariables().get('SuccessVariable').getAsNumber()
).toBe(1);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
expect(
runtimeScene.getVariables().get('SuccessVariable').getAsNumber()
).toBe(3);
});
it('generates a working function with asynchronous actions referring to the function arguments', function () {
const eventsSerializerElement = gd.Serializer.fromJSON(
JSON.stringify([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [],
actions: [
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'ModVarScene' },
parameters: [
'SuccessVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
],
},
])
);
const project = new gd.ProjectHelper.createNewGDJSProject();
const eventsFunction = new gd.EventsFunction();
eventsFunction
.getEvents()
.unserializeFrom(project, eventsSerializerElement);
eventsFunction
.getParameters()
.insertNewParameter('IncreaseValue', 0)
.setType('number');
const runCompiledEvents = generateCompiledEventsForEventsFunction(
gd,
project,
eventsFunction
);
eventsFunction.delete();
project.delete();
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
runCompiledEvents(gdjs, runtimeScene, [5]);
expect(runtimeScene.getVariables().has('SuccessVariable')).toBe(false);
// Process the tasks (but the task is not finished yet).
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
expect(runtimeScene.getVariables().has('SuccessVariable')).toBe(false);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
expect(
runtimeScene.getVariables().get('SuccessVariable').getAsNumber()
).toBe(5);
});
});
describe('With objects', () => {
test('one asynchronous action', function () {
const eventsSerializerElement = gd.Serializer.fromJSON(
JSON.stringify([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [],
actions: [
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
],
},
])
);
const runCompiledEvents = generateCompiledEventsFromSerializedEvents(
gd,
eventsSerializerElement,
{
parameterTypes: { IncreaseValue: 'number', MyParamObject: 'object' },
}
);
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const myObjectA = runtimeScene.createObject('MyObjectA');
const myObjectALists = gdjs.Hashtable.newFrom({ MyObjectA: [myObjectA] });
runCompiledEvents(gdjs, runtimeScene, [5, myObjectALists]);
expect(myObjectA.getVariables().has('TestVariable')).toBe(true);
expect(myObjectA.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
// Process the tasks (but the task is not finished yet).
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
expect(myObjectA.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
expect(myObjectA.getVariables().get('TestVariable').getAsNumber()).toBe(
10
);
});
test('two asynchronous actions and a condition before the async actions filtering objects', function () {
const eventsSerializerElement = gd.Serializer.fromJSON(
JSON.stringify([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [
{
type: { value: 'VarObjet' },
parameters: ['MyParamObject', 'TestVariable', '=', '1'],
},
],
actions: [
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
],
events: [
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [],
actions: [
{
type: {
value: 'Wait',
},
parameters: ['1.5'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
],
},
],
},
])
);
const project = new gd.ProjectHelper.createNewGDJSProject();
const eventsFunction = new gd.EventsFunction();
eventsFunction
.getEvents()
.unserializeFrom(project, eventsSerializerElement);
eventsFunction
.getParameters()
.insertNewParameter('IncreaseValue', 0)
.setType('number');
eventsFunction
.getParameters()
.insertNewParameter('MyParamObject', 1)
.setType('object');
const runCompiledEvents = generateCompiledEventsForEventsFunction(
gd,
project,
eventsFunction
);
eventsFunction.delete();
project.delete();
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const myObjectA1 = runtimeScene.createObject('MyObjectA');
const myObjectA2 = runtimeScene.createObject('MyObjectA');
const myObjectALists = gdjs.Hashtable.newFrom({
MyObjectA: [myObjectA1, myObjectA2],
});
myObjectA2.getVariables().get('TestVariable').setNumber(1);
runCompiledEvents(gdjs, runtimeScene, [5, myObjectALists]);
// Initial state is unchanged because the first wait task is not done.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectA2.getVariables().has('TestVariable')).toBe(true);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
1
);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Initial state is still unchanged because the condition ran but the second wait task
// is not done.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectA2.getVariables().has('TestVariable')).toBe(true);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
1
);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Only the "myObjectA2" instance was modified by the action.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectA2.getVariables().has('TestVariable')).toBe(true);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
6
);
});
test('two asynchronous actions and a condition in between filtering objects', function () {
const eventsSerializerElement = gd.Serializer.fromJSON(
JSON.stringify([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [],
actions: [
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
],
events: [
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [
{
type: { value: 'VarObjet' },
parameters: ['MyParamObject', 'TestVariable', '=', '1'],
},
],
actions: [
{
type: {
value: 'Wait',
},
parameters: ['1.5'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
],
},
],
},
])
);
const project = new gd.ProjectHelper.createNewGDJSProject();
const eventsFunction = new gd.EventsFunction();
eventsFunction
.getEvents()
.unserializeFrom(project, eventsSerializerElement);
eventsFunction
.getParameters()
.insertNewParameter('IncreaseValue', 0)
.setType('number');
eventsFunction
.getParameters()
.insertNewParameter('MyParamObject', 1)
.setType('object');
const runCompiledEvents = generateCompiledEventsForEventsFunction(
gd,
project,
eventsFunction
);
eventsFunction.delete();
project.delete();
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const myObjectA1 = runtimeScene.createObject('MyObjectA');
const myObjectA2 = runtimeScene.createObject('MyObjectA');
const myObjectALists = gdjs.Hashtable.newFrom({
MyObjectA: [myObjectA1, myObjectA2],
});
myObjectA2.getVariables().get('TestVariable').setNumber(1);
runCompiledEvents(gdjs, runtimeScene, [5, myObjectALists]);
// Initial state is unchanged because the first wait task is not done.
expect(myObjectA1.getVariables().has('TestVariable')).toBe(false);
expect(myObjectA2.getVariables().has('TestVariable')).toBe(true);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
1
);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Initial state is still unchanged because the condition ran but the second wait task
// is not done.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectA2.getVariables().has('TestVariable')).toBe(true);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
1
);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Only the "myObjectA2" instance was modified by the action.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectA2.getVariables().has('TestVariable')).toBe(true);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
6
);
});
test('two asynchronous actions and conditions filtering objects in sub events after a filtering outside the async context', function () {
const eventsSerializerElement = gd.Serializer.fromJSON(
JSON.stringify([
{
type: 'BuiltinCommonInstructions::Standard',
// Do a first filtering.
conditions: [
{
type: { value: 'VarObjet' },
parameters: ['MyParamObject', 'TestVariable', '>=', '1'],
},
],
actions: [
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
],
events: [
{
type: 'BuiltinCommonInstructions::Standard',
// Filter with the more precise condition first.
conditions: [
{
type: { value: 'VarObjet' },
parameters: ['MyParamObject', 'TestVariable', '>=', '3'],
},
],
actions: [],
events: [
{
type: 'BuiltinCommonInstructions::Standard',
// Filter with a less precise condition then.
conditions: [
{
type: { value: 'VarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'>=',
'2',
],
},
],
actions: [
{
type: {
value: 'Wait',
},
parameters: ['1.5'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
],
},
],
},
],
},
])
);
const project = new gd.ProjectHelper.createNewGDJSProject();
const eventsFunction = new gd.EventsFunction();
eventsFunction
.getEvents()
.unserializeFrom(project, eventsSerializerElement);
eventsFunction
.getParameters()
.insertNewParameter('IncreaseValue', 0)
.setType('number');
eventsFunction
.getParameters()
.insertNewParameter('MyParamObject', 1)
.setType('object');
const runCompiledEvents = generateCompiledEventsForEventsFunction(
gd,
project,
eventsFunction
);
eventsFunction.delete();
project.delete();
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const myObjectA1 = runtimeScene.createObject('MyObjectA');
const myObjectA2 = runtimeScene.createObject('MyObjectA');
const myObjectA3 = runtimeScene.createObject('MyObjectA');
const myObjectA4 = runtimeScene.createObject('MyObjectA');
const myObjectALists = gdjs.Hashtable.newFrom({
MyObjectA: [myObjectA1, myObjectA2, myObjectA3, myObjectA4],
});
myObjectA2.getVariables().get('TestVariable').setNumber(1);
myObjectA3.getVariables().get('TestVariable').setNumber(2);
myObjectA4.getVariables().get('TestVariable').setNumber(3);
runCompiledEvents(gdjs, runtimeScene, [5, myObjectALists]);
// Initial state is unchanged because the first wait task is not done.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectA2.getVariables().has('TestVariable')).toBe(true);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
1
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
2
);
expect(myObjectA4.getVariables().get('TestVariable').getAsNumber()).toBe(
3
);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Initial state is still unchanged because the conditions ran but the second wait task
// is not done.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectA2.getVariables().has('TestVariable')).toBe(true);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
1
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
2
);
expect(myObjectA4.getVariables().get('TestVariable').getAsNumber()).toBe(
3
);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Only the "myObjectA3" instance was modified by the action.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectA2.getVariables().has('TestVariable')).toBe(true);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
1
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
2
);
expect(myObjectA4.getVariables().get('TestVariable').getAsNumber()).toBe(
3 + 5
);
});
test('two asynchronous actions and conditions filtering objects in sub events after a filtering outside the async context, with a third condition having its result discarded', function () {
const eventsSerializerElement = gd.Serializer.fromJSON(
JSON.stringify([
{
type: 'BuiltinCommonInstructions::Standard',
// Do a first filtering.
conditions: [
{
type: { value: 'VarObjet' },
parameters: ['MyParamObject', 'TestVariable', '>=', '1'],
},
],
actions: [
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
],
events: [
{
type: 'BuiltinCommonInstructions::Standard',
// Filter with the more precise condition first.
conditions: [
{
type: { value: 'VarObjet' },
parameters: ['MyParamObject', 'TestVariable', '>=', '3'],
},
],
actions: [],
events: [
{
type: 'BuiltinCommonInstructions::Standard',
// Filter with a less precise condition then.
conditions: [
{
type: { value: 'VarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'>=',
'2',
],
},
],
actions: [
{
type: {
value: 'Wait',
},
parameters: ['1.5'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
],
},
// Add an event to prevent optimisation (reuse of the same objects list)
// in the previous event.
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [
{
type: { value: 'VarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'>=',
'0',
],
},
],
actions: [],
},
],
},
],
},
])
);
const project = new gd.ProjectHelper.createNewGDJSProject();
const eventsFunction = new gd.EventsFunction();
eventsFunction
.getEvents()
.unserializeFrom(project, eventsSerializerElement);
eventsFunction
.getParameters()
.insertNewParameter('IncreaseValue', 0)
.setType('number');
eventsFunction
.getParameters()
.insertNewParameter('MyParamObject', 1)
.setType('object');
const runCompiledEvents = generateCompiledEventsForEventsFunction(
gd,
project,
eventsFunction
);
eventsFunction.delete();
project.delete();
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const myObjectA1 = runtimeScene.createObject('MyObjectA');
const myObjectA2 = runtimeScene.createObject('MyObjectA');
const myObjectA3 = runtimeScene.createObject('MyObjectA');
const myObjectA4 = runtimeScene.createObject('MyObjectA');
const myObjectALists = gdjs.Hashtable.newFrom({
MyObjectA: [myObjectA1, myObjectA2, myObjectA3, myObjectA4],
});
myObjectA2.getVariables().get('TestVariable').setNumber(1);
myObjectA3.getVariables().get('TestVariable').setNumber(2);
myObjectA4.getVariables().get('TestVariable').setNumber(3);
runCompiledEvents(gdjs, runtimeScene, [5, myObjectALists]);
// Initial state is unchanged because the first wait task is not done.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectA2.getVariables().has('TestVariable')).toBe(true);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
1
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
2
);
expect(myObjectA4.getVariables().get('TestVariable').getAsNumber()).toBe(
3
);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Initial state is still unchanged because the conditions ran but the second wait task
// is not done.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectA2.getVariables().has('TestVariable')).toBe(true);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
1
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
2
);
expect(myObjectA4.getVariables().get('TestVariable').getAsNumber()).toBe(
3
);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Only the "myObjectA3" instance was modified by the action.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectA2.getVariables().has('TestVariable')).toBe(true);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
1
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
2
);
expect(myObjectA4.getVariables().get('TestVariable').getAsNumber()).toBe(
3 + 5
);
});
test('two asynchronous actions and two conditions in different sub-events in between filtering objects, with a third condition having its result discarded', function () {
const eventsSerializerElement = gd.Serializer.fromJSON(
JSON.stringify([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [],
actions: [
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
],
events: [
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [
{
type: { value: 'VarObjet' },
parameters: ['MyParamObject', 'TestVariable', '>=', '2'],
},
],
actions: [],
events: [
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [
{
type: { value: 'VarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'>=',
'1',
],
},
],
actions: [
{
type: {
value: 'Wait',
},
parameters: ['1.5'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
],
},
// Add an event to prevent optimisation (reuse of the same objects list)
// in the previous event.
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [
{
type: { value: 'VarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'>=',
'0',
],
},
],
actions: [],
},
],
},
],
},
])
);
const project = new gd.ProjectHelper.createNewGDJSProject();
const eventsFunction = new gd.EventsFunction();
eventsFunction
.getEvents()
.unserializeFrom(project, eventsSerializerElement);
eventsFunction
.getParameters()
.insertNewParameter('IncreaseValue', 0)
.setType('number');
eventsFunction
.getParameters()
.insertNewParameter('MyParamObject', 1)
.setType('object');
const runCompiledEvents = generateCompiledEventsForEventsFunction(
gd,
project,
eventsFunction
);
eventsFunction.delete();
project.delete();
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const myObjectA1 = runtimeScene.createObject('MyObjectA');
const myObjectA2 = runtimeScene.createObject('MyObjectA');
const myObjectA3 = runtimeScene.createObject('MyObjectA');
const myObjectALists = gdjs.Hashtable.newFrom({
MyObjectA: [myObjectA1, myObjectA2, myObjectA3],
});
myObjectA2.getVariables().get('TestVariable').setNumber(1);
myObjectA3.getVariables().get('TestVariable').setNumber(2);
runCompiledEvents(gdjs, runtimeScene, [5, myObjectALists]);
// Initial state is unchanged because the first wait task is not done.
expect(myObjectA1.getVariables().has('TestVariable')).toBe(false);
expect(myObjectA2.getVariables().has('TestVariable')).toBe(true);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
1
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
2
);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Initial state is still unchanged because the conditions ran but the second wait task
// is not done.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectA2.getVariables().has('TestVariable')).toBe(true);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
1
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
2
);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Only the "myObjectA3" instance was modified by the action.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectA2.getVariables().has('TestVariable')).toBe(true);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
1
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
2 + 5
);
});
});
describe('With objects, object groups and deleted/created objects', () => {
test('asynchronous actions and deleted objects', function () {
const eventsSerializerElement = gd.Serializer.fromJSON(
JSON.stringify([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [],
actions: [
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
],
},
])
);
const project = new gd.ProjectHelper.createNewGDJSProject();
const eventsFunction = new gd.EventsFunction();
eventsFunction
.getEvents()
.unserializeFrom(project, eventsSerializerElement);
eventsFunction
.getParameters()
.insertNewParameter('IncreaseValue', 0)
.setType('number');
eventsFunction
.getParameters()
.insertNewParameter('MyParamObject', 1)
.setType('object');
const runCompiledEvents = generateCompiledEventsForEventsFunction(
gd,
project,
eventsFunction
);
eventsFunction.delete();
project.delete();
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const myObjectA1 = runtimeScene.createObject('MyObjectA');
const myObjectA2 = runtimeScene.createObject('MyObjectA');
const myObjectA3 = runtimeScene.createObject('MyObjectA');
const myObjectB1 = runtimeScene.createObject('MyObjectB');
const myObjectB2 = runtimeScene.createObject('MyObjectB');
const myObjectsLists = gdjs.Hashtable.newFrom({
MyObjectA: [myObjectA1, myObjectA2, myObjectA3],
MyObjectB: [myObjectB1, myObjectB2],
});
runCompiledEvents(gdjs, runtimeScene, [5, myObjectsLists]);
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectB1.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectB2.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
// Delete an object while the task is running.
myObjectA1.deleteFromScene();
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
10
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
10
);
expect(myObjectB1.getVariables().get('TestVariable').getAsNumber()).toBe(
10
);
expect(myObjectB2.getVariables().get('TestVariable').getAsNumber()).toBe(
10
);
// Delete other objects while the task is running.
myObjectA3.deleteFromScene();
myObjectB1.deleteFromScene();
// Process the tasks again (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Check only non deleted objects are updated by the final action.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
15
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
10
);
expect(myObjectB1.getVariables().get('TestVariable').getAsNumber()).toBe(
10
);
expect(myObjectB2.getVariables().get('TestVariable').getAsNumber()).toBe(
15
);
});
test('two asynchronous actions immediately following each other, and deleted objects', function () {
const eventsSerializerElement = gd.Serializer.fromJSON(
JSON.stringify([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [],
actions: [
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
],
},
])
);
const project = new gd.ProjectHelper.createNewGDJSProject();
const eventsFunction = new gd.EventsFunction();
eventsFunction
.getEvents()
.unserializeFrom(project, eventsSerializerElement);
eventsFunction
.getParameters()
.insertNewParameter('IncreaseValue', 0)
.setType('number');
eventsFunction
.getParameters()
.insertNewParameter('MyParamObject', 1)
.setType('object');
const runCompiledEvents = generateCompiledEventsForEventsFunction(
gd,
project,
eventsFunction
);
eventsFunction.delete();
project.delete();
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const myObjectA1 = runtimeScene.createObject('MyObjectA');
const myObjectA2 = runtimeScene.createObject('MyObjectA');
const myObjectA3 = runtimeScene.createObject('MyObjectA');
const myObjectB1 = runtimeScene.createObject('MyObjectB');
const myObjectB2 = runtimeScene.createObject('MyObjectB');
const myObjectsLists = gdjs.Hashtable.newFrom({
MyObjectA: [myObjectA1, myObjectA2, myObjectA3],
MyObjectB: [myObjectB1, myObjectB2],
});
runCompiledEvents(gdjs, runtimeScene, [5, myObjectsLists]);
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectB1.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectB2.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
// Delete an object while the task is running.
myObjectA1.deleteFromScene();
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Nothing is changed (no action run).
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectB1.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectB2.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
// Delete other objects while the task is running.
myObjectA3.deleteFromScene();
myObjectB1.deleteFromScene();
// Process the tasks again (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Check only non deleted objects are updated by the final action.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
10
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectB1.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectB2.getVariables().get('TestVariable').getAsNumber()).toBe(
10
);
});
test('asynchronous actions and object groups', function () {
const eventsSerializerElement = gd.Serializer.fromJSON(
JSON.stringify([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [
{
type: { value: 'VarObjet' },
parameters: ['MyGroup', 'TestVariable', '=', '1'],
},
],
actions: [
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject1',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject2',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyGroup',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
],
},
])
);
const project = new gd.ProjectHelper.createNewGDJSProject();
const eventsFunction = new gd.EventsFunction();
eventsFunction
.getEvents()
.unserializeFrom(project, eventsSerializerElement);
eventsFunction
.getParameters()
.addNewParameter('IncreaseValue')
.setType('number');
eventsFunction
.getParameters()
.addNewParameter('MyParamObject1')
.setType('object');
eventsFunction
.getParameters()
.addNewParameter('MyParamObject2')
.setType('object');
// Create a group that refers to both objects passed as parameters.
const myGroup = eventsFunction.getObjectGroups().insertNew('MyGroup', 0);
myGroup.addObject('MyParamObject1');
myGroup.addObject('MyParamObject2');
const runCompiledEvents = generateCompiledEventsForEventsFunction(
gd,
project,
eventsFunction
);
eventsFunction.delete();
project.delete();
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const myObjectA1 = runtimeScene.createObject('MyObjectA');
const myObjectA2 = runtimeScene.createObject('MyObjectA');
const myObjectA3 = runtimeScene.createObject('MyObjectA');
const myObjectB1 = runtimeScene.createObject('MyObjectB');
const myObjectB2 = runtimeScene.createObject('MyObjectB');
const myObjectALists = gdjs.Hashtable.newFrom({
MyObjectA: [myObjectA1, myObjectA2, myObjectA3],
});
const myObjectBLists = gdjs.Hashtable.newFrom({
MyObjectB: [myObjectB1, myObjectB2],
});
myObjectA2.getVariables().get('TestVariable').setNumber(1);
myObjectB2.getVariables().get('TestVariable').setNumber(1);
runCompiledEvents(gdjs, runtimeScene, [
5,
myObjectALists,
myObjectBLists,
]);
// Only objects passed to the "MyParamObject1" parameter have their variable increased.
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
1 + 5
);
expect(myObjectB2.getVariables().get('TestVariable').getAsNumber()).toBe(
1
);
// Object filtered in the initial condition are not updated.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectB1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Now, only objects passed to the "MyParamObject2" parameter have their variable increased.
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
1 + 5
);
expect(myObjectB2.getVariables().get('TestVariable').getAsNumber()).toBe(
1 + 5
);
// Object filtered in the initial condition are not updated.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectB1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
// Process the tasks again (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// All the remaining objects, referred by "MyGroup" in the function, should have their variable increased.
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
1 + 5 + 5
);
expect(myObjectB2.getVariables().get('TestVariable').getAsNumber()).toBe(
1 + 5 + 5
);
// Object filtered in the initial condition are not updated.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectB1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
});
test('asynchronous actions and deleted objects in object groups', function () {
const eventsSerializerElement = gd.Serializer.fromJSON(
JSON.stringify([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [],
actions: [
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject1',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject2',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyGroup',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
],
},
])
);
const project = new gd.ProjectHelper.createNewGDJSProject();
const eventsFunction = new gd.EventsFunction();
eventsFunction
.getEvents()
.unserializeFrom(project, eventsSerializerElement);
eventsFunction
.getParameters()
.addNewParameter('IncreaseValue')
.setType('number');
eventsFunction
.getParameters()
.addNewParameter('MyParamObject1')
.setType('object');
eventsFunction
.getParameters()
.addNewParameter('MyParamObject2')
.setType('object');
// Create a group that refers to both objects passed as parameters.
const myGroup = eventsFunction.getObjectGroups().insertNew('MyGroup', 0);
myGroup.addObject('MyParamObject1');
myGroup.addObject('MyParamObject2');
const runCompiledEvents = generateCompiledEventsForEventsFunction(
gd,
project,
eventsFunction
);
eventsFunction.delete();
project.delete();
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const myObjectA1 = runtimeScene.createObject('MyObjectA');
const myObjectA2 = runtimeScene.createObject('MyObjectA');
const myObjectA3 = runtimeScene.createObject('MyObjectA');
const myObjectB1 = runtimeScene.createObject('MyObjectB');
const myObjectB2 = runtimeScene.createObject('MyObjectB');
const myObjectALists = gdjs.Hashtable.newFrom({
MyObjectA: [myObjectA1, myObjectA2, myObjectA3],
});
const myObjectBLists = gdjs.Hashtable.newFrom({
MyObjectB: [myObjectB1, myObjectB2],
});
runCompiledEvents(gdjs, runtimeScene, [
5,
myObjectALists,
myObjectBLists,
]);
// Only objects passed to the "MyParamObject1" parameter have their variable increased.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectB1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectB2.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
// Delete an object while the task is running.
myObjectA1.deleteFromScene();
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Now, only objects passed to the "MyParamObject2" parameter have their variable increased.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectB1.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectB2.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
// Delete other objects while the task is running.
myObjectA3.deleteFromScene();
myObjectB1.deleteFromScene();
// Process the tasks again (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// All the remaining objects, referred by "MyGroup" in the function, should have their variable increased.
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
10
);
expect(myObjectB2.getVariables().get('TestVariable').getAsNumber()).toBe(
10
);
// Objects deleted, even if they are in "MyGroup", don't have their variable increased.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectB1.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
});
test('asynchronous actions and multiple created objects (that were not used before)', function () {
const eventsSerializerElement = gd.Serializer.fromJSON(
JSON.stringify([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [],
actions: [
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'Create' },
parameters: ['', 'MyParamObject', '0', '0', ''],
},
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'Create' },
parameters: ['', 'MyParamObject', '0', '0', ''],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
],
},
])
);
const project = new gd.ProjectHelper.createNewGDJSProject();
const eventsFunction = new gd.EventsFunction();
eventsFunction
.getEvents()
.unserializeFrom(project, eventsSerializerElement);
eventsFunction
.getParameters()
.insertNewParameter('IncreaseValue', 0)
.setType('number');
eventsFunction
.getParameters()
.insertNewParameter('MyParamObject', 1)
.setType('object');
const runCompiledEvents = generateCompiledEventsForEventsFunction(
gd,
project,
eventsFunction
);
eventsFunction.delete();
project.delete();
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const myObjectA1 = runtimeScene.createObject('MyObjectA');
const myObjectsLists = gdjs.Hashtable.newFrom({
MyObjectA: [],
});
runCompiledEvents(gdjs, runtimeScene, [5, myObjectsLists]);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Check an object was created.
expect(runtimeScene.getObjects('MyObjectA').length).toBe(2);
const myObjectA2 = runtimeScene.getObjects('MyObjectA')[1];
// Process the tasks again (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Check an object was created.
expect(runtimeScene.getObjects('MyObjectA').length).toBe(3);
const myObjectA3 = runtimeScene.getObjects('MyObjectA')[2];
// Check that both objects that have been created are updated by
// the last action (like if there was no wait action).
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
});
test('asynchronous actions and multiple created objects (that were not used before, with a usage after the first is created)', function () {
const eventsSerializerElement = gd.Serializer.fromJSON(
JSON.stringify([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [],
actions: [
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'Create' },
parameters: ['', 'MyParamObject', '0', '0', ''],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'Create' },
parameters: ['', 'MyParamObject', '0', '0', ''],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
],
},
])
);
const project = new gd.ProjectHelper.createNewGDJSProject();
const eventsFunction = new gd.EventsFunction();
eventsFunction
.getEvents()
.unserializeFrom(project, eventsSerializerElement);
eventsFunction
.getParameters()
.insertNewParameter('IncreaseValue', 0)
.setType('number');
eventsFunction
.getParameters()
.insertNewParameter('MyParamObject', 1)
.setType('object');
const runCompiledEvents = generateCompiledEventsForEventsFunction(
gd,
project,
eventsFunction
);
eventsFunction.delete();
project.delete();
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const myObjectA1 = runtimeScene.createObject('MyObjectA');
const myObjectsLists = gdjs.Hashtable.newFrom({
MyObjectA: [],
});
runCompiledEvents(gdjs, runtimeScene, [5, myObjectsLists]);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Check an object was created.
expect(runtimeScene.getObjects('MyObjectA').length).toBe(2);
const myObjectA2 = runtimeScene.getObjects('MyObjectA')[1];
// Check that the instance just created is updated by
// the action (like if there was no wait action).
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
// Process the tasks again (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Check an object was created.
expect(runtimeScene.getObjects('MyObjectA').length).toBe(3);
const myObjectA3 = runtimeScene.getObjects('MyObjectA')[2];
// Check that both objects that have been created are updated by
// the last action (like if there was no wait action).
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
5 + 5
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
});
test('asynchronous actions and multiple created objects (that were not used before, with a usage after an async action after the first is created)', function () {
const eventsSerializerElement = gd.Serializer.fromJSON(
JSON.stringify([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [],
actions: [
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'Create' },
parameters: ['', 'MyParamObject', '0', '0', ''],
},
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
{
type: { value: 'Create' },
parameters: ['', 'MyParamObject', '0', '0', ''],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
],
},
])
);
const project = new gd.ProjectHelper.createNewGDJSProject();
const eventsFunction = new gd.EventsFunction();
eventsFunction
.getEvents()
.unserializeFrom(project, eventsSerializerElement);
eventsFunction
.getParameters()
.insertNewParameter('IncreaseValue', 0)
.setType('number');
eventsFunction
.getParameters()
.insertNewParameter('MyParamObject', 1)
.setType('object');
const runCompiledEvents = generateCompiledEventsForEventsFunction(
gd,
project,
eventsFunction
);
eventsFunction.delete();
project.delete();
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const myObjectA1 = runtimeScene.createObject('MyObjectA');
const myObjectsLists = gdjs.Hashtable.newFrom({
MyObjectA: [],
});
runCompiledEvents(gdjs, runtimeScene, [5, myObjectsLists]);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Check an object was created.
expect(runtimeScene.getObjects('MyObjectA').length).toBe(2);
const myObjectA2 = runtimeScene.getObjects('MyObjectA')[1];
// Check that the instance just created is updated by
// the action (like if there was no wait action).
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
// Process the tasks again (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Check an object was created.
expect(runtimeScene.getObjects('MyObjectA').length).toBe(3);
const myObjectA3 = runtimeScene.getObjects('MyObjectA')[2];
// Check that both objects that have been created are updated by
// the last action (like if there was no wait action).
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
5 + 5
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
});
test('asynchronous actions and created and deleted objects, using object groups', function () {
const eventsSerializerElement = gd.Serializer.fromJSON(
JSON.stringify([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [
{
type: { value: 'VarObjet' },
parameters: ['MyParamObject', 'TestVariable', '>=', '1'],
},
],
actions: [
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'Create' },
parameters: ['', 'MyParamObject', '0', '0', ''],
},
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
],
},
])
);
const project = new gd.ProjectHelper.createNewGDJSProject();
const eventsFunction = new gd.EventsFunction();
eventsFunction
.getEvents()
.unserializeFrom(project, eventsSerializerElement);
eventsFunction
.getParameters()
.insertNewParameter('IncreaseValue', 0)
.setType('number');
eventsFunction
.getParameters()
.insertNewParameter('MyParamObject', 1)
.setType('object');
const runCompiledEvents = generateCompiledEventsForEventsFunction(
gd,
project,
eventsFunction
);
eventsFunction.delete();
project.delete();
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const myObjectA1 = runtimeScene.createObject('MyObjectA');
const myObjectA2 = runtimeScene.createObject('MyObjectA');
const myObjectA3 = runtimeScene.createObject('MyObjectA');
const myObjectB1 = runtimeScene.createObject('MyObjectB');
const myObjectB2 = runtimeScene.createObject('MyObjectB');
const myObjectsLists = gdjs.Hashtable.newFrom({
MyObjectA: [myObjectA1, myObjectA2, myObjectA3],
MyObjectB: [myObjectB1, myObjectB2],
});
myObjectA1.getVariables().get('TestVariable').setNumber(1);
myObjectA2.getVariables().get('TestVariable').setNumber(1);
myObjectB1.getVariables().get('TestVariable').setNumber(1);
runCompiledEvents(gdjs, runtimeScene, [5, myObjectsLists]);
// Only objects filtered by the first condition should have been impacted.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
1 + 5
);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
1 + 5
);
expect(myObjectB1.getVariables().get('TestVariable').getAsNumber()).toBe(
1 + 5
);
// Other objects, not picked by the first condition, are not impacted.
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectB2.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Check an object was created.
expect(runtimeScene.getObjects('MyObjectA').length).toBe(4);
const newMyObjectA = runtimeScene.getObjects('MyObjectA')[3];
// Delete some objects while the second Wait task is running.
myObjectA1.deleteFromScene();
myObjectB1.deleteFromScene();
// Process the tasks again (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Check the newly created object was updated by the last action
expect(
newMyObjectA.getVariables().get('TestVariable').getAsNumber()
).toBe(5);
// Check the object picked by the condition (and not deleted) is updated
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
1 + 5 + 5
);
// Check the deleted objects and objects not picked are not updated
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
1 + 5
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectB1.getVariables().get('TestVariable').getAsNumber()).toBe(
1 + 5
);
expect(myObjectB2.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
});
test('created and then immediately deleted objects', function () {
const eventsSerializerElement = gd.Serializer.fromJSON(
JSON.stringify([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [
{
type: { value: 'VarObjet' },
parameters: ['MyParamObject', 'TestVariable', '>=', '1'],
},
],
actions: [
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'Create' },
parameters: ['', 'MyParamObject', '0', '0', ''],
},
{
type: { value: 'Create' },
parameters: ['', 'MyParamObject', '0', '0', ''],
},
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
],
},
])
);
const project = new gd.ProjectHelper.createNewGDJSProject();
const eventsFunction = new gd.EventsFunction();
eventsFunction
.getEvents()
.unserializeFrom(project, eventsSerializerElement);
eventsFunction
.getParameters()
.insertNewParameter('IncreaseValue', 0)
.setType('number');
eventsFunction
.getParameters()
.insertNewParameter('MyParamObject', 1)
.setType('object');
const runCompiledEvents = generateCompiledEventsForEventsFunction(
gd,
project,
eventsFunction
);
eventsFunction.delete();
project.delete();
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const myObjectA1 = runtimeScene.createObject('MyObjectA');
const myObjectA2 = runtimeScene.createObject('MyObjectA');
const myObjectA3 = runtimeScene.createObject('MyObjectA');
const myObjectB1 = runtimeScene.createObject('MyObjectB');
const myObjectB2 = runtimeScene.createObject('MyObjectB');
const myObjectsLists = gdjs.Hashtable.newFrom({
MyObjectA: [myObjectA1, myObjectA2, myObjectA3],
MyObjectB: [myObjectB1, myObjectB2],
});
myObjectA1.getVariables().get('TestVariable').setNumber(1);
myObjectA2.getVariables().get('TestVariable').setNumber(1);
myObjectB1.getVariables().get('TestVariable').setNumber(1);
runCompiledEvents(gdjs, runtimeScene, [5, myObjectsLists]);
// Only objects filtered by the first condition should have been impacted.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
1 + 5
);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
1 + 5
);
expect(myObjectB1.getVariables().get('TestVariable').getAsNumber()).toBe(
1 + 5
);
// Other objects, not picked by the first condition, are not impacted.
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectB2.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Check that two objects were created.
expect(runtimeScene.getObjects('MyObjectA').length).toBe(5);
const newMyObjectA1 = runtimeScene.getObjects('MyObjectA')[3];
const newMyObjectA2 = runtimeScene.getObjects('MyObjectA')[4];
// Delete some objects while the second Wait task is running.
myObjectA1.deleteFromScene();
myObjectB1.deleteFromScene();
newMyObjectA1.deleteFromScene();
// Process the tasks again (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Check the newly created and then deleted object was not updated by the last action
expect(
newMyObjectA1.getVariables().get('TestVariable').getAsNumber()
).toBe(0);
// Check the newly created object was updated by the last action
expect(
newMyObjectA2.getVariables().get('TestVariable').getAsNumber()
).toBe(5);
// Check the object picked by the condition (and not deleted) is updated
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
1 + 5 + 5
);
// Check the deleted objects and objects not picked are not updated
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
1 + 5
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectB1.getVariables().get('TestVariable').getAsNumber()).toBe(
1 + 5
);
expect(myObjectB2.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
});
describe('async object actions, waiting for all objects to be finished', () => {
const expectProgressivelyResolvedTasksForObjects = (
runCompiledEvents
) => {
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const myObjectA1 = runtimeScene.createObject('MyObjectA');
const myObjectA2 = runtimeScene.createObject('MyObjectA');
const myObjectA3 = runtimeScene.createObject('MyObjectA');
const myObjectB1 = runtimeScene.createObject('MyObjectB');
const myObjectB2 = runtimeScene.createObject('MyObjectB');
const myObjectsLists = gdjs.Hashtable.newFrom({
MyObjectA: [myObjectA1, myObjectA2, myObjectA3],
MyObjectB: [myObjectB1, myObjectB2],
});
runCompiledEvents(gdjs, runtimeScene, [5, myObjectsLists]);
expect(runtimeScene.getVariables().has('SuccessVariable')).toBe(false);
// Process the tasks again (but none is finished).
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
expect(runtimeScene.getVariables().has('SuccessVariable')).toBe(false);
// Mark some tasks as done.
myObjectA1.markFakeAsyncActionAsFinished();
myObjectA2.markFakeAsyncActionAsFinished();
myObjectB1.markFakeAsyncActionAsFinished();
// Process the tasks again (but not everything is finished).
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
expect(runtimeScene.getVariables().has('SuccessVariable')).toBe(false);
// Mark the rest of tasks as done.
myObjectA3.markFakeAsyncActionAsFinished();
myObjectB2.markFakeAsyncActionAsFinished();
// Process the tasks again (everything is finished this time).
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
expect(runtimeScene.getVariables().has('SuccessVariable')).toBe(true);
expect(
runtimeScene.getVariables().get('SuccessVariable').getAsNumber()
).toBe(1);
expect(
myObjectA1.getVariables().get('TestVariable').getAsNumber()
).toBe(5);
expect(
myObjectA2.getVariables().get('TestVariable').getAsNumber()
).toBe(5);
expect(
myObjectA3.getVariables().get('TestVariable').getAsNumber()
).toBe(5);
expect(
myObjectB1.getVariables().get('TestVariable').getAsNumber()
).toBe(5);
expect(
myObjectB2.getVariables().get('TestVariable').getAsNumber()
).toBe(5);
};
test('async object actions, waiting for all objects to be finished', function () {
const eventsSerializerElement = gd.Serializer.fromJSON(
JSON.stringify([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [],
actions: [
{
type: {
value:
'FakeObjectWithAsyncAction::FakeObjectWithAsyncAction::DoAsyncAction',
},
parameters: ['MyParamObject'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
{
type: { value: 'ModVarScene' },
parameters: ['SuccessVariable', '+', '1'],
},
],
},
])
);
const project = new gd.ProjectHelper.createNewGDJSProject();
const eventsFunction = new gd.EventsFunction();
eventsFunction
.getEvents()
.unserializeFrom(project, eventsSerializerElement);
eventsFunction
.getParameters()
.insertNewParameter('IncreaseValue', 0)
.setType('number');
eventsFunction
.getParameters()
.insertNewParameter('MyParamObject', 1)
.setType('object')
.setExtraInfo('FakeObjectWithAsyncAction::FakeObjectWithAsyncAction');
const runCompiledEvents = generateCompiledEventsForEventsFunction(
gd,
project,
eventsFunction
);
eventsFunction.delete();
project.delete();
expectProgressivelyResolvedTasksForObjects(runCompiledEvents);
});
test('optionally async object action, set as async', function () {
const eventsSerializerElement = gd.Serializer.fromJSON(
JSON.stringify([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [],
actions: [
{
type: {
value:
'FakeObjectWithAsyncAction::FakeObjectWithAsyncAction::DoOptionallyAsyncAction',
await: true,
},
parameters: ['MyParamObject'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
{
type: { value: 'ModVarScene' },
parameters: ['SuccessVariable', '+', '1'],
},
],
},
])
);
const project = new gd.ProjectHelper.createNewGDJSProject();
const eventsFunction = new gd.EventsFunction();
eventsFunction
.getEvents()
.unserializeFrom(project, eventsSerializerElement);
eventsFunction
.getParameters()
.insertNewParameter('IncreaseValue', 0)
.setType('number');
eventsFunction
.getParameters()
.insertNewParameter('MyParamObject', 1)
.setType('object')
.setExtraInfo('FakeObjectWithAsyncAction::FakeObjectWithAsyncAction');
const runCompiledEvents = generateCompiledEventsForEventsFunction(
gd,
project,
eventsFunction
);
eventsFunction.delete();
project.delete();
expectProgressivelyResolvedTasksForObjects(runCompiledEvents);
});
test('optionally async object action, not set as async', function () {
const eventsSerializerElement = gd.Serializer.fromJSON(
JSON.stringify([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [],
actions: [
{
type: {
value:
'FakeObjectWithAsyncAction::FakeObjectWithAsyncAction::DoOptionallyAsyncAction',
await: false,
},
parameters: ['MyParamObject'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
{
type: { value: 'ModVarScene' },
parameters: ['SuccessVariable', '+', '1'],
},
],
},
])
);
const project = new gd.ProjectHelper.createNewGDJSProject();
const eventsFunction = new gd.EventsFunction();
eventsFunction
.getEvents()
.unserializeFrom(project, eventsSerializerElement);
eventsFunction
.getParameters()
.insertNewParameter('IncreaseValue', 0)
.setType('number');
eventsFunction
.getParameters()
.insertNewParameter('MyParamObject', 1)
.setType('object')
.setExtraInfo('FakeObjectWithAsyncAction::FakeObjectWithAsyncAction');
const runCompiledEvents = generateCompiledEventsForEventsFunction(
gd,
project,
eventsFunction
);
eventsFunction.delete();
project.delete();
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const myObjectA1 = runtimeScene.createObject('MyObjectA');
const myObjectA2 = runtimeScene.createObject('MyObjectA');
const myObjectA3 = runtimeScene.createObject('MyObjectA');
const myObjectB1 = runtimeScene.createObject('MyObjectB');
const myObjectB2 = runtimeScene.createObject('MyObjectB');
const myObjectsLists = gdjs.Hashtable.newFrom({
MyObjectA: [myObjectA1, myObjectA2, myObjectA3],
MyObjectB: [myObjectB1, myObjectB2],
});
runCompiledEvents(gdjs, runtimeScene, [5, myObjectsLists]);
// Nothing is async, everything is done in a single run.
expect(runtimeScene.getVariables().has('SuccessVariable')).toBe(true);
expect(
runtimeScene.getVariables().get('SuccessVariable').getAsNumber()
).toBe(1);
expect(
myObjectA1.getVariables().get('TestVariable').getAsNumber()
).toBe(5);
expect(
myObjectA2.getVariables().get('TestVariable').getAsNumber()
).toBe(5);
expect(
myObjectA3.getVariables().get('TestVariable').getAsNumber()
).toBe(5);
expect(
myObjectB1.getVariables().get('TestVariable').getAsNumber()
).toBe(5);
expect(
myObjectB2.getVariables().get('TestVariable').getAsNumber()
).toBe(5);
});
});
});
describe('With objects, and advanced conditions', () => {
test('with "Or" conditions', function () {
const eventsSerializerElement = gd.Serializer.fromJSON(
JSON.stringify([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [
{
type: {
value: 'BuiltinCommonInstructions::Or',
},
parameters: [],
subInstructions: [
{
type: { value: 'VarObjet' },
parameters: ['MyParamObject', 'PleaseCountMe', '=', '1'],
},
{
type: { value: 'VarObjet' },
parameters: ['MyParamObject', 'PleaseCountMeToo', '=', '1'],
},
],
},
],
actions: [
{
type: {
value:
'FakeObjectWithAsyncAction::FakeObjectWithAsyncAction::DoAsyncAction',
},
parameters: ['MyParamObject'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
],
events: [
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [
{
type: {
value: 'BuiltinCommonInstructions::Or',
},
parameters: [],
subInstructions: [
{
type: { value: 'VarObjet' },
parameters: [
'MyParamObject',
'PleaseCountMeASecondTime',
'=',
'1',
],
},
{
type: { value: 'VarObjet' },
parameters: [
'MyParamObject',
'PleaseCountMeASecondTimeToo',
'=',
'1',
],
},
],
},
],
actions: [
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
],
},
],
},
])
);
const project = new gd.ProjectHelper.createNewGDJSProject();
const eventsFunction = new gd.EventsFunction();
eventsFunction
.getEvents()
.unserializeFrom(project, eventsSerializerElement);
eventsFunction
.getParameters()
.insertNewParameter('IncreaseValue', 0)
.setType('number');
eventsFunction
.getParameters()
.insertNewParameter('MyParamObject', 1)
.setType('object')
.setExtraInfo('FakeObjectWithAsyncAction::FakeObjectWithAsyncAction');
const runCompiledEvents = generateCompiledEventsForEventsFunction(
gd,
project,
eventsFunction
);
eventsFunction.delete();
project.delete();
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const myObjectA1 = runtimeScene.createObject('MyObjectA');
const myObjectA2 = runtimeScene.createObject('MyObjectA');
const myObjectA3 = runtimeScene.createObject('MyObjectA');
const myObjectB1 = runtimeScene.createObject('MyObjectB');
const myObjectB2 = runtimeScene.createObject('MyObjectB');
const myObjectB3 = runtimeScene.createObject('MyObjectB');
const myObjectsLists = gdjs.Hashtable.newFrom({
MyObjectA: [myObjectA1, myObjectA2, myObjectA3],
MyObjectB: [myObjectB1, myObjectB2, myObjectB3],
});
myObjectA1.getVariables().get('PleaseCountMe').setNumber(1);
myObjectA1.getVariables().get('PleaseCountMeASecondTime').setNumber(1);
myObjectA2.getVariables().get('PleaseCountMeToo').setNumber(1);
myObjectB1.getVariables().get('PleaseCountMe').setNumber(1);
myObjectB1.getVariables().get('PleaseCountMeASecondTimeToo').setNumber(1);
myObjectB2.getVariables().get('PleaseCountMeToo').setNumber(1);
runCompiledEvents(gdjs, runtimeScene, [5, myObjectsLists]);
expect(runtimeScene.getVariables().has('SuccessVariable')).toBe(false);
// Mark tasks as done.
myObjectA1.markFakeAsyncActionAsFinished();
myObjectA2.markFakeAsyncActionAsFinished();
myObjectA3.markFakeAsyncActionAsFinished();
myObjectB1.markFakeAsyncActionAsFinished();
myObjectB2.markFakeAsyncActionAsFinished();
myObjectB3.markFakeAsyncActionAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Check that only objects passing the "Or" sub-conditions have been
// updated.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
5 + 5 // Pass both "Or" conditions.
);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
5 // Pass the first "Or" conditions.
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
0 // Pass no conditions.
);
expect(myObjectB1.getVariables().get('TestVariable').getAsNumber()).toBe(
5 + 5 // Pass both "Or" conditions.
);
expect(myObjectB2.getVariables().get('TestVariable').getAsNumber()).toBe(
5 // Pass the first "Or" conditions.
);
expect(myObjectB3.getVariables().get('TestVariable').getAsNumber()).toBe(
0 // Pass no conditions.
);
});
});
describe('With non standard events', () => {
test('a While event', function () {
const eventsSerializerElement = gd.Serializer.fromJSObject([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [],
actions: [
{
type: { value: 'ModVarScene' },
parameters: ['Counter', '=', '0'],
},
],
},
{
infiniteLoopWarning: true,
type: 'BuiltinCommonInstructions::While',
whileConditions: [
{
type: { value: 'VarScene' },
parameters: ['Counter', '<', '4'],
},
],
conditions: [
{
type: { value: 'VarObjet' },
parameters: ['MyParamObject', 'PleasePickMe', '=', '1'],
},
],
actions: [
{
type: { value: 'ModVarScene' },
parameters: ['Counter', '+', '1'],
},
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
],
},
]);
const project = new gd.ProjectHelper.createNewGDJSProject();
const eventsFunction = new gd.EventsFunction();
eventsFunction
.getEvents()
.unserializeFrom(project, eventsSerializerElement);
eventsFunction
.getParameters()
.insertNewParameter('IncreaseValue', 0)
.setType('number');
eventsFunction
.getParameters()
.insertNewParameter('MyParamObject', 1)
.setType('object');
const runCompiledEvents = generateCompiledEventsForEventsFunction(
gd,
project,
eventsFunction
);
eventsFunction.delete();
project.delete();
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const myObjectA1 = runtimeScene.createObject('MyObjectA');
const myObjectA2 = runtimeScene.createObject('MyObjectA');
const myObjectA3 = runtimeScene.createObject('MyObjectA');
const myObjectB1 = runtimeScene.createObject('MyObjectB');
const myObjectB2 = runtimeScene.createObject('MyObjectB');
const myObjectsLists = gdjs.Hashtable.newFrom({
MyObjectA: [myObjectA1, myObjectA2, myObjectA3],
MyObjectB: [myObjectB1, myObjectB2],
});
myObjectA1.getVariables().get('PleasePickMe').setNumber(1);
myObjectA2.getVariables().get('PleasePickMe').setNumber(1);
myObjectB1.getVariables().get('PleasePickMe').setNumber(1);
runCompiledEvents(gdjs, runtimeScene, [5, myObjectsLists]);
// Check that the loop is done.
expect(runtimeScene.getVariables().has('Counter')).toBe(true);
expect(runtimeScene.getVariables().get('Counter').getAsNumber()).toBe(4);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Check that all the tasks are done
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
5 * 4
);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
5 * 4
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectB1.getVariables().get('TestVariable').getAsNumber()).toBe(
5 * 4
);
expect(myObjectB2.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
});
test('a While event, with sub-events', function () {
const eventsSerializerElement = gd.Serializer.fromJSObject([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [],
actions: [
{
type: { value: 'ModVarScene' },
parameters: ['Counter', '=', '0'],
},
],
},
{
infiniteLoopWarning: true,
type: 'BuiltinCommonInstructions::While',
whileConditions: [
{
type: { value: 'VarScene' },
parameters: ['Counter', '<', '4'],
},
],
conditions: [
{
type: { value: 'VarObjet' },
parameters: ['MyParamObject', 'PleasePickMe', '=', '1'],
},
],
actions: [],
events: [
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [
// (Same condition as before)
{
type: { value: 'VarObjet' },
parameters: ['MyParamObject', 'PleasePickMe', '=', '1'],
},
],
actions: [
{
type: { value: 'ModVarScene' },
parameters: ['Counter', '+', '1'],
},
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
],
},
],
},
]);
const project = new gd.ProjectHelper.createNewGDJSProject();
const eventsFunction = new gd.EventsFunction();
eventsFunction
.getEvents()
.unserializeFrom(project, eventsSerializerElement);
eventsFunction
.getParameters()
.insertNewParameter('IncreaseValue', 0)
.setType('number');
eventsFunction
.getParameters()
.insertNewParameter('MyParamObject', 1)
.setType('object');
const runCompiledEvents = generateCompiledEventsForEventsFunction(
gd,
project,
eventsFunction
);
eventsFunction.delete();
project.delete();
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const myObjectA1 = runtimeScene.createObject('MyObjectA');
const myObjectA2 = runtimeScene.createObject('MyObjectA');
const myObjectA3 = runtimeScene.createObject('MyObjectA');
const myObjectB1 = runtimeScene.createObject('MyObjectB');
const myObjectB2 = runtimeScene.createObject('MyObjectB');
const myObjectsLists = gdjs.Hashtable.newFrom({
MyObjectA: [myObjectA1, myObjectA2, myObjectA3],
MyObjectB: [myObjectB1, myObjectB2],
});
myObjectA1.getVariables().get('PleasePickMe').setNumber(1);
myObjectA2.getVariables().get('PleasePickMe').setNumber(1);
myObjectB1.getVariables().get('PleasePickMe').setNumber(1);
runCompiledEvents(gdjs, runtimeScene, [5, myObjectsLists]);
// Check that the loop is done.
expect(runtimeScene.getVariables().has('Counter')).toBe(true);
expect(runtimeScene.getVariables().get('Counter').getAsNumber()).toBe(4);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Check that all the tasks are done
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
5 * 4
);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
5 * 4
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectB1.getVariables().get('TestVariable').getAsNumber()).toBe(
5 * 4
);
expect(myObjectB2.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
});
test('a Repeat event', function () {
const eventsSerializerElement = gd.Serializer.fromJSObject([
{
infiniteLoopWarning: true,
type: 'BuiltinCommonInstructions::Repeat',
repeatExpression: '3',
conditions: [
{
type: { value: 'VarObjet' },
parameters: ['MyParamObject', 'PleasePickMe', '=', '1'],
},
],
actions: [
{
type: { value: 'ModVarScene' },
parameters: ['Counter', '+', '1'],
},
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
],
},
]);
const project = new gd.ProjectHelper.createNewGDJSProject();
const eventsFunction = new gd.EventsFunction();
eventsFunction
.getEvents()
.unserializeFrom(project, eventsSerializerElement);
eventsFunction
.getParameters()
.insertNewParameter('IncreaseValue', 0)
.setType('number');
eventsFunction
.getParameters()
.insertNewParameter('MyParamObject', 1)
.setType('object');
const runCompiledEvents = generateCompiledEventsForEventsFunction(
gd,
project,
eventsFunction
);
eventsFunction.delete();
project.delete();
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const myObjectA1 = runtimeScene.createObject('MyObjectA');
const myObjectA2 = runtimeScene.createObject('MyObjectA');
const myObjectA3 = runtimeScene.createObject('MyObjectA');
const myObjectB1 = runtimeScene.createObject('MyObjectB');
const myObjectB2 = runtimeScene.createObject('MyObjectB');
const myObjectsLists = gdjs.Hashtable.newFrom({
MyObjectA: [myObjectA1, myObjectA2, myObjectA3],
MyObjectB: [myObjectB1, myObjectB2],
});
myObjectA1.getVariables().get('PleasePickMe').setNumber(1);
myObjectA2.getVariables().get('PleasePickMe').setNumber(1);
myObjectB1.getVariables().get('PleasePickMe').setNumber(1);
runCompiledEvents(gdjs, runtimeScene, [5, myObjectsLists]);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Check that all the tasks are done
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
5 * 3
);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
5 * 3
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectB1.getVariables().get('TestVariable').getAsNumber()).toBe(
5 * 3
);
expect(myObjectB2.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
});
test('a ForEach event', function () {
const eventsSerializerElement = gd.Serializer.fromJSObject([
{
infiniteLoopWarning: true,
type: 'BuiltinCommonInstructions::ForEach',
object: 'MyParamObject',
conditions: [
{
type: { value: 'VarObjet' },
parameters: ['MyParamObject', 'PleasePickMe', '=', '1'],
},
],
actions: [
{
type: { value: 'ModVarScene' },
parameters: ['Counter', '+', '1'],
},
// Add a wait action to check that 3 different waits will be done
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
// Add another wait action to check that 3 different waits will be done
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
{
type: { value: 'ModVarObjet' },
parameters: ['MyOtherParamObject', 'TestVariable', '+', '4'],
},
// Add an async object action that can be resolved at different time by each object.
{
type: {
value:
'FakeObjectWithAsyncAction::FakeObjectWithAsyncAction::DoAsyncAction',
},
parameters: ['MyParamObject'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
{
type: { value: 'ModVarObjet' },
parameters: ['MyOtherParamObject', 'TestVariable', '+', '4'],
},
],
},
]);
const project = new gd.ProjectHelper.createNewGDJSProject();
const eventsFunction = new gd.EventsFunction();
eventsFunction
.getEvents()
.unserializeFrom(project, eventsSerializerElement);
eventsFunction
.getParameters()
.insertNewParameter('IncreaseValue', 0)
.setType('number');
eventsFunction
.getParameters()
.insertNewParameter('MyParamObject', 1)
.setType('object')
.setExtraInfo('FakeObjectWithAsyncAction::FakeObjectWithAsyncAction');
eventsFunction
.getParameters()
.insertNewParameter('MyOtherParamObject', 2)
.setType('object');
const runCompiledEvents = generateCompiledEventsForEventsFunction(
gd,
project,
eventsFunction
);
eventsFunction.delete();
project.delete();
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const myObjectA1 = runtimeScene.createObject('MyObjectA');
const myObjectA2 = runtimeScene.createObject('MyObjectA');
const myObjectA3 = runtimeScene.createObject('MyObjectA');
const myObjectB1 = runtimeScene.createObject('MyObjectB');
const myObjectB2 = runtimeScene.createObject('MyObjectB');
const myObjectsLists = gdjs.Hashtable.newFrom({
MyObjectA: [myObjectA1, myObjectA2, myObjectA3],
MyObjectB: [myObjectB1, myObjectB2],
});
myObjectA1.getVariables().get('PleasePickMe').setNumber(1);
myObjectA2.getVariables().get('PleasePickMe').setNumber(1);
myObjectB1.getVariables().get('PleasePickMe').setNumber(1);
const myObjectC1 = runtimeScene.createObject('MyObjectC');
const myObjectC2 = runtimeScene.createObject('MyObjectC');
const myOtherObjectsLists = gdjs.Hashtable.newFrom({
MyObjectC: [myObjectC1, myObjectC2],
});
runCompiledEvents(gdjs, runtimeScene, [
5,
myObjectsLists,
myOtherObjectsLists,
]);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Check that each object A and B got its variable updated.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectB1.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectB2.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Check that each object A and B got its variable updated.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
5 + 5
);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
5 + 5
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectB1.getVariables().get('TestVariable').getAsNumber()).toBe(
5 + 5
);
expect(myObjectB2.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
// Check that the objects C are also updated: the two of them are updated
// 3 times (once for each object of the ForEach)
// (4 is added each time to the variable).
expect(myObjectC1.getVariables().get('TestVariable').getAsNumber()).toBe(
3 * 4
);
expect(myObjectC2.getVariables().get('TestVariable').getAsNumber()).toBe(
3 * 4
);
// Process some object (myObjectA1, myObjectB1) async tasks:
myObjectA1.markFakeAsyncActionAsFinished();
myObjectB1.markFakeAsyncActionAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Check that each object A and B got its variable updated.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
5 + 5 + 5
);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
5 + 5 // This was not updated
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectB1.getVariables().get('TestVariable').getAsNumber()).toBe(
5 + 5 + 5
);
expect(myObjectB2.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
// Check that the objects C are also updated: the two of them are updated
// 2 times (once for each object that finished its task)
// (4 is added each time to the variable).
expect(myObjectC1.getVariables().get('TestVariable').getAsNumber()).toBe(
3 * 4 + 2 * 4
);
expect(myObjectC2.getVariables().get('TestVariable').getAsNumber()).toBe(
3 * 4 + 2 * 4
);
// Process the last object (myObjectA2) async tasks:
myObjectA2.markFakeAsyncActionAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Check that each object A and B got its variable updated.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
5 + 5 + 5
);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
5 + 5 + 5 // This was just updated.
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectB1.getVariables().get('TestVariable').getAsNumber()).toBe(
5 + 5 + 5
);
expect(myObjectB2.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
// Check that the objects C are also updated: the two of them are updated
// 1 more time (once the last object) (4 is added each time to the variable).
expect(myObjectC1.getVariables().get('TestVariable').getAsNumber()).toBe(
3 * 4 + 2 * 4 + 1 * 4
);
expect(myObjectC2.getVariables().get('TestVariable').getAsNumber()).toBe(
3 * 4 + 2 * 4 + 1 * 4
);
});
test('a ForEach on created objects', function () {
const eventsSerializerElement = gd.Serializer.fromJSON(
JSON.stringify([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [],
actions: [
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'Create' },
parameters: ['', 'MyParamObject', '0', '0', ''],
},
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
{
type: { value: 'Create' },
parameters: ['', 'MyParamObject', '0', '0', ''],
},
// Set a variable for the last two created instances:
{
type: { value: 'ModVarObjet' },
parameters: ['MyParamObject', 'PleasePickMe', '=', '1'],
},
{
type: { value: 'Wait' },
parameters: ['1.5'],
},
// Create an additional object but without a variable, so
// that it's discarded in the for each
{
type: { value: 'Create' },
parameters: ['', 'MyParamObject', '0', '0', ''],
},
],
events: [
{
infiniteLoopWarning: true,
type: 'BuiltinCommonInstructions::ForEach',
object: 'MyParamObject',
conditions: [
{
type: { value: 'VarObjet' },
parameters: ['MyParamObject', 'PleasePickMe', '=', '1'],
},
],
actions: [
// Add an async object action that can be resolved at different time by each object.
{
type: {
value:
'FakeObjectWithAsyncAction::FakeObjectWithAsyncAction::DoAsyncAction',
},
parameters: ['MyParamObject'],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyParamObject',
'TestVariable',
'+',
'GetArgumentAsNumber("IncreaseValue")',
],
},
{
type: { value: 'ModVarObjet' },
parameters: [
'MyOtherParamObject',
'TestVariable',
'+',
'4',
],
},
],
},
],
},
])
);
const project = new gd.ProjectHelper.createNewGDJSProject();
const eventsFunction = new gd.EventsFunction();
eventsFunction
.getEvents()
.unserializeFrom(project, eventsSerializerElement);
eventsFunction
.getParameters()
.insertNewParameter('IncreaseValue', 0)
.setType('number');
eventsFunction
.getParameters()
.insertNewParameter('MyParamObject', 1)
.setType('object')
.setExtraInfo('FakeObjectWithAsyncAction::FakeObjectWithAsyncAction');
eventsFunction
.getParameters()
.insertNewParameter('MyOtherParamObject', 2)
.setType('object');
const runCompiledEvents = generateCompiledEventsForEventsFunction(
gd,
project,
eventsFunction
);
eventsFunction.delete();
project.delete();
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const myObjectA1 = runtimeScene.createObject('MyObjectA');
const myObjectC1 = runtimeScene.createObject('MyObjectC');
const myObjectC2 = runtimeScene.createObject('MyObjectC');
const myObjectsLists = gdjs.Hashtable.newFrom({
MyObjectA: [],
});
const myOtherObjectsLists = gdjs.Hashtable.newFrom({
MyObjectC: [myObjectC1, myObjectC2],
});
runCompiledEvents(gdjs, runtimeScene, [
5,
myObjectsLists,
myOtherObjectsLists,
]);
// Process the tasks (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Check an object was created.
expect(runtimeScene.getObjects('MyObjectA').length).toBe(2);
const myObjectA2 = runtimeScene.getObjects('MyObjectA')[1];
// Process the tasks again (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Check an object was created.
expect(runtimeScene.getObjects('MyObjectA').length).toBe(3);
const myObjectA3 = runtimeScene.getObjects('MyObjectA')[2];
// Process the tasks again (after faking it's finished).
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Check an object was created.
expect(runtimeScene.getObjects('MyObjectA').length).toBe(4);
const myObjectA4 = runtimeScene.getObjects('MyObjectA')[3];
// Process some object async tasks:
myObjectA2.markFakeAsyncActionAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Check that object A got its variable updated.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
5 // This was just updated.
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectA4.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
// Check that the objects C are also updated: the two of them are updated
// once (4 is added each time to the variable).
expect(myObjectC1.getVariables().get('TestVariable').getAsNumber()).toBe(
4
);
expect(myObjectC2.getVariables().get('TestVariable').getAsNumber()).toBe(
4
);
// Process the remaining object async tasks:
myObjectA3.markFakeAsyncActionAsFinished();
runtimeScene.getAsyncTasksManager().processTasks(runtimeScene);
// Check that object A got its variable updated.
expect(myObjectA1.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
expect(myObjectA2.getVariables().get('TestVariable').getAsNumber()).toBe(
5
);
expect(myObjectA3.getVariables().get('TestVariable').getAsNumber()).toBe(
5 // This was just updated.
);
expect(myObjectA4.getVariables().get('TestVariable').getAsNumber()).toBe(
0
);
// Check that the objects C are also updated: the two of them are updated
// once more.
expect(myObjectC1.getVariables().get('TestVariable').getAsNumber()).toBe(
4 + 4
);
expect(myObjectC2.getVariables().get('TestVariable').getAsNumber()).toBe(
4 + 4
);
});
});
describe('Events based asynchronous functions', () => {
it('Resolves after awaiting an async action', () => {
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const extensionModule =
generateCompiledEventsForSerializedEventsBasedExtension(
gd,
require('./extensions/EBAsyncAction.json'),
gdjs,
runtimeScene
);
const {
freeFunctions: { wait },
behaviors: { Behavior },
objects: { Object },
} = extensionModule;
const freeFunctionExtensionTask = wait();
expect(freeFunctionExtensionTask.update()).toBe(false);
expect(runtimeScene.getAsyncTasksManager().tasks.size).toBe(1);
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks();
expect(freeFunctionExtensionTask.update()).toBe(true);
const object = new Object(runtimeScene, {});
const objectExtensionTask = object.wait();
expect(objectExtensionTask.update()).toBe(false);
expect(runtimeScene.getAsyncTasksManager().tasks.size).toBe(1);
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks();
expect(objectExtensionTask.update()).toBe(true);
const behavior = new Behavior(runtimeScene, {});
const behaviorExtensionTask = behavior.wait();
expect(behaviorExtensionTask.update()).toBe(false);
expect(runtimeScene.getAsyncTasksManager().tasks.size).toBe(1);
runtimeScene.getAsyncTasksManager().markAllFakeAsyncTasksAsFinished();
runtimeScene.getAsyncTasksManager().processTasks();
expect(behaviorExtensionTask.update()).toBe(true);
});
it('Resolves without awaiting an async action', () => {
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const extensionModule =
generateCompiledEventsForSerializedEventsBasedExtension(
gd,
require('./extensions/EBAsyncAction.json'),
gdjs,
runtimeScene
);
const {
freeFunctions: { noWait },
behaviors: { Behavior },
objects: { Object },
} = extensionModule;
const extensionTask = noWait();
expect(extensionTask.update()).toBe(true);
expect(runtimeScene.getAsyncTasksManager().tasks.size).toBe(0);
const obj = new Object(runtimeScene, {});
const objectExtensionTask = obj.noWait();
expect(objectExtensionTask.update()).toBe(true);
expect(runtimeScene.getAsyncTasksManager().tasks.size).toBe(0);
const behavior = new Behavior(runtimeScene, {});
const behaviorExtensionTask = behavior.noWait();
expect(behaviorExtensionTask.update()).toBe(true);
expect(runtimeScene.getAsyncTasksManager().tasks.size).toBe(0);
});
});
});