mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
64cad25b81 | ||
![]() |
8472e30342 | ||
![]() |
1b7d258727 | ||
![]() |
946b77093d | ||
![]() |
74c882f219 | ||
![]() |
abd417c494 |
@@ -151,7 +151,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
|
||||
|
||||
extension
|
||||
.AddAction("Wait",
|
||||
_("Wait X seconds (experimental)"),
|
||||
_("Wait X seconds"),
|
||||
_("Waits a number of seconds before running "
|
||||
"the next actions (and sub-events)."),
|
||||
_("Wait _PARAM0_ seconds"),
|
||||
|
@@ -28,7 +28,7 @@ module.exports = {
|
||||
extension
|
||||
.setExtensionInformation(
|
||||
'DialogueTree',
|
||||
_('Dialogue Tree (experimental)'),
|
||||
_('Dialogue Tree'),
|
||||
'Handle dialogue trees, made using Yarn Spinner. Useful to make complex dialogues with multiple choices. The Yarn Spinner editor is embedded in GDevelop so you can edit your dialogues without leaving GDevelop.',
|
||||
'Todor Imreorov',
|
||||
'Open source (MIT License)'
|
||||
@@ -36,7 +36,7 @@ module.exports = {
|
||||
.setExtensionHelpPath('/all-features/dialogue-tree')
|
||||
.setCategory('Game mechanic');
|
||||
extension
|
||||
.addInstructionOrExpressionGroupMetadata(_('Dialogue Tree (experimental)'))
|
||||
.addInstructionOrExpressionGroupMetadata(_('Dialogue Tree'))
|
||||
.setIcon('JsPlatform/Extensions/yarn32.png');
|
||||
|
||||
extension
|
||||
|
@@ -28,14 +28,14 @@ module.exports = {
|
||||
extension
|
||||
.setExtensionInformation(
|
||||
'Leaderboards',
|
||||
_('Leaderboards (experimental)'),
|
||||
_('Leaderboards'),
|
||||
_('Allow your game to send scores to your leaderboards.'),
|
||||
'Florian Rival',
|
||||
'Open source (MIT License)'
|
||||
)
|
||||
.setExtensionHelpPath('/all-features/leaderboards')
|
||||
.setCategory('Players')
|
||||
.addInstructionOrExpressionGroupMetadata(_('Leaderboards (experimental)'))
|
||||
.addInstructionOrExpressionGroupMetadata(_('Leaderboards'))
|
||||
.setIcon('JsPlatform/Extensions/leaderboard.svg');
|
||||
|
||||
extension
|
||||
|
@@ -28,7 +28,7 @@ module.exports = {
|
||||
extension
|
||||
.setExtensionInformation(
|
||||
'P2P',
|
||||
_('P2P (experimental)'),
|
||||
_('P2P'),
|
||||
'Allow game instances to communicate remotely using messages sent via WebRTC (P2P).',
|
||||
'Arthur Pacaud (arthuro555)',
|
||||
'MIT'
|
||||
@@ -36,7 +36,7 @@ module.exports = {
|
||||
.setExtensionHelpPath('/all-features/p2p')
|
||||
.setCategory('Network');
|
||||
extension
|
||||
.addInstructionOrExpressionGroupMetadata(_('P2P (experimental)'))
|
||||
.addInstructionOrExpressionGroupMetadata(_('P2P'))
|
||||
.setIcon('JsPlatform/Extensions/p2picon.svg');
|
||||
|
||||
extension
|
||||
|
@@ -28,7 +28,7 @@ module.exports = {
|
||||
extension
|
||||
.setExtensionInformation(
|
||||
'PlayerAuthentication',
|
||||
_('Player Authentication (experimental)'),
|
||||
_('Player Authentication'),
|
||||
_('Allow your game to authenticate players.'),
|
||||
'Florian Rival',
|
||||
'Open source (MIT License)'
|
||||
@@ -36,9 +36,7 @@ module.exports = {
|
||||
.setExtensionHelpPath('/all-features/player-authentication')
|
||||
.setCategory('Players');
|
||||
extension
|
||||
.addInstructionOrExpressionGroupMetadata(
|
||||
_('Player Authentication (experimental)')
|
||||
)
|
||||
.addInstructionOrExpressionGroupMetadata(_('Player Authentication'))
|
||||
.setIcon('JsPlatform/Extensions/authentication.svg');
|
||||
|
||||
extension
|
||||
|
@@ -25,16 +25,18 @@ module.exports = {
|
||||
gd /*: libGDevelop */
|
||||
) {
|
||||
const extension = new gd.PlatformExtension();
|
||||
extension.setExtensionInformation(
|
||||
'TextInput',
|
||||
_('Text Input'),
|
||||
_('A text field the player can type text into.'),
|
||||
'Florian Rival',
|
||||
'MIT'
|
||||
)
|
||||
.setCategory('User interface');
|
||||
extension.addInstructionOrExpressionGroupMetadata(_("Text Input"))
|
||||
.setIcon("JsPlatform/Extensions/text_input.svg");
|
||||
extension
|
||||
.setExtensionInformation(
|
||||
'TextInput',
|
||||
_('Text Input'),
|
||||
_('A text field the player can type text into.'),
|
||||
'Florian Rival',
|
||||
'MIT'
|
||||
)
|
||||
.setCategory('User interface');
|
||||
extension
|
||||
.addInstructionOrExpressionGroupMetadata(_('Text Input'))
|
||||
.setIcon('JsPlatform/Extensions/text_input.svg');
|
||||
|
||||
const textInputObject = new gd.ObjectJsImplementation();
|
||||
// $FlowExpectedError - ignore Flow warning as we're creating an object
|
||||
@@ -275,7 +277,7 @@ module.exports = {
|
||||
const object = extension
|
||||
.addObject(
|
||||
'TextInputObject',
|
||||
_('Text input (experimental)'),
|
||||
_('Text input'),
|
||||
_('A text field the player can type text into.'),
|
||||
'JsPlatform/Extensions/text_input.svg',
|
||||
textInputObject
|
||||
@@ -645,8 +647,7 @@ module.exports = {
|
||||
|
||||
update() {
|
||||
const instance = this._instance;
|
||||
const properties = this._associatedObjectConfiguration
|
||||
.getProperties();
|
||||
const properties = this._associatedObjectConfiguration.getProperties();
|
||||
|
||||
const placeholder =
|
||||
instance.getRawStringProperty('placeholder') ||
|
||||
|
@@ -107,7 +107,7 @@ const defineTileMap = function (
|
||||
.setLabel(_('Atlas image'))
|
||||
.setDescription(
|
||||
_(
|
||||
"Tiled only - not useful for LDtk files. The Atlas image containing the tileset."
|
||||
'Tiled only - not useful for LDtk files. The Atlas image containing the tileset.'
|
||||
)
|
||||
)
|
||||
.setGroup(_('Tiled only: Tileset and Atlas image'))
|
||||
@@ -223,7 +223,12 @@ const defineTileMap = function (
|
||||
'JsPlatform/Extensions/tile_map.svg'
|
||||
)
|
||||
.addParameter('object', _('Tile map'), 'TileMap', false)
|
||||
.addParameter('tilemapResource', _('Tilemap file (Tiled or LDtk)'), '', false)
|
||||
.addParameter(
|
||||
'tilemapResource',
|
||||
_('Tilemap file (Tiled or LDtk)'),
|
||||
'',
|
||||
false
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('isTilemapJsonFile');
|
||||
|
||||
@@ -240,7 +245,12 @@ const defineTileMap = function (
|
||||
'JsPlatform/Extensions/tile_map.svg'
|
||||
)
|
||||
.addParameter('object', _('Tile map'), 'TileMap', false)
|
||||
.addParameter('tilemapResource', _('Tilemap file (Tiled or LDtk)'), '', false)
|
||||
.addParameter(
|
||||
'tilemapResource',
|
||||
_('Tilemap file (Tiled or LDtk)'),
|
||||
'',
|
||||
false
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('setTilemapJsonFile');
|
||||
|
||||
@@ -376,10 +386,7 @@ const defineTileMap = function (
|
||||
'JsPlatform/Extensions/tile_map.svg'
|
||||
)
|
||||
.addParameter('object', _('Tile map'), 'TileMap', false)
|
||||
.useStandardParameters(
|
||||
'number',
|
||||
gd.ParameterOptions.makeNewOptions()
|
||||
)
|
||||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||
.setFunctionName('getLevelndex');
|
||||
|
||||
object
|
||||
@@ -652,7 +659,9 @@ const defineCollisionMask = function (
|
||||
.addExtraInfo('json')
|
||||
.setLabel(_('Tilemap JSON file'))
|
||||
.setDescription(
|
||||
_('This is the JSON file that was saved or exported from Tiled. LDtk is not supported yet for collisions.')
|
||||
_(
|
||||
'This is the JSON file that was saved or exported from Tiled. LDtk is not supported yet for collisions.'
|
||||
)
|
||||
)
|
||||
);
|
||||
objectProperties.set(
|
||||
@@ -771,7 +780,7 @@ const defineCollisionMask = function (
|
||||
const object = extension
|
||||
.addObject(
|
||||
'CollisionMask',
|
||||
_('Tilemap collision mask (experimental)'),
|
||||
_('Tilemap collision mask'),
|
||||
_('Invisible object handling collisions with parts of a tilemap.'),
|
||||
'JsPlatform/Extensions/tile_map_collision_mask32.svg',
|
||||
collisionMaskObject
|
||||
|
@@ -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();
|
||||
|
||||
|
@@ -31,7 +31,6 @@ export type Exporter = {|
|
||||
tabName: React.Node,
|
||||
helpPage: string,
|
||||
disabled?: boolean,
|
||||
experimental?: boolean,
|
||||
key: ExporterKey,
|
||||
exportPipeline: ExportPipeline<any, any, any, any, any>,
|
||||
|};
|
||||
|
@@ -35,10 +35,6 @@ export const getExtraObjectsInformation = (): {
|
||||
},
|
||||
],
|
||||
'BitmapText::BitmapTextObject': [
|
||||
{
|
||||
kind: 'warning',
|
||||
message: t`This object is experimental and not yet complete. It might have bugs or incomplete support in GDevelop, be sure to read the wiki by clicking on help button below.`,
|
||||
},
|
||||
{
|
||||
kind: 'info',
|
||||
message: t`For a pixel type font, you must disable the Smooth checkbox related to your texture in the game resources to disable anti-aliasing.`,
|
||||
|
@@ -243,6 +243,7 @@ export default class SpritesList extends Component<Props, void> {
|
||||
editWith = (externalEditor: ResourceExternalEditor) => {
|
||||
const {
|
||||
project,
|
||||
resourceManagementProps,
|
||||
direction,
|
||||
resourcesLoader,
|
||||
onReplaceByDirection,
|
||||
@@ -271,6 +272,7 @@ export default class SpritesList extends Component<Props, void> {
|
||||
|
||||
externalEditor.edit({
|
||||
project,
|
||||
getStorageProvider: resourceManagementProps.getStorageProvider,
|
||||
resourcesLoader,
|
||||
singleFrame: false,
|
||||
resourceNames,
|
||||
|
@@ -31,7 +31,7 @@ import {
|
||||
} from './Utils/SpriteObjectHelper';
|
||||
import { type EditorProps } from '../EditorProps.flow';
|
||||
import { type ResourceManagementProps } from '../../../ResourcesList/ResourceSource';
|
||||
import { Column, Line } from '../../../UI/Grid';
|
||||
import { Column } from '../../../UI/Grid';
|
||||
import { ResponsiveLineStackLayout } from '../../../UI/Layout';
|
||||
import ScrollView from '../../../UI/ScrollView';
|
||||
import Checkbox from '../../../UI/Checkbox';
|
||||
@@ -41,6 +41,15 @@ import SpacedDismissableTutorialMessage from './SpacedDismissableTutorialMessage
|
||||
|
||||
const gd: libGDevelop = global.gd;
|
||||
|
||||
const styles = {
|
||||
animationLine: {
|
||||
// Use a non standard spacing because:
|
||||
// - The SortableAnimationsList won't work with <Spacer /> or <LargeSpacer /> between elements.
|
||||
// - We need to visually show a difference between animations.
|
||||
marginBottom: 16,
|
||||
},
|
||||
};
|
||||
|
||||
type AnimationProps = {|
|
||||
animation: gdAnimation,
|
||||
id: number,
|
||||
@@ -82,7 +91,7 @@ class Animation extends React.Component<AnimationProps, void> {
|
||||
|
||||
const animationName = animation.getName();
|
||||
return (
|
||||
<Line expand>
|
||||
<div style={styles.animationLine}>
|
||||
<Column expand noMargin>
|
||||
{isAnimationListLocked && (
|
||||
<Column expand noMargin>
|
||||
@@ -132,7 +141,7 @@ class Animation extends React.Component<AnimationProps, void> {
|
||||
);
|
||||
})}
|
||||
</Column>
|
||||
</Line>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@ import { openYarn } from './LocalYarnBridge';
|
||||
import { type ResourceExternalEditor } from './ResourceExternalEditor.flow';
|
||||
import { sendExternalEditorOpened } from '../Utils/Analytics/EventSender';
|
||||
import { t } from '@lingui/macro';
|
||||
import Window from '../Utils/Window';
|
||||
|
||||
/**
|
||||
* This is the list of editors that can be used to edit resources
|
||||
@@ -17,6 +18,14 @@ const editors: Array<ResourceExternalEditor> = [
|
||||
editDisplayName: t`Edit with Piskel`,
|
||||
kind: 'image',
|
||||
edit: options => {
|
||||
const storageProvider = options.getStorageProvider();
|
||||
if (storageProvider.internalName !== 'LocalFile') {
|
||||
Window.showMessageBox(
|
||||
'Piskel is only supported when your project is saved locally. It will be available for Cloud projects in a future version. To use Piskel, save your project on your computer first.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
sendExternalEditorOpened('piskel');
|
||||
return openPiskel(options);
|
||||
},
|
||||
@@ -27,6 +36,14 @@ const editors: Array<ResourceExternalEditor> = [
|
||||
editDisplayName: t`Edit with Jfxr`,
|
||||
kind: 'audio',
|
||||
edit: options => {
|
||||
const storageProvider = options.getStorageProvider();
|
||||
if (storageProvider.internalName !== 'LocalFile') {
|
||||
Window.showMessageBox(
|
||||
'Jfxr is only supported when your project is saved locally. It will be available for Cloud projects in a future version. To use Jfxr, save your project on your computer first.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
sendExternalEditorOpened('jfxr');
|
||||
return openJfxr(options);
|
||||
},
|
||||
@@ -37,6 +54,14 @@ const editors: Array<ResourceExternalEditor> = [
|
||||
editDisplayName: t`Edit with Yarn`,
|
||||
kind: 'json',
|
||||
edit: options => {
|
||||
const storageProvider = options.getStorageProvider();
|
||||
if (storageProvider.internalName !== 'LocalFile') {
|
||||
Window.showMessageBox(
|
||||
'Yarn is only supported when your project is saved locally. It will be available for Cloud projects in a future version. To use Yarn, save your project on your computer first.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
sendExternalEditorOpened('yarn');
|
||||
return openYarn(options);
|
||||
},
|
||||
|
@@ -2,12 +2,14 @@
|
||||
import { type ResourceKind } from './ResourceSource';
|
||||
import ResourcesLoader from '../ResourcesLoader';
|
||||
import { type MessageDescriptor } from '../Utils/i18n/MessageDescriptor.flow';
|
||||
import { type StorageProvider } from '../ProjectsStorage';
|
||||
|
||||
/**
|
||||
* These are the options passed to an external editor to edit one or more resources.
|
||||
*/
|
||||
export type ExternalEditorOpenOptions = {|
|
||||
project: gdProject,
|
||||
getStorageProvider: () => StorageProvider,
|
||||
resourcesLoader: typeof ResourcesLoader,
|
||||
singleFrame?: boolean, // If set to true, edition should be limited to a single frame
|
||||
resourceNames: Array<string>,
|
||||
|
@@ -215,7 +215,12 @@ export default class ResourceSelector extends React.Component<Props, State> {
|
||||
};
|
||||
|
||||
_editWith = (resourceExternalEditor: ResourceExternalEditor) => {
|
||||
const { project, resourcesLoader, resourceKind } = this.props;
|
||||
const {
|
||||
project,
|
||||
resourcesLoader,
|
||||
resourceKind,
|
||||
resourceManagementProps,
|
||||
} = this.props;
|
||||
const { resourceName } = this.state;
|
||||
const resourcesManager = project.getResourcesManager();
|
||||
const initialResource = resourcesManager.getResource(resourceName);
|
||||
@@ -236,6 +241,7 @@ export default class ResourceSelector extends React.Component<Props, State> {
|
||||
}
|
||||
const externalEditorOptions = {
|
||||
project,
|
||||
getStorageProvider: resourceManagementProps.getStorageProvider,
|
||||
resourcesLoader,
|
||||
singleFrame: true,
|
||||
resourceNames,
|
||||
@@ -259,6 +265,7 @@ export default class ResourceSelector extends React.Component<Props, State> {
|
||||
} else if (resourceKind === 'audio') {
|
||||
const externalEditorOptions = {
|
||||
project,
|
||||
getStorageProvider: resourceManagementProps.getStorageProvider,
|
||||
resourcesLoader,
|
||||
resourceNames: [resourceName],
|
||||
extraOptions: {
|
||||
@@ -280,6 +287,7 @@ export default class ResourceSelector extends React.Component<Props, State> {
|
||||
) {
|
||||
const externalEditorOptions = {
|
||||
project,
|
||||
getStorageProvider: resourceManagementProps.getStorageProvider,
|
||||
resourcesLoader,
|
||||
resourceNames: [resourceName],
|
||||
extraOptions: {
|
||||
|
@@ -35,7 +35,7 @@ module.exports = [
|
||||
"languageCode": "ca_ES",
|
||||
"languageName": "Catalan",
|
||||
"languageNativeName": "Català",
|
||||
"translationRatio": 0.27719821162444114
|
||||
"translationRatio": 0.2774962742175857
|
||||
},
|
||||
{
|
||||
"languageCode": "cs_CZ",
|
||||
@@ -77,7 +77,7 @@ module.exports = [
|
||||
"languageCode": "es_ES",
|
||||
"languageName": "Spanish",
|
||||
"languageNativeName": "Español",
|
||||
"translationRatio": 0.98301043219076
|
||||
"translationRatio": 0.9833084947839046
|
||||
},
|
||||
{
|
||||
"languageCode": "fa_IR",
|
||||
@@ -101,7 +101,7 @@ module.exports = [
|
||||
"languageCode": "fr_FR",
|
||||
"languageName": "French",
|
||||
"languageNativeName": "Français",
|
||||
"translationRatio": 0.9812220566318927
|
||||
"translationRatio": 0.9815201192250372
|
||||
},
|
||||
{
|
||||
"languageCode": "ha_HG",
|
||||
@@ -149,7 +149,7 @@ module.exports = [
|
||||
"languageCode": "ja_JP",
|
||||
"languageName": "Japanese",
|
||||
"languageNativeName": "日本語",
|
||||
"translationRatio": 0.980327868852459
|
||||
"translationRatio": 0.9821162444113264
|
||||
},
|
||||
{
|
||||
"languageCode": "ka_GE",
|
||||
@@ -227,7 +227,7 @@ module.exports = [
|
||||
"languageCode": "pt_BR",
|
||||
"languageName": "Brazilian Portuguese",
|
||||
"languageNativeName": "Português brasileiro",
|
||||
"translationRatio": 0.9169895678092399
|
||||
"translationRatio": 0.919672131147541
|
||||
},
|
||||
{
|
||||
"languageCode": "pt_PT",
|
||||
@@ -329,7 +329,7 @@ module.exports = [
|
||||
"languageCode": "vi_VN",
|
||||
"languageName": "Vietnamese",
|
||||
"languageNativeName": "Tiếng Việt",
|
||||
"translationRatio": 0.06140089418777939
|
||||
"translationRatio": 0.1250372578241431
|
||||
},
|
||||
{
|
||||
"languageCode": "yo_NG",
|
||||
@@ -341,7 +341,7 @@ module.exports = [
|
||||
"languageCode": "zh_CN",
|
||||
"languageName": "Chinese Simplified",
|
||||
"languageNativeName": "简化字",
|
||||
"translationRatio": 0.9907600596125187
|
||||
"translationRatio": 0.9921013412816692
|
||||
},
|
||||
{
|
||||
"languageCode": "zh_TW",
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -2,7 +2,7 @@
|
||||
"name": "gdevelop",
|
||||
"productName": "GDevelop 5",
|
||||
"description": "GDevelop 5 IDE - the open-source, cross-platform game engine designed for everyone",
|
||||
"version": "5.1.154",
|
||||
"version": "5.1.155",
|
||||
"author": "GDevelop Team <hello@gdevelop.io>",
|
||||
"license": "MIT",
|
||||
"homepage": "https://gdevelop.io",
|
||||
|
Reference in New Issue
Block a user