gdcore-tools 1.0.8 → 1.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,50 +1,50 @@
1
- const loadGD = require("../..");
2
- const list = require("./mylist.json");
3
-
4
- let gdTools;
5
- loadGD()
6
- .then((_gdTools) => {
7
- gdTools = _gdTools;
8
- // Load the project file
9
- return gdTools.loadProject("./game.json");
10
- })
11
- .then((project) => {
12
- // Get the scene and add the objects and instances from the list
13
- const scene = project.getLayout(/* Scene name: */ "MyScene");
14
- const instances = scene.getInitialInstances();
15
- let offset = 1;
16
- list.forEach((item) => {
17
- const textObjectName = "MyListItem_" + item;
18
- const object = gdTools.gd.asTextObject(
19
- scene.insertNewObject(
20
- /* Project: */ project,
21
- /* Object type: */ "TextObject::Text",
22
- /* Object name: */ textObjectName,
23
- /* Position where to insert: */ scene.getObjectsCount()
24
- )
25
- );
26
- object.setString(item);
27
- object.setColor(
28
- Math.random() * 255,
29
- Math.random() * 255,
30
- Math.random() * 255
31
- );
32
-
33
- const textObjectInstance = instances.insertNewInitialInstance();
34
- const spriteObjectInstance = instances.insertNewInitialInstance();
35
- textObjectInstance.setObjectName(textObjectName);
36
- spriteObjectInstance.setObjectName("Button");
37
- textObjectInstance.setX(50);
38
- spriteObjectInstance.setX(40);
39
- textObjectInstance.setY(70 * offset + 15);
40
- spriteObjectInstance.setY(70 * offset++);
41
- textObjectInstance.setZOrder(1);
42
- spriteObjectInstance.setZOrder(0);
43
-
44
- spriteObjectInstance.setHasCustomSize(true);
45
- spriteObjectInstance.setCustomHeight(48);
46
- spriteObjectInstance.setCustomWidth(96);
47
- });
48
-
49
- return gdTools.saveProject(project, "new_game.json");
50
- });
1
+ const loadGD = require("../..");
2
+ const list = require("./mylist.json");
3
+
4
+ let gdTools;
5
+ loadGD()
6
+ .then((_gdTools) => {
7
+ gdTools = _gdTools;
8
+ // Load the project file
9
+ return gdTools.loadProject("./game.json");
10
+ })
11
+ .then((project) => {
12
+ // Get the scene and add the objects and instances from the list
13
+ const scene = project.getLayout(/* Scene name: */ "MyScene");
14
+ const instances = scene.getInitialInstances();
15
+ let offset = 1;
16
+ list.forEach((item) => {
17
+ const textObjectName = "MyListItem_" + item;
18
+ const object = gdTools.gd.asTextObject(
19
+ scene.insertNewObject(
20
+ /* Project: */ project,
21
+ /* Object type: */ "TextObject::Text",
22
+ /* Object name: */ textObjectName,
23
+ /* Position where to insert: */ scene.getObjectsCount()
24
+ )
25
+ );
26
+ object.setString(item);
27
+ object.setColor(
28
+ Math.random() * 255,
29
+ Math.random() * 255,
30
+ Math.random() * 255
31
+ );
32
+
33
+ const textObjectInstance = instances.insertNewInitialInstance();
34
+ const spriteObjectInstance = instances.insertNewInitialInstance();
35
+ textObjectInstance.setObjectName(textObjectName);
36
+ spriteObjectInstance.setObjectName("Button");
37
+ textObjectInstance.setX(50);
38
+ spriteObjectInstance.setX(40);
39
+ textObjectInstance.setY(70 * offset + 15);
40
+ spriteObjectInstance.setY(70 * offset++);
41
+ textObjectInstance.setZOrder(1);
42
+ spriteObjectInstance.setZOrder(0);
43
+
44
+ spriteObjectInstance.setHasCustomSize(true);
45
+ spriteObjectInstance.setCustomHeight(48);
46
+ spriteObjectInstance.setCustomWidth(96);
47
+ });
48
+
49
+ return gdTools.saveProject(project, "new_game.json");
50
+ });
@@ -1,205 +1,205 @@
1
- {
2
- "firstLayout": "",
3
- "gdVersion": {
4
- "build": 99,
5
- "major": 4,
6
- "minor": 0,
7
- "revision": 0
8
- },
9
- "properties": {
10
- "adaptGameResolutionAtRuntime": true,
11
- "folderProject": false,
12
- "orientation": "landscape",
13
- "packageName": "com.example.gamename",
14
- "projectUuid": "b0ec0124-f3d9-4225-bfb5-60645a43b358",
15
- "scaleMode": "linear",
16
- "sizeOnStartupMode": "",
17
- "useExternalSourceFiles": false,
18
- "version": "1.0.0",
19
- "name": "Project",
20
- "author": "",
21
- "windowWidth": 800,
22
- "windowHeight": 600,
23
- "latestCompilationDirectory": "",
24
- "maxFPS": 60,
25
- "minFPS": 20,
26
- "verticalSync": false,
27
- "platformSpecificAssets": {},
28
- "loadingScreen": {
29
- "showGDevelopSplash": true
30
- },
31
- "extensionProperties": [],
32
- "extensions": [
33
- {
34
- "name": "BuiltinObject"
35
- },
36
- {
37
- "name": "BuiltinAudio"
38
- },
39
- {
40
- "name": "BuiltinVariables"
41
- },
42
- {
43
- "name": "BuiltinTime"
44
- },
45
- {
46
- "name": "BuiltinMouse"
47
- },
48
- {
49
- "name": "BuiltinKeyboard"
50
- },
51
- {
52
- "name": "BuiltinJoystick"
53
- },
54
- {
55
- "name": "BuiltinCamera"
56
- },
57
- {
58
- "name": "BuiltinWindow"
59
- },
60
- {
61
- "name": "BuiltinFile"
62
- },
63
- {
64
- "name": "BuiltinNetwork"
65
- },
66
- {
67
- "name": "BuiltinScene"
68
- },
69
- {
70
- "name": "BuiltinAdvanced"
71
- },
72
- {
73
- "name": "Sprite"
74
- },
75
- {
76
- "name": "BuiltinCommonInstructions"
77
- },
78
- {
79
- "name": "BuiltinCommonConversions"
80
- },
81
- {
82
- "name": "BuiltinStringInstructions"
83
- },
84
- {
85
- "name": "BuiltinMathematicalTools"
86
- },
87
- {
88
- "name": "BuiltinExternalLayouts"
89
- }
90
- ],
91
- "platforms": [
92
- {
93
- "name": "GDevelop JS platform"
94
- }
95
- ],
96
- "currentPlatform": "GDevelop JS platform"
97
- },
98
- "resources": {
99
- "resources": [],
100
- "resourceFolders": []
101
- },
102
- "objects": [],
103
- "objectsGroups": [],
104
- "variables": [],
105
- "layouts": [
106
- {
107
- "b": 209,
108
- "disableInputWhenNotFocused": true,
109
- "mangledName": "New_32scene",
110
- "name": "New scene",
111
- "oglFOV": 90,
112
- "oglZFar": 500,
113
- "oglZNear": 1,
114
- "r": 209,
115
- "standardSortMethod": true,
116
- "stopSoundsOnStartup": true,
117
- "title": "",
118
- "v": 209,
119
- "uiSettings": {
120
- "grid": false,
121
- "gridB": 255,
122
- "gridG": 180,
123
- "gridHeight": 32,
124
- "gridOffsetX": 0,
125
- "gridOffsetY": 0,
126
- "gridR": 158,
127
- "gridWidth": 32,
128
- "snap": true,
129
- "windowMask": false,
130
- "zoomFactor": 0.7662
131
- },
132
- "objectsGroups": [],
133
- "variables": [],
134
- "instances": [
135
- {
136
- "angle": 0,
137
- "customSize": false,
138
- "height": 0,
139
- "layer": "",
140
- "locked": false,
141
- "name": "Test",
142
- "persistentUuid": "f65d2b44-652d-4fdf-a603-05e48a9cf5ef",
143
- "width": 0,
144
- "x": 247,
145
- "y": 279,
146
- "zOrder": 1,
147
- "numberProperties": [],
148
- "stringProperties": [],
149
- "initialVariables": []
150
- }
151
- ],
152
- "objects": [
153
- {
154
- "bold": false,
155
- "italic": false,
156
- "name": "Test",
157
- "smoothed": true,
158
- "tags": "",
159
- "type": "TextObject::Text",
160
- "underlined": false,
161
- "variables": [],
162
- "behaviors": [],
163
- "string": "Test exporting via gdcore-tools",
164
- "font": "",
165
- "characterSize": 20,
166
- "color": {
167
- "b": 0,
168
- "g": 0,
169
- "r": 0
170
- }
171
- }
172
- ],
173
- "events": [],
174
- "layers": [
175
- {
176
- "ambientLightColorB": 16,
177
- "ambientLightColorG": 0,
178
- "ambientLightColorR": 0,
179
- "followBaseLayerCamera": false,
180
- "isLightingLayer": false,
181
- "name": "",
182
- "visibility": true,
183
- "cameras": [
184
- {
185
- "defaultSize": true,
186
- "defaultViewport": true,
187
- "height": 0,
188
- "viewportBottom": 1,
189
- "viewportLeft": 0,
190
- "viewportRight": 1,
191
- "viewportTop": 0,
192
- "width": 0
193
- }
194
- ],
195
- "effects": []
196
- }
197
- ],
198
- "behaviorsSharedData": []
199
- }
200
- ],
201
- "externalEvents": [],
202
- "eventsFunctionsExtensions": [],
203
- "externalLayouts": [],
204
- "externalSourceFiles": []
1
+ {
2
+ "firstLayout": "",
3
+ "gdVersion": {
4
+ "build": 99,
5
+ "major": 4,
6
+ "minor": 0,
7
+ "revision": 0
8
+ },
9
+ "properties": {
10
+ "adaptGameResolutionAtRuntime": true,
11
+ "folderProject": false,
12
+ "orientation": "landscape",
13
+ "packageName": "com.example.gamename",
14
+ "projectUuid": "b0ec0124-f3d9-4225-bfb5-60645a43b358",
15
+ "scaleMode": "linear",
16
+ "sizeOnStartupMode": "",
17
+ "useExternalSourceFiles": false,
18
+ "version": "1.0.0",
19
+ "name": "Project",
20
+ "author": "",
21
+ "windowWidth": 800,
22
+ "windowHeight": 600,
23
+ "latestCompilationDirectory": "",
24
+ "maxFPS": 60,
25
+ "minFPS": 20,
26
+ "verticalSync": false,
27
+ "platformSpecificAssets": {},
28
+ "loadingScreen": {
29
+ "showGDevelopSplash": true
30
+ },
31
+ "extensionProperties": [],
32
+ "extensions": [
33
+ {
34
+ "name": "BuiltinObject"
35
+ },
36
+ {
37
+ "name": "BuiltinAudio"
38
+ },
39
+ {
40
+ "name": "BuiltinVariables"
41
+ },
42
+ {
43
+ "name": "BuiltinTime"
44
+ },
45
+ {
46
+ "name": "BuiltinMouse"
47
+ },
48
+ {
49
+ "name": "BuiltinKeyboard"
50
+ },
51
+ {
52
+ "name": "BuiltinJoystick"
53
+ },
54
+ {
55
+ "name": "BuiltinCamera"
56
+ },
57
+ {
58
+ "name": "BuiltinWindow"
59
+ },
60
+ {
61
+ "name": "BuiltinFile"
62
+ },
63
+ {
64
+ "name": "BuiltinNetwork"
65
+ },
66
+ {
67
+ "name": "BuiltinScene"
68
+ },
69
+ {
70
+ "name": "BuiltinAdvanced"
71
+ },
72
+ {
73
+ "name": "Sprite"
74
+ },
75
+ {
76
+ "name": "BuiltinCommonInstructions"
77
+ },
78
+ {
79
+ "name": "BuiltinCommonConversions"
80
+ },
81
+ {
82
+ "name": "BuiltinStringInstructions"
83
+ },
84
+ {
85
+ "name": "BuiltinMathematicalTools"
86
+ },
87
+ {
88
+ "name": "BuiltinExternalLayouts"
89
+ }
90
+ ],
91
+ "platforms": [
92
+ {
93
+ "name": "GDevelop JS platform"
94
+ }
95
+ ],
96
+ "currentPlatform": "GDevelop JS platform"
97
+ },
98
+ "resources": {
99
+ "resources": [],
100
+ "resourceFolders": []
101
+ },
102
+ "objects": [],
103
+ "objectsGroups": [],
104
+ "variables": [],
105
+ "layouts": [
106
+ {
107
+ "b": 209,
108
+ "disableInputWhenNotFocused": true,
109
+ "mangledName": "New_32scene",
110
+ "name": "New scene",
111
+ "oglFOV": 90,
112
+ "oglZFar": 500,
113
+ "oglZNear": 1,
114
+ "r": 209,
115
+ "standardSortMethod": true,
116
+ "stopSoundsOnStartup": true,
117
+ "title": "",
118
+ "v": 209,
119
+ "uiSettings": {
120
+ "grid": false,
121
+ "gridB": 255,
122
+ "gridG": 180,
123
+ "gridHeight": 32,
124
+ "gridOffsetX": 0,
125
+ "gridOffsetY": 0,
126
+ "gridR": 158,
127
+ "gridWidth": 32,
128
+ "snap": true,
129
+ "windowMask": false,
130
+ "zoomFactor": 0.7662
131
+ },
132
+ "objectsGroups": [],
133
+ "variables": [],
134
+ "instances": [
135
+ {
136
+ "angle": 0,
137
+ "customSize": false,
138
+ "height": 0,
139
+ "layer": "",
140
+ "locked": false,
141
+ "name": "Test",
142
+ "persistentUuid": "f65d2b44-652d-4fdf-a603-05e48a9cf5ef",
143
+ "width": 0,
144
+ "x": 247,
145
+ "y": 279,
146
+ "zOrder": 1,
147
+ "numberProperties": [],
148
+ "stringProperties": [],
149
+ "initialVariables": []
150
+ }
151
+ ],
152
+ "objects": [
153
+ {
154
+ "bold": false,
155
+ "italic": false,
156
+ "name": "Test",
157
+ "smoothed": true,
158
+ "tags": "",
159
+ "type": "TextObject::Text",
160
+ "underlined": false,
161
+ "variables": [],
162
+ "behaviors": [],
163
+ "string": "Test exporting via gdcore-tools",
164
+ "font": "",
165
+ "characterSize": 20,
166
+ "color": {
167
+ "b": 0,
168
+ "g": 0,
169
+ "r": 0
170
+ }
171
+ }
172
+ ],
173
+ "events": [],
174
+ "layers": [
175
+ {
176
+ "ambientLightColorB": 16,
177
+ "ambientLightColorG": 0,
178
+ "ambientLightColorR": 0,
179
+ "followBaseLayerCamera": false,
180
+ "isLightingLayer": false,
181
+ "name": "",
182
+ "visibility": true,
183
+ "cameras": [
184
+ {
185
+ "defaultSize": true,
186
+ "defaultViewport": true,
187
+ "height": 0,
188
+ "viewportBottom": 1,
189
+ "viewportLeft": 0,
190
+ "viewportRight": 1,
191
+ "viewportTop": 0,
192
+ "width": 0
193
+ }
194
+ ],
195
+ "effects": []
196
+ }
197
+ ],
198
+ "behaviorsSharedData": []
199
+ }
200
+ ],
201
+ "externalEvents": [],
202
+ "eventsFunctionsExtensions": [],
203
+ "externalLayouts": [],
204
+ "externalSourceFiles": []
205
205
  }
@@ -1,13 +1,13 @@
1
- // Note: for exporting games programatically, look into GDExporter.
2
- // https://github.com/arthuro555/gdexporter
3
-
4
- const loadGD = require("../..");
5
-
6
- let gdTools;
7
- loadGD()
8
- .then((_gdTools) => {
9
- gdTools = _gdTools;
10
- // Load the project file
11
- return gdTools.loadProject("./game.json");
12
- })
13
- .then((project) => gdTools.exportProject(project, "GameExport"));
1
+ // Note: for exporting games programatically, look into GDExporter.
2
+ // https://github.com/arthuro555/gdexporter
3
+
4
+ const loadGD = require("../..");
5
+
6
+ let gdTools;
7
+ loadGD()
8
+ .then((_gdTools) => {
9
+ gdTools = _gdTools;
10
+ // Load the project file
11
+ return gdTools.loadProject("./game.json");
12
+ })
13
+ .then((project) => gdTools.exportProject(project, "GameExport"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gdcore-tools",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
4
4
  "description": "A package that downloads and bootstraps any version of GDevelops Core library",
5
5
  "main": "src/index.js",
6
6
  "repository": {
@@ -27,16 +27,8 @@ const getObjectFunctionCodeNamespace = (
27
27
  };
28
28
 
29
29
  module.exports.makeLoader = (gd) => {
30
- const {
31
- declareInstructionOrExpressionMetadata,
32
- declareBehaviorInstructionOrExpressionMetadata,
33
- declareEventsFunctionParameters,
34
- declareBehaviorMetadata,
35
- declareExtension,
36
- isBehaviorLifecycleEventsFunction,
37
- isExtensionLifecycleEventsFunction,
38
- declareBehaviorPropertiesInstructionAndExpressions,
39
- } = require("./MetadataDeclarationHelpers")(gd);
30
+ const { isExtensionLifecycleEventsFunction } =
31
+ require("./MetadataDeclarationHelpers")(gd);
40
32
 
41
33
  const loader = {};
42
34
 
@@ -135,7 +127,10 @@ module.exports.makeLoader = (gd) => {
135
127
  options
136
128
  ) => {
137
129
  const extension = new gd.PlatformExtension();
138
- declareExtension(extension, eventsFunctionsExtension);
130
+ gd.MetadataDeclarationHelper.declareExtension(
131
+ extension,
132
+ eventsFunctionsExtension
133
+ );
139
134
 
140
135
  const codeNamespacePrefix =
141
136
  "gdjs.evtsExt__" + mangleName(eventsFunctionsExtension.getName());
@@ -168,24 +163,22 @@ module.exports.makeLoader = (gd) => {
168
163
  )
169
164
  )
170
165
  .then(() =>
171
- !gd.MetadataDeclarationHelper
172
- ? Promise.resolve()
173
- : // Generate all objects and their functions
174
- Promise.all(
175
- mapVector(
176
- eventsFunctionsExtension.getEventsBasedObjects(),
177
- (eventsBasedObject) => {
178
- return generateObject(
179
- project,
180
- extension,
181
- eventsFunctionsExtension,
182
- eventsBasedObject,
183
- options,
184
- codeGenerationContext
185
- );
186
- }
187
- )
188
- )
166
+ // Generate all objects and their functions
167
+ Promise.all(
168
+ mapVector(
169
+ eventsFunctionsExtension.getEventsBasedObjects(),
170
+ (eventsBasedObject) => {
171
+ return generateObject(
172
+ project,
173
+ extension,
174
+ eventsFunctionsExtension,
175
+ eventsBasedObject,
176
+ options,
177
+ codeGenerationContext
178
+ );
179
+ }
180
+ )
181
+ )
189
182
  )
190
183
  .then(() =>
191
184
  // Generate all free functions
@@ -204,7 +197,9 @@ module.exports.makeLoader = (gd) => {
204
197
  })
205
198
  )
206
199
  )
207
- .then(() => extension);
200
+ .then((functionInfos) => {
201
+ return extension;
202
+ });
208
203
  };
209
204
 
210
205
  const generateFreeFunction = (
@@ -215,46 +210,28 @@ module.exports.makeLoader = (gd) => {
215
210
  options,
216
211
  codeGenerationContext
217
212
  ) => {
218
- const instructionOrExpression = declareInstructionOrExpressionMetadata(
213
+ const metadataDeclarationHelper = new gd.MetadataDeclarationHelper();
214
+ const { functionMetadata } = generateFreeFunctionMetadata(
215
+ project,
219
216
  extension,
220
217
  eventsFunctionsExtension,
221
- eventsFunction
222
- );
223
- // By convention, first parameter is always the Runtime Scene.
224
- instructionOrExpression.addCodeOnlyParameter("currentScene", "");
225
- declareEventsFunctionParameters(eventsFunction, instructionOrExpression);
226
-
227
- // Hide "lifecycle" functions as they are called automatically by
228
- // the game engine.
229
- if (isExtensionLifecycleEventsFunction(eventsFunction.getName())) {
230
- instructionOrExpression.setHidden();
231
- }
232
-
233
- const codeNamespace = getFreeFunctionCodeNamespace(
234
218
  eventsFunction,
235
- codeGenerationContext.codeNamespacePrefix
219
+ options,
220
+ codeGenerationContext,
221
+ metadataDeclarationHelper
236
222
  );
237
- const functionName = codeNamespace + ".func";
238
-
239
- const codeExtraInformation =
240
- instructionOrExpression.getCodeExtraInformation();
241
- codeExtraInformation
242
- .setIncludeFile(
243
- options.eventsFunctionCodeWriter.getIncludeFileFor(functionName)
244
- )
245
- .setFunctionName(functionName);
246
-
247
- // Always include the extension include files when using a free function.
248
- codeGenerationContext.extensionIncludeFiles.forEach((includeFile) => {
249
- codeExtraInformation.addIncludeFile(includeFile);
250
- });
251
223
 
252
224
  if (!options.skipCodeGeneration) {
253
225
  const includeFiles = new gd.SetString();
254
226
  const eventsFunctionsExtensionCodeGenerator =
255
227
  new gd.EventsFunctionsExtensionCodeGenerator(project);
228
+ const codeNamespace = getFreeFunctionCodeNamespace(
229
+ eventsFunction,
230
+ codeGenerationContext.codeNamespacePrefix
231
+ );
256
232
  const code =
257
233
  eventsFunctionsExtensionCodeGenerator.generateFreeEventsFunctionCompleteCode(
234
+ eventsFunctionsExtension,
258
235
  eventsFunction,
259
236
  codeNamespace,
260
237
  includeFiles,
@@ -271,15 +248,18 @@ module.exports.makeLoader = (gd) => {
271
248
  .toNewVectorString()
272
249
  .toJSArray()
273
250
  .forEach((includeFile) => {
274
- codeExtraInformation.addIncludeFile(includeFile);
251
+ functionMetadata.addIncludeFile(includeFile);
275
252
  });
276
253
 
277
254
  includeFiles.delete();
278
-
279
- return options.eventsFunctionCodeWriter.writeFunctionCode(
280
- functionName,
281
- code
282
- );
255
+ eventsFunctionsExtensionCodeGenerator.delete();
256
+ metadataDeclarationHelper.delete();
257
+
258
+ // TODO Implement an helper function for free function names.
259
+ const functionName = codeNamespace + ".func";
260
+ return options.eventsFunctionCodeWriter
261
+ .writeFunctionCode(functionName, code)
262
+ .then(() => {});
283
263
  } else {
284
264
  // Skip code generation if no events function writer is provided.
285
265
  // This is the case during the "first pass", where all events functions extensions
@@ -289,79 +269,71 @@ module.exports.makeLoader = (gd) => {
289
269
  }
290
270
  };
291
271
 
292
- function generateBehavior(
272
+ const generateFreeFunctionMetadata = (
293
273
  project,
294
274
  extension,
295
275
  eventsFunctionsExtension,
296
- eventsBasedBehavior,
276
+ eventsFunction,
297
277
  options,
298
- codeGenerationContext
299
- ) {
300
- const behaviorMetadata = declareBehaviorMetadata(
301
- extension,
302
- eventsBasedBehavior
278
+ codeGenerationContext,
279
+ metadataDeclarationHelper
280
+ ) => {
281
+ const instructionOrExpression =
282
+ metadataDeclarationHelper.generateFreeFunctionMetadata(
283
+ project,
284
+ extension,
285
+ eventsFunctionsExtension,
286
+ eventsFunction
287
+ );
288
+ const functionName = gd.MetadataDeclarationHelper.getFreeFunctionCodeName(
289
+ eventsFunctionsExtension,
290
+ eventsFunction
303
291
  );
292
+ const functionFile =
293
+ options.eventsFunctionCodeWriter.getIncludeFileFor(functionName);
294
+ instructionOrExpression.setIncludeFile(functionFile);
304
295
 
305
- const eventsFunctionsContainer = eventsBasedBehavior.getEventsFunctions();
306
- const codeNamespace = getBehaviorFunctionCodeNamespace(
307
- eventsBasedBehavior,
308
- codeGenerationContext.codeNamespacePrefix
309
- );
310
- const includeFile =
311
- options.eventsFunctionCodeWriter.getIncludeFileFor(codeNamespace);
312
-
313
- behaviorMetadata.setIncludeFile(includeFile);
314
-
315
- // Always include the extension include files when using a behavior.
296
+ // Always include the extension include files when using a free function.
316
297
  codeGenerationContext.extensionIncludeFiles.forEach((includeFile) => {
317
- behaviorMetadata.addIncludeFile(includeFile);
298
+ instructionOrExpression.addIncludeFile(includeFile);
318
299
  });
319
300
 
301
+ // Skip code generation if no events function writer is provided.
302
+ // This is the case during the "first pass", where all events functions extensions
303
+ // are loaded as extensions but not code generated, as events in functions could
304
+ // themselves be using functions that are not yet available in extensions.
305
+ return {
306
+ functionFile: functionFile,
307
+ functionMetadata: instructionOrExpression,
308
+ };
309
+ };
310
+
311
+ function generateBehavior(
312
+ project,
313
+ extension,
314
+ eventsFunctionsExtension,
315
+ eventsBasedBehavior,
316
+ options,
317
+ codeGenerationContext
318
+ ) {
320
319
  return Promise.resolve().then(() => {
321
320
  const behaviorMethodMangledNames = new gd.MapStringString();
322
-
323
- // Declare the instructions/expressions for properties
324
- declareBehaviorPropertiesInstructionAndExpressions(
325
- behaviorMetadata,
326
- eventsBasedBehavior
321
+ const behaviorMetadata = generateBehaviorMetadata(
322
+ project,
323
+ extension,
324
+ eventsFunctionsExtension,
325
+ eventsBasedBehavior,
326
+ options,
327
+ codeGenerationContext,
328
+ behaviorMethodMangledNames
327
329
  );
328
330
 
329
- // Declare all the behavior functions
330
- mapFor(0, eventsFunctionsContainer.getEventsFunctionsCount(), (i) => {
331
- const eventsFunction = eventsFunctionsContainer.getEventsFunctionAt(i);
332
-
333
- const eventsFunctionMangledName = mangleName(eventsFunction.getName());
334
- behaviorMethodMangledNames.set(
335
- eventsFunction.getName(),
336
- eventsFunctionMangledName
337
- );
338
-
339
- const instructionOrExpression =
340
- declareBehaviorInstructionOrExpressionMetadata(
341
- behaviorMetadata,
342
- eventsBasedBehavior,
343
- eventsFunction
344
- );
345
- declareEventsFunctionParameters(
346
- eventsFunction,
347
- instructionOrExpression
348
- );
349
-
350
- // Hide "lifecycle" methods as they are called automatically by
351
- // the game engine.
352
- if (isBehaviorLifecycleEventsFunction(eventsFunction.getName())) {
353
- instructionOrExpression.setHidden();
354
- }
355
-
356
- const codeExtraInformation =
357
- instructionOrExpression.getCodeExtraInformation();
358
- codeExtraInformation
359
- .setIncludeFile(includeFile)
360
- .setFunctionName(eventsFunctionMangledName);
361
- });
362
-
363
331
  // Generate code for the behavior and its methods
364
332
  if (!options.skipCodeGeneration) {
333
+ const codeNamespace = getBehaviorFunctionCodeNamespace(
334
+ eventsBasedBehavior,
335
+ codeGenerationContext.codeNamespacePrefix
336
+ );
365
337
  const includeFiles = new gd.SetString();
366
338
  const behaviorCodeGenerator = new gd.BehaviorCodeGenerator(project);
367
339
  const code = behaviorCodeGenerator.generateRuntimeBehaviorCompleteCode(
@@ -403,6 +375,41 @@ module.exports.makeLoader = (gd) => {
403
375
  });
404
376
  }
405
377
 
378
+ function generateBehaviorMetadata(
379
+ project,
380
+ extension,
381
+ eventsFunctionsExtension,
382
+ eventsBasedBehavior,
383
+ options,
384
+ codeGenerationContext,
385
+ behaviorMethodMangledNames
386
+ ) {
387
+ const behaviorMetadata =
388
+ gd.MetadataDeclarationHelper.generateBehaviorMetadata(
389
+ project,
390
+ extension,
391
+ eventsFunctionsExtension,
392
+ eventsBasedBehavior,
393
+ behaviorMethodMangledNames
394
+ );
395
+
396
+ const codeNamespace = getBehaviorFunctionCodeNamespace(
397
+ eventsBasedBehavior,
398
+ codeGenerationContext.codeNamespacePrefix
399
+ );
400
+ const includeFile =
401
+ options.eventsFunctionCodeWriter.getIncludeFileFor(codeNamespace);
402
+
403
+ behaviorMetadata.setIncludeFile(includeFile);
404
+
405
+ // Always include the extension include files when using a behavior.
406
+ codeGenerationContext.extensionIncludeFiles.forEach((includeFile) => {
407
+ behaviorMetadata.addIncludeFile(includeFile);
408
+ });
409
+
410
+ return behaviorMetadata;
411
+ }
412
+
406
413
  function generateObject(
407
414
  project,
408
415
  extension,
@@ -0,0 +1,451 @@
1
+ const { mapVector, mapFor } = require("../MapFor");
2
+ const { caseSensitiveSlug } = require("../CaseSensitiveSlug");
3
+
4
+ const mangleName = (name) => {
5
+ return caseSensitiveSlug(name, "_", []);
6
+ };
7
+
8
+ /** Generate the namespace for a free function. */
9
+ const getFreeFunctionCodeNamespace = (eventsFunction, codeNamespacePrefix) => {
10
+ return codeNamespacePrefix + "__" + mangleName(eventsFunction.getName());
11
+ };
12
+
13
+ /** Generate the namespace for a behavior function. */
14
+ const getBehaviorFunctionCodeNamespace = (
15
+ eventsBasedBehavior,
16
+ codeNamespacePrefix
17
+ ) => {
18
+ return codeNamespacePrefix + "__" + mangleName(eventsBasedBehavior.getName());
19
+ };
20
+
21
+ module.exports.makeLoader = (gd) => {
22
+ const {
23
+ declareInstructionOrExpressionMetadata,
24
+ declareBehaviorInstructionOrExpressionMetadata,
25
+ declareEventsFunctionParameters,
26
+ declareBehaviorMetadata,
27
+ declareExtension,
28
+ isBehaviorLifecycleEventsFunction,
29
+ isExtensionLifecycleEventsFunction,
30
+ declareBehaviorPropertiesInstructionAndExpressions,
31
+ } = require("./MetadataDeclarationHelpers")(gd);
32
+
33
+ const loader = {};
34
+
35
+ /**
36
+ * Load all events functions of a project in extensions
37
+ */
38
+ const loadProjectEventsFunctionsExtensions = (
39
+ project,
40
+ eventsFunctionCodeWriter
41
+ ) => {
42
+ return Promise.all(
43
+ // First pass: generate extensions from the events functions extensions,
44
+ // without writing code for the functions. This is useful as events in functions
45
+ // could be using other functions, which would not yet be available as
46
+ // extensions.
47
+ mapFor(0, project.getEventsFunctionsExtensionsCount(), (i) => {
48
+ return loadProjectEventsFunctionsExtension(
49
+ project,
50
+ project.getEventsFunctionsExtensionAt(i),
51
+ { skipCodeGeneration: true, eventsFunctionCodeWriter }
52
+ );
53
+ })
54
+ ).then(() =>
55
+ Promise.all(
56
+ // Second pass: generate extensions, including code.
57
+ mapFor(0, project.getEventsFunctionsExtensionsCount(), (i) => {
58
+ return loadProjectEventsFunctionsExtension(
59
+ project,
60
+ project.getEventsFunctionsExtensionAt(i),
61
+ {
62
+ skipCodeGeneration: false,
63
+ eventsFunctionCodeWriter,
64
+ }
65
+ );
66
+ })
67
+ )
68
+ );
69
+ };
70
+ loader.loadProjectEventsFunctionsExtensions =
71
+ loadProjectEventsFunctionsExtensions;
72
+
73
+ const loadProjectEventsFunctionsExtension = (
74
+ project,
75
+ eventsFunctionsExtension,
76
+ options
77
+ ) => {
78
+ return generateEventsFunctionExtension(
79
+ project,
80
+ eventsFunctionsExtension,
81
+ options
82
+ ).then((extension) => {
83
+ gd.JsPlatform.get().addNewExtension(extension);
84
+ extension.delete();
85
+ });
86
+ };
87
+
88
+ /**
89
+ * Get the list of mandatory include files when using the
90
+ * extension.
91
+ */
92
+ const getExtensionIncludeFiles = (
93
+ project,
94
+ eventsFunctionsExtension,
95
+ options,
96
+ codeNamespacePrefix
97
+ ) => {
98
+ return mapFor(
99
+ 0,
100
+ eventsFunctionsExtension.getEventsFunctionsCount(),
101
+ (i) => {
102
+ const eventsFunction = eventsFunctionsExtension.getEventsFunctionAt(i);
103
+
104
+ if (isExtensionLifecycleEventsFunction(eventsFunction.getName())) {
105
+ const codeNamespace = getFreeFunctionCodeNamespace(
106
+ eventsFunction,
107
+ codeNamespacePrefix
108
+ );
109
+ const functionName = codeNamespace + ".func"; // TODO
110
+
111
+ return options.eventsFunctionCodeWriter.getIncludeFileFor(
112
+ functionName
113
+ );
114
+ }
115
+
116
+ return null;
117
+ }
118
+ ).filter(Boolean);
119
+ };
120
+
121
+ /**
122
+ * Generate the code for the events based extension
123
+ */
124
+ const generateEventsFunctionExtension = (
125
+ project,
126
+ eventsFunctionsExtension,
127
+ options
128
+ ) => {
129
+ const extension = new gd.PlatformExtension();
130
+ declareExtension(extension, eventsFunctionsExtension);
131
+
132
+ const codeNamespacePrefix =
133
+ "gdjs.evtsExt__" + mangleName(eventsFunctionsExtension.getName());
134
+
135
+ const extensionIncludeFiles = getExtensionIncludeFiles(
136
+ project,
137
+ eventsFunctionsExtension,
138
+ options,
139
+ codeNamespacePrefix
140
+ );
141
+ const codeGenerationContext = {
142
+ codeNamespacePrefix,
143
+ extensionIncludeFiles,
144
+ };
145
+
146
+ return Promise.all(
147
+ // Generate all behaviors and their functions
148
+ mapVector(
149
+ eventsFunctionsExtension.getEventsBasedBehaviors(),
150
+ (eventsBasedBehavior) => {
151
+ return generateBehavior(
152
+ project,
153
+ extension,
154
+ eventsFunctionsExtension,
155
+ eventsBasedBehavior,
156
+ options,
157
+ codeGenerationContext
158
+ );
159
+ }
160
+ )
161
+ )
162
+ .then(() =>
163
+ // Generate all free functions
164
+ Promise.all(
165
+ mapFor(0, eventsFunctionsExtension.getEventsFunctionsCount(), (i) => {
166
+ const eventsFunction =
167
+ eventsFunctionsExtension.getEventsFunctionAt(i);
168
+ return generateFreeFunction(
169
+ project,
170
+ extension,
171
+ eventsFunctionsExtension,
172
+ eventsFunction,
173
+ options,
174
+ codeGenerationContext
175
+ );
176
+ })
177
+ )
178
+ )
179
+ .then(() => extension);
180
+ };
181
+
182
+ const generateFreeFunction = (
183
+ project,
184
+ extension,
185
+ eventsFunctionsExtension,
186
+ eventsFunction,
187
+ options,
188
+ codeGenerationContext
189
+ ) => {
190
+ const instructionOrExpression = declareInstructionOrExpressionMetadata(
191
+ extension,
192
+ eventsFunctionsExtension,
193
+ eventsFunction
194
+ );
195
+ // By convention, first parameter is always the Runtime Scene.
196
+ instructionOrExpression.addCodeOnlyParameter("currentScene", "");
197
+ declareEventsFunctionParameters(eventsFunction, instructionOrExpression);
198
+
199
+ // Hide "lifecycle" functions as they are called automatically by
200
+ // the game engine.
201
+ if (isExtensionLifecycleEventsFunction(eventsFunction.getName())) {
202
+ instructionOrExpression.setHidden();
203
+ }
204
+
205
+ const codeNamespace = getFreeFunctionCodeNamespace(
206
+ eventsFunction,
207
+ codeGenerationContext.codeNamespacePrefix
208
+ );
209
+ const functionName = codeNamespace + ".func";
210
+
211
+ const codeExtraInformation =
212
+ instructionOrExpression.getCodeExtraInformation();
213
+ codeExtraInformation
214
+ .setIncludeFile(
215
+ options.eventsFunctionCodeWriter.getIncludeFileFor(functionName)
216
+ )
217
+ .setFunctionName(functionName);
218
+
219
+ // Always include the extension include files when using a free function.
220
+ codeGenerationContext.extensionIncludeFiles.forEach((includeFile) => {
221
+ codeExtraInformation.addIncludeFile(includeFile);
222
+ });
223
+
224
+ if (!options.skipCodeGeneration) {
225
+ const includeFiles = new gd.SetString();
226
+ const eventsFunctionsExtensionCodeGenerator =
227
+ new gd.EventsFunctionsExtensionCodeGenerator(project);
228
+ const code =
229
+ eventsFunctionsExtensionCodeGenerator.generateFreeEventsFunctionCompleteCode(
230
+ eventsFunction,
231
+ codeNamespace,
232
+ includeFiles,
233
+ // For now, always generate functions for runtime (this disables
234
+ // generation of profiling for groups (see EventsCodeGenerator))
235
+ // as extensions generated can be used either for preview or export.
236
+ true
237
+ );
238
+
239
+ // Add any include file required by the function to the list
240
+ // of include files for this function (so that when used, the "dependencies"
241
+ // are transitively included).
242
+ includeFiles
243
+ .toNewVectorString()
244
+ .toJSArray()
245
+ .forEach((includeFile) => {
246
+ codeExtraInformation.addIncludeFile(includeFile);
247
+ });
248
+
249
+ includeFiles.delete();
250
+
251
+ return options.eventsFunctionCodeWriter.writeFunctionCode(
252
+ functionName,
253
+ code
254
+ );
255
+ } else {
256
+ // Skip code generation if no events function writer is provided.
257
+ // This is the case during the "first pass", where all events functions extensions
258
+ // are loaded as extensions but not code generated, as events in functions could
259
+ // themselves be using functions that are not yet available in extensions.
260
+ return Promise.resolve();
261
+ }
262
+ };
263
+
264
+ function generateBehavior(
265
+ project,
266
+ extension,
267
+ eventsFunctionsExtension,
268
+ eventsBasedBehavior,
269
+ options,
270
+ codeGenerationContext
271
+ ) {
272
+ const behaviorMetadata = declareBehaviorMetadata(
273
+ extension,
274
+ eventsBasedBehavior
275
+ );
276
+
277
+ const eventsFunctionsContainer = eventsBasedBehavior.getEventsFunctions();
278
+ const codeNamespace = getBehaviorFunctionCodeNamespace(
279
+ eventsBasedBehavior,
280
+ codeGenerationContext.codeNamespacePrefix
281
+ );
282
+ const includeFile =
283
+ options.eventsFunctionCodeWriter.getIncludeFileFor(codeNamespace);
284
+
285
+ behaviorMetadata.setIncludeFile(includeFile);
286
+
287
+ // Always include the extension include files when using a behavior.
288
+ codeGenerationContext.extensionIncludeFiles.forEach((includeFile) => {
289
+ behaviorMetadata.addIncludeFile(includeFile);
290
+ });
291
+
292
+ return Promise.resolve().then(() => {
293
+ const behaviorMethodMangledNames = new gd.MapStringString();
294
+
295
+ // Declare the instructions/expressions for properties
296
+ declareBehaviorPropertiesInstructionAndExpressions(
297
+ behaviorMetadata,
298
+ eventsBasedBehavior
299
+ );
300
+
301
+ // Declare all the behavior functions
302
+ mapFor(0, eventsFunctionsContainer.getEventsFunctionsCount(), (i) => {
303
+ const eventsFunction = eventsFunctionsContainer.getEventsFunctionAt(i);
304
+
305
+ const eventsFunctionMangledName = mangleName(eventsFunction.getName());
306
+ behaviorMethodMangledNames.set(
307
+ eventsFunction.getName(),
308
+ eventsFunctionMangledName
309
+ );
310
+
311
+ const instructionOrExpression =
312
+ declareBehaviorInstructionOrExpressionMetadata(
313
+ behaviorMetadata,
314
+ eventsBasedBehavior,
315
+ eventsFunction
316
+ );
317
+ declareEventsFunctionParameters(
318
+ eventsFunction,
319
+ instructionOrExpression
320
+ );
321
+
322
+ // Hide "lifecycle" methods as they are called automatically by
323
+ // the game engine.
324
+ if (isBehaviorLifecycleEventsFunction(eventsFunction.getName())) {
325
+ instructionOrExpression.setHidden();
326
+ }
327
+
328
+ const codeExtraInformation =
329
+ instructionOrExpression.getCodeExtraInformation();
330
+ codeExtraInformation
331
+ .setIncludeFile(includeFile)
332
+ .setFunctionName(eventsFunctionMangledName);
333
+ });
334
+
335
+ // Generate code for the behavior and its methods
336
+ if (!options.skipCodeGeneration) {
337
+ const includeFiles = new gd.SetString();
338
+ const behaviorCodeGenerator = new gd.BehaviorCodeGenerator(project);
339
+ const code = behaviorCodeGenerator.generateRuntimeBehaviorCompleteCode(
340
+ eventsFunctionsExtension.getName(),
341
+ eventsBasedBehavior,
342
+ codeNamespace,
343
+ behaviorMethodMangledNames,
344
+ includeFiles,
345
+
346
+ // For now, always generate functions for runtime (this disables
347
+ // generation of profiling for groups (see EventsCodeGenerator))
348
+ // as extensions generated can be used either for preview or export.
349
+ true
350
+ );
351
+ behaviorCodeGenerator.delete();
352
+ behaviorMethodMangledNames.delete();
353
+
354
+ // Add any include file required by the functions to the list
355
+ // of include files for this behavior (so that when used, the "dependencies"
356
+ // are transitively included).
357
+ includeFiles
358
+ .toNewVectorString()
359
+ .toJSArray()
360
+ .forEach((includeFile) => {
361
+ behaviorMetadata.addIncludeFile(includeFile);
362
+ });
363
+
364
+ includeFiles.delete();
365
+
366
+ return options.eventsFunctionCodeWriter.writeBehaviorCode(
367
+ codeNamespace,
368
+ code
369
+ );
370
+ } else {
371
+ // Skip code generation
372
+ behaviorMethodMangledNames.delete();
373
+ return Promise.resolve();
374
+ }
375
+ });
376
+ }
377
+
378
+ /**
379
+ * Unload all extensions providing events functions of a project
380
+ */
381
+ const unloadProjectEventsFunctionsExtensions = (project) => {
382
+ return Promise.all(
383
+ mapFor(0, project.getEventsFunctionsExtensionsCount(), (i) => {
384
+ gd.JsPlatform.get().removeExtension(
385
+ project.getEventsFunctionsExtensionAt(i).getName()
386
+ );
387
+ })
388
+ );
389
+ };
390
+ loader.unloadProjectEventsFunctionsExtensions =
391
+ unloadProjectEventsFunctionsExtensions;
392
+
393
+ /**
394
+ * Given metadata about an instruction or an expression, tells if this was created
395
+ * from an event function.
396
+ */
397
+ const isAnEventFunctionMetadata = (instructionOrExpression) => {
398
+ const parametersCount = instructionOrExpression.getParametersCount();
399
+ if (parametersCount <= 0) return false;
400
+
401
+ return (
402
+ instructionOrExpression.getParameter(parametersCount - 1).getType() ===
403
+ "eventsFunctionContext"
404
+ );
405
+ };
406
+ loader.isAnEventFunctionMetadata = isAnEventFunctionMetadata;
407
+
408
+ /**
409
+ * Get back the name a function from its type.
410
+ * See also getFreeEventsFunctionType for the reverse operation.
411
+ */
412
+ const getFunctionNameFromType = (type) => {
413
+ const parts = type.split("::");
414
+ if (!parts.length)
415
+ return {
416
+ name: "",
417
+ behaviorName: "",
418
+ extensionName: "",
419
+ };
420
+
421
+ return {
422
+ name: parts[parts.length - 1],
423
+ behaviorName: parts.length > 2 ? parts[1] : undefined,
424
+ extensionName: parts[0],
425
+ };
426
+ };
427
+ loader.getFunctionNameFromType = getFunctionNameFromType;
428
+
429
+ /**
430
+ * Get the type of a Events Function.
431
+ * See also getFunctionNameFromType for the reverse operation.
432
+ */
433
+ const getFreeEventsFunctionType = (extensionName, eventsFunction) => {
434
+ return extensionName + "::" + eventsFunction.getName();
435
+ };
436
+ loader.getFreeEventsFunctionType = getFreeEventsFunctionType;
437
+
438
+ /**
439
+ * Return the index of the first parameter to be shown to the user:
440
+ * * 0 for a behavior "method",
441
+ * * 1 for a free function (as the first parameter is by convention the runtimeScene).
442
+ */
443
+ const getParametersIndexOffset = (isEventsBasedBehaviorMethod) => {
444
+ return isEventsBasedBehaviorMethod
445
+ ? 0 /*In the case of a behavior events function, the first two parameters are by convention the "Object" and "Behavior" */
446
+ : 1; /*In the case of a free events function (i.e: not tied to a behavior), the first parameter is by convention the current scene and is not shown.*/
447
+ };
448
+ loader.getParametersIndexOffset = getParametersIndexOffset;
449
+
450
+ return loader;
451
+ };
package/src/WrappedGD.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const EventEmitter = require("events");
2
2
  const loadExtensions = require("./JsExtensionsLoader/LocalJsExtensionsLoader");
3
3
  const projectLoader = require("./LocalProjectOpener");
4
+ const { makeLoader: makeLegacyLoader } = require("./EventsFunctionsExtensionsLoader/legacy");
4
5
  const { makeLoader } = require("./EventsFunctionsExtensionsLoader/index");
5
6
  const {
6
7
  makeLocalEventsFunctionCodeWriter,
@@ -59,7 +60,9 @@ class WrappedGD extends EventEmitter {
59
60
  })
60
61
  .then(() => {
61
62
  this.fs = assignIn(new this.gd.AbstractFileSystemJS(), makeFS(this.gd));
62
- this.eventsFunctionsLoader = makeLoader(
63
+
64
+ const makeLoaderFunc = (!this.gd.MetadataDeclarationHelper) ? makeLegacyLoader : makeLoader;
65
+ this.eventsFunctionsLoader = makeLoaderFunc(
63
66
  this.gd
64
67
  ).loadProjectEventsFunctionsExtensions;
65
68
  })