mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Fix games crash because of some extensions not included in the generated games
Revert "Fix missing export files by including the free functions of every extension that is actually used (#4672)" (#4746) (commit 93121d1a1c
)
This commit is contained in:
@@ -54,8 +54,8 @@ bool Exporter::ExportWholePixiProject(
|
||||
|
||||
auto usedExtensions = gd::UsedExtensionsFinder::ScanProject(project);
|
||||
|
||||
auto exportProject = [this, &exportedProject, &exportOptions, &helper,
|
||||
&usedExtensions](gd::String exportDir) {
|
||||
auto exportProject = [this, &exportedProject, &exportOptions, &helper](
|
||||
gd::String exportDir) {
|
||||
bool exportForCordova = exportOptions["exportForCordova"];
|
||||
bool exportForFacebookInstantGames =
|
||||
exportOptions["exportForFacebookInstantGames"];
|
||||
@@ -88,8 +88,7 @@ bool Exporter::ExportWholePixiProject(
|
||||
exportedProject.GetLoadingScreen().GetGDevelopLogoStyle(),
|
||||
includesFiles);
|
||||
|
||||
// Export files for free function, object and behaviors
|
||||
helper.ExportFreeFunctionIncludes(exportedProject, includesFiles, usedExtensions);
|
||||
// Export files for object and behaviors
|
||||
helper.ExportObjectAndBehaviorsIncludes(exportedProject, includesFiles);
|
||||
helper.ExportObjectAndBehaviorsRequiredFiles(exportedProject, resourcesFiles);
|
||||
|
||||
|
@@ -41,7 +41,6 @@
|
||||
#include "GDCore/Tools/Log.h"
|
||||
#include "GDJS/Events/CodeGeneration/LayoutCodeGenerator.h"
|
||||
#include "GDJS/Extensions/JsPlatform.h"
|
||||
#include "GDCore/IDE/Events/UsedExtensionsFinder.h"
|
||||
#undef CopyFile // Disable an annoying macro
|
||||
|
||||
namespace {
|
||||
@@ -116,9 +115,7 @@ bool ExporterHelper::ExportProjectForPixiPreview(
|
||||
immutableProject.GetLoadingScreen().GetGDevelopLogoStyle(),
|
||||
includesFiles);
|
||||
|
||||
// Export files for free function, object and behaviors
|
||||
auto usedExtensions = gd::UsedExtensionsFinder::ScanProject(exportedProject);
|
||||
ExportFreeFunctionIncludes(exportedProject, includesFiles, usedExtensions);
|
||||
// Export files for object and behaviors
|
||||
ExportObjectAndBehaviorsIncludes(immutableProject, includesFiles);
|
||||
ExportObjectAndBehaviorsRequiredFiles(immutableProject, resourcesFiles);
|
||||
|
||||
@@ -800,37 +797,6 @@ bool ExporterHelper::ExportIncludesAndLibs(
|
||||
return true;
|
||||
}
|
||||
|
||||
void ExporterHelper::ExportFreeFunctionIncludes(
|
||||
gd::Project &project, std::vector<gd::String> &includesFiles,
|
||||
std::set<gd::String> &usedExtensions) {
|
||||
auto addIncludeFiles = [&](const std::vector<gd::String> &newIncludeFiles) {
|
||||
for (const auto &includeFile : newIncludeFiles) {
|
||||
InsertUnique(includesFiles, includeFile);
|
||||
}
|
||||
};
|
||||
|
||||
for (auto &&usedExtension : usedExtensions) {
|
||||
if (project.HasEventsFunctionsExtensionNamed(usedExtension)) {
|
||||
auto &extension = project.GetEventsFunctionsExtension(usedExtension);
|
||||
|
||||
for (size_t functionIndex = 0;
|
||||
functionIndex < extension.GetEventsFunctionsCount(); functionIndex++) {
|
||||
auto &function = extension.GetEventsFunction(functionIndex);
|
||||
|
||||
gd::String fullType = gd::PlatformExtension::GetEventsFunctionFullType(
|
||||
usedExtension, function.GetName());
|
||||
|
||||
auto metadata = function.IsCondition()
|
||||
? gd::MetadataProvider::GetConditionMetadata(
|
||||
project.GetCurrentPlatform(), fullType)
|
||||
: gd::MetadataProvider::GetActionMetadata(
|
||||
project.GetCurrentPlatform(), fullType);
|
||||
addIncludeFiles(metadata.GetIncludeFiles());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExporterHelper::ExportObjectAndBehaviorsIncludes(
|
||||
const gd::Project &project, std::vector<gd::String> &includesFiles) {
|
||||
auto addIncludeFiles = [&](const std::vector<gd::String> &newIncludeFiles) {
|
||||
|
@@ -247,12 +247,6 @@ class ExporterHelper {
|
||||
bool ExportEffectIncludes(const gd::Project &project,
|
||||
std::vector<gd::String> &includesFiles);
|
||||
|
||||
/**
|
||||
* \brief Add the include files for all free functions from used extensions.
|
||||
*/
|
||||
void ExportFreeFunctionIncludes(gd::Project &project,
|
||||
std::vector<gd::String> &includesFiles,
|
||||
std::set<gd::String> &usedExtensions);
|
||||
/**
|
||||
* \brief Add the include files for all the objects of the project
|
||||
* and their behaviors.
|
||||
|
@@ -43,6 +43,7 @@ type Options = {|
|
||||
|
||||
type CodeGenerationContext = {|
|
||||
codeNamespacePrefix: string,
|
||||
extensionIncludeFiles: Array<string>,
|
||||
|};
|
||||
|
||||
const mangleName = (name: string) => {
|
||||
@@ -144,6 +145,29 @@ const loadProjectEventsFunctionsExtension = (
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the list of mandatory include files when using the
|
||||
* extension.
|
||||
*/
|
||||
const getExtensionIncludeFiles = (
|
||||
project: gdProject,
|
||||
eventsFunctionsExtension: gdEventsFunctionsExtension,
|
||||
options: Options,
|
||||
codeNamespacePrefix: string
|
||||
): Array<string> => {
|
||||
return mapFor(0, eventsFunctionsExtension.getEventsFunctionsCount(), i => {
|
||||
const eventsFunction = eventsFunctionsExtension.getEventsFunctionAt(i);
|
||||
|
||||
const codeNamespace = getFreeFunctionCodeNamespace(
|
||||
eventsFunction,
|
||||
codeNamespacePrefix
|
||||
);
|
||||
const functionName = codeNamespace + '.func'; // TODO
|
||||
|
||||
return options.eventsFunctionCodeWriter.getIncludeFileFor(functionName);
|
||||
}).filter(Boolean);
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate the code for the events based extension
|
||||
*/
|
||||
@@ -158,8 +182,15 @@ const generateEventsFunctionExtension = (
|
||||
const codeNamespacePrefix =
|
||||
'gdjs.evtsExt__' + mangleName(eventsFunctionsExtension.getName());
|
||||
|
||||
const extensionIncludeFiles = getExtensionIncludeFiles(
|
||||
project,
|
||||
eventsFunctionsExtension,
|
||||
options,
|
||||
codeNamespacePrefix
|
||||
);
|
||||
const codeGenerationContext = {
|
||||
codeNamespacePrefix,
|
||||
extensionIncludeFiles,
|
||||
};
|
||||
|
||||
return Promise.all(
|
||||
@@ -215,6 +246,9 @@ const generateEventsFunctionExtension = (
|
||||
)
|
||||
)
|
||||
.then(functionInfos => {
|
||||
if (!options.skipCodeGeneration) {
|
||||
applyFunctionIncludeFilesDependencyTransitivity(functionInfos);
|
||||
}
|
||||
return extension;
|
||||
});
|
||||
};
|
||||
@@ -267,6 +301,11 @@ const generateFreeFunction = (
|
||||
.setIncludeFile(functionFile)
|
||||
.setFunctionName(functionName);
|
||||
|
||||
// Always include the extension include files when using a free function.
|
||||
codeGenerationContext.extensionIncludeFiles.forEach(includeFile => {
|
||||
instructionOrExpression.addIncludeFile(includeFile);
|
||||
});
|
||||
|
||||
if (!options.skipCodeGeneration) {
|
||||
const includeFiles = new gd.SetString();
|
||||
const eventsFunctionsExtensionCodeGenerator = new gd.EventsFunctionsExtensionCodeGenerator(
|
||||
@@ -314,6 +353,65 @@ const generateFreeFunction = (
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Add dependencies between functions according to transitivity.
|
||||
* @param functionInfos free function metadatas
|
||||
*/
|
||||
const applyFunctionIncludeFilesDependencyTransitivity = (
|
||||
functionInfos: Array<{
|
||||
functionFile: string,
|
||||
functionMetadata:
|
||||
| gdInstructionMetadata
|
||||
| gdExpressionMetadata
|
||||
| gdMultipleInstructionMetadata,
|
||||
}>
|
||||
): void => {
|
||||
// Note that the iteration order doesn't matter, for instance for:
|
||||
// a -> b
|
||||
// b -> c
|
||||
// c -> d
|
||||
//
|
||||
// going from a to c:
|
||||
// a -> (b -> c)
|
||||
// b -> c
|
||||
// c -> d
|
||||
//
|
||||
// or from c to a:
|
||||
// a -> b
|
||||
// b -> (c -> d)
|
||||
// c -> d
|
||||
//
|
||||
// give the same result:
|
||||
// a -> (b -> (c -> d))
|
||||
// b -> (c -> d)
|
||||
// c -> d
|
||||
const includeFileSets = functionInfos.map(
|
||||
functionInfo =>
|
||||
new Set(functionInfo.functionMetadata.getIncludeFiles().toJSArray())
|
||||
);
|
||||
// For any function A of the extension...
|
||||
for (let index = 0; index < functionInfos.length; index++) {
|
||||
const includeFiles = includeFileSets[index];
|
||||
const functionIncludeFile = functionInfos[index].functionFile;
|
||||
|
||||
// ...and any function B of the extension...
|
||||
for (let otherIndex = 0; otherIndex < functionInfos.length; otherIndex++) {
|
||||
const otherFunctionMetadata = functionInfos[otherIndex].functionMetadata;
|
||||
const otherIncludeFileSet = includeFileSets[otherIndex];
|
||||
// ...where function B depends on function A...
|
||||
if (otherIncludeFileSet.has(functionIncludeFile)) {
|
||||
// ...add function A dependencies to the function B ones.
|
||||
includeFiles.forEach(includeFile => {
|
||||
if (!otherIncludeFileSet.has(includeFile)) {
|
||||
otherIncludeFileSet.add(includeFile);
|
||||
otherFunctionMetadata.addIncludeFile(includeFile);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function generateBehavior(
|
||||
project: gdProject,
|
||||
extension: gdPlatformExtension,
|
||||
@@ -338,6 +436,11 @@ function generateBehavior(
|
||||
|
||||
behaviorMetadata.setIncludeFile(includeFile);
|
||||
|
||||
// Always include the extension include files when using a behavior.
|
||||
codeGenerationContext.extensionIncludeFiles.forEach(includeFile => {
|
||||
behaviorMetadata.addIncludeFile(includeFile);
|
||||
});
|
||||
|
||||
return Promise.resolve().then(() => {
|
||||
const behaviorMethodMangledNames = new gd.MapStringString();
|
||||
|
||||
@@ -454,6 +557,11 @@ function generateObject(
|
||||
|
||||
objectMetadata.setIncludeFile(includeFile);
|
||||
|
||||
// Always include the extension include files when using an object.
|
||||
codeGenerationContext.extensionIncludeFiles.forEach(includeFile => {
|
||||
objectMetadata.addIncludeFile(includeFile);
|
||||
});
|
||||
|
||||
return Promise.resolve().then(() => {
|
||||
const objectMethodMangledNames = new gd.MapStringString();
|
||||
|
||||
|
Reference in New Issue
Block a user