Compare commits

...

13 Commits

Author SHA1 Message Date
Davy Hélard
689676e058 Review changes: add a test with create and return object actions. 2023-11-18 17:28:29 +01:00
Davy Hélard
1ed6b4889a Move the action declaration next to other "return" actions. 2023-10-29 17:00:47 +01:00
Davy Hélard
ccec9e9b8b Wording 2023-10-29 17:00:06 +01:00
Davy Hélard
2a036368f5 Remove only. 2023-10-29 16:46:08 +01:00
Davy Hélard
3bc8b1839f Add tests. 2023-10-29 16:43:51 +01:00
Davy Hélard
d8f2ced5f5 Format 2023-10-28 16:27:25 +02:00
Davy Hélard
5373406177 Fix a crash when the pick action is used in a function called from another function. 2023-10-28 16:27:24 +02:00
Davy Hélard
3d1142f7c7 Add line breaks. 2023-10-28 16:27:24 +02:00
Davy Hélard
2d7e6248f7 Use the new way for context. 2023-10-28 16:27:24 +02:00
Arthur Pacaud
85dd04e430 Don't use Object.values" 2023-10-28 16:27:24 +02:00
Arthur Pacaud
c25252ce33 Fix objects groups inside of functions 2023-10-28 16:27:23 +02:00
Arthur Pacaud
685b2105e1 Fix object being added to wring lists when a group is passed 2023-10-28 16:27:23 +02:00
Arthur Pacaud
cd0bfa9281 Add action to return objects 2023-10-28 16:27:23 +02:00
6 changed files with 270 additions and 0 deletions

View File

@@ -66,6 +66,19 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
.AddAction("SetReturnObject",
_("Set returned objects"),
_("Set currently picked instances as the ones returned for the object. These instances will be picked for actions, conditions and sub-events that follow this function call."),
_("Set currently picked instances of _PARAM0_ to be returned"),
_("Functions"),
"res/function24.png",
"res/function16.png")
.SetHelpPath("/events/functions/return")
.AddParameter("object", "Picked instances object")
.SetRelevantForFunctionEventsOnly()
.MarkAsAdvanced();
extension
.AddAction("CopyArgumentToVariable",
_("Copy function parameter to variable"),

View File

@@ -99,6 +99,28 @@ AdvancedExtension::AdvancedExtension() {
"}\n";
});
GetAllActions()["SetReturnObject"]
.GetCodeExtraInformation()
.SetCustomCodeGenerator([](gd::Instruction& instruction,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context) {
gd::String objectsPickingCode;
for (const auto& objectName : codeGenerator.GetObjectsContainersList().ExpandObjectName(
instruction.GetParameter(0).GetPlainString(), context.GetCurrentObject())) {
const gd::String& objectNameString = codeGenerator.ConvertToStringExplicit(objectName);
const gd::String& objectList = codeGenerator.GetObjectListName(objectName, context);
objectsPickingCode += "gdjs.evtTools.object.pickObjects("
"eventsFunctionContext.getObjectsLists(" +
objectNameString + "), " + objectList + ");\n";
}
return "if (typeof eventsFunctionContext !== 'undefined') {\n"
" eventsFunctionContext.returnValue = true;\n"
+ objectsPickingCode +
"}\n";
});
GetAllConditions()["GetArgumentAsBoolean"]
.SetCustomCodeGenerator([](gd::Instruction& instruction,
gd::EventsCodeGenerator& codeGenerator,

View File

@@ -218,6 +218,37 @@ namespace gdjs {
arr.length = finalSize;
};
/**
* Pick the objects from a given `Array`.
* @param objectsLists the picking list to filter
* @param objects the objects to pick
*/
export const pickObjects = (
objectsLists: ObjectsLists,
objects: gdjs.RuntimeObject[]
) => {
// Clear the `pick` flag on every objects.
for (const objectsName in objectsLists.items) {
if (objectsLists.items.hasOwnProperty(objectsName)) {
for (const object of objectsLists.items[objectsName]) {
object.pick = false;
}
}
}
// Mark objects that need to be picked.
for (const object of objects) {
object.pick = true;
}
// Trim not picked objects from lists.
for (const objectsName in objectsLists.items) {
if (objectsLists.items.hasOwnProperty(objectsName)) {
gdjs.evtTools.object.filterPickedObjectsList(
objectsLists.items[objectsName]
);
}
}
};
export const hitBoxesCollisionTest = function (
objectsLists1: ObjectsLists,
objectsLists2: ObjectsLists,

View File

@@ -86,6 +86,28 @@ describe('gdjs.evtTools.object.pickObjectsIf', function() {
});
});
describe('gdjs.evtTools.object.pickObjects', function() {
it('should properly pick objects', function(){
const runtimeScene = new gdjs.RuntimeScene(null);
const objectA1 = new gdjs.RuntimeObject(runtimeScene, {name: "ObjectA", type: "", behaviors: [], effects: []});
const objectA2 = new gdjs.RuntimeObject(runtimeScene, {name: "ObjectA", type: "", behaviors: [], effects: []});
const objectA3 = new gdjs.RuntimeObject(runtimeScene, {name: "ObjectA", type: "", behaviors: [], effects: []});
const objectB1 = new gdjs.RuntimeObject(runtimeScene, {name: "ObjectB", type: "", behaviors: [], effects: []});
const objectB2 = new gdjs.RuntimeObject(runtimeScene, {name: "ObjectB", type: "", behaviors: [], effects: []});
const pickedObjectMap = Hashtable.newFrom({
ObjectA: [objectA1, objectA2, objectA3],
ObjectB: [objectB1, objectB2]
});
gdjs.evtTools.object.pickObjects(pickedObjectMap, [objectA3, objectB2, objectA1]);
expect(pickedObjectMap.get("ObjectA")).to.have.length(2);
expect(pickedObjectMap.get("ObjectB")).to.have.length(1);
expect(pickedObjectMap.get("ObjectA")).to.eql([objectA1, objectA3]);
expect(pickedObjectMap.get("ObjectB")).to.eql([objectB2]);
});
});
describe('gdjs.evtTools.object.pickRandomObject', function() {
it('should pick only one object', function(){
var runtimeScene = new gdjs.RuntimeScene(null);

View File

@@ -290,6 +290,22 @@ class VariablesContainer {
has(variableName) {
return this._variables.containsKey(variableName);
}
/**
* @param {string} name
* @param {Variable} newVariable
*/
add(name, newVariable) {
const oldVariable = this._variables.get(name);
this._variables.put(name, newVariable);
if (oldVariable) {
const variableIndex = this._variablesArray.indexOf(oldVariable);
if (variableIndex !== -1) {
this._variablesArray[variableIndex] = newVariable;
}
}
}
}
class RuntimeObject {
@@ -565,6 +581,54 @@ const getPickedInstancesCount = (objectsLists) => {
return count;
};
/**
* @param {RuntimeObject[]} arr
*/
const filterPickedObjectsList = function (
arr
) {
let finalSize = 0;
for (let k = 0, lenk = arr.length; k < lenk; ++k) {
const obj = arr[k];
if (obj.pick) {
arr[finalSize] = obj;
finalSize++;
}
}
arr.length = finalSize;
};
/**
* @param {Hashtable<RuntimeObject[]>} objectsLists
* @param {RuntimeObject[]} objects
*/
const pickObjects = (
objectsLists,
objects
) => {
// Clear the `pick` flag on every objects.
for (const objectsName in objectsLists.items) {
if (objectsLists.items.hasOwnProperty(objectsName)) {
for (const object of objectsLists.items[objectsName]) {
object.pick = false;
}
}
}
// Mark objects that need to be picked.
for (const object of objects) {
object.pick = true;
}
// Trim not picked objects from lists.
for (const objectsName in objectsLists.items) {
if (objectsLists.items.hasOwnProperty(objectsName)) {
filterPickedObjectsList(
objectsLists.items[objectsName]
);
}
}
};
/** A minimal implementation of gdjs.RuntimeScene for testing. */
class RuntimeScene {
constructor(sceneData) {
@@ -729,6 +793,7 @@ function makeMinimalGDJSMock(options) {
createObjectOnScene,
getSceneInstancesCount,
getPickedInstancesCount,
pickObjects,
},
runtimeScene: {
wait: () => new FakeAsyncTask(),

View File

@@ -219,4 +219,121 @@ describe('libGD.js - GDJS Code Generation integration tests', function () {
.getAsNumber()
).toBe(123);
});
it('can generate function returning objects', function () {
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const myObjectA1 = runtimeScene.createObject('MyObjectA');
const myObjectA2 = runtimeScene.createObject('MyObjectA');
const myObjectB1 = runtimeScene.createObject('MyObjectB');
const myObjectB2 = runtimeScene.createObject('MyObjectB');
const myObjectB3 = runtimeScene.createObject('MyObjectB');
const variableA1 = new gdjs.Variable();
variableA1.setNumber(1);
myObjectA1.getVariables().add('Pick', variableA1);
const variableB3 = new gdjs.Variable();
variableB3.setNumber(1);
myObjectB3.getVariables().add('Pick', variableB3);
// Run the function passing some objects as parameters.
const objectsLists = gdjs.Hashtable.newFrom({
MyObjectA: [myObjectA1],
MyObjectB: [myObjectB2, myObjectB3],
MyObjectC: [],
});
const serializerElement = gd.Serializer.fromJSObject([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [
{
type: { value: 'VarObjet' },
parameters: ["Object","Pick","!=","0"],
},
],
actions: [
{
type: { value: 'SetReturnObject' },
parameters: ['Object'],
},
],
events: [],
},
]);
const runCompiledEvents = generateCompiledEventsFromSerializedEvents(
gd,
serializerElement,
{ parameterTypes: { Object: 'object' }, logCode: false }
);
runCompiledEvents(gdjs, runtimeScene, [objectsLists]);
expect(objectsLists.get('MyObjectA')).toEqual([myObjectA1]);
expect(objectsLists.get('MyObjectB')).toEqual([myObjectB3]);
expect(objectsLists.get('MyObjectC')).toEqual([]);
});
it('can generate function creating 2 instances and returning only one', function () {
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
const myObjectA1 = runtimeScene.createObject('MyObjectA');
const myObjectA2 = runtimeScene.createObject('MyObjectA');
const myObjectB1 = runtimeScene.createObject('MyObjectB');
// According to the parameter type objectListOrEmptyIfJustDeclared,
// no instances is passed to the function because the ObjectsLists has not
// been filtered before.
const objectsLists = gdjs.Hashtable.newFrom({
MyObjectA: [],
MyObjectB: [],
MyObjectC: [],
});
const serializerElement = gd.Serializer.fromJSObject([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [
],
actions: [
{
type: { value: 'Create' },
parameters: ['', 'Object', '0','0',''],
},
{
type: {'value':'ModVarObjet'},
parameters: ['Object','Pick','=','1']
},
{
type: { value: 'Create' },
parameters: ['', 'Object', '0','0',''],
},
],
events: [],
},
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [
{
type: { value: 'VarObjet' },
parameters: ['Object','Pick','!=','0'],
},
],
actions: [
{
type: { value: 'SetReturnObject' },
parameters: ['Object'],
},
],
events: [],
},
]);
const runCompiledEvents = generateCompiledEventsFromSerializedEvents(
gd,
serializerElement,
{ parameterTypes: { Object: 'objectListOrEmptyIfJustDeclared' }, logCode: false }
);
runCompiledEvents(gdjs, runtimeScene, [objectsLists]);
expect(objectsLists.get('MyObjectA').length).toBe(1);
});
});