Compare commits

..

72 Commits

Author SHA1 Message Date
Alex
8c817a4674 Use top bar on mobile to signify version is checkout 2023-12-15 14:10:16 +01:00
Alex
cacd81f233 Add margin to avoid misclicks 2023-12-15 14:09:59 +01:00
AlexandreSi
061da1f02d Remove unused 'saved' status 2023-12-15 12:02:37 +01:00
AlexandreSi
5202a61b0f Prettier 2023-12-15 11:24:59 +01:00
AlexandreSi
3e32f7278e Quit navigating history when checking out latest save 2023-12-15 11:24:59 +01:00
AlexandreSi
3a70315388 Store latest versions instead of just its id 2023-12-15 11:15:47 +01:00
AlexandreSi
5b5db025eb Display bottom border on toolbar when a version is checked out 2023-12-15 10:52:27 +01:00
AlexandreSi
9abad68125 Simplify typing 2023-12-15 10:43:49 +01:00
AlexandreSi
256ce50d98 Add OpenedVersionStatusChip to toolbar 2023-12-15 09:37:49 +01:00
AlexandreSi
5ce68cd257 Store whole version when checking out a version 2023-12-15 09:30:36 +01:00
AlexandreSi
e122c38c19 Reduce padding so that it fits better in the toolbar 2023-12-15 09:05:59 +01:00
AlexandreSi
05a8f084dc Fix loading error 2023-12-15 09:01:34 +01:00
AlexandreSi
930316e121 Add history icon 2023-12-15 09:01:26 +01:00
AlexandreSi
90681c75cd Improve context menu actions 2023-12-15 08:55:50 +01:00
AlexandreSi
1140b1cd37 Create OpenedVersionStatusChip component for the toolbar 2023-12-14 17:55:06 +01:00
AlexandreSi
f992c14893 Display Latest save chip and indicator 2023-12-14 15:37:57 +01:00
AlexandreSi
093df26ba5 Add Status indicator to sub rows 2023-12-14 15:14:42 +01:00
AlexandreSi
5731fe8d2e Highlight correct part of day collapse 2023-12-14 14:46:18 +01:00
AlexandreSi
93b2c7cc5f Display named versions in collapsed day row 2023-12-14 14:22:36 +01:00
AlexandreSi
225a6e199a Remove the Changes Saved chip state when saving 2023-12-14 12:04:47 +01:00
AlexandreSi
c3e587b09e Prevent checking out previous version if unsaved changes in project 2023-12-13 17:36:48 +01:00
AlexandreSi
aa300b2441 Unfold most recent day initially 2023-12-13 17:25:03 +01:00
AlexandreSi
fd8eb03de3 Update current filemetadata lastModifiedDate when saving cloud project name 2023-12-13 17:11:40 +01:00
AlexandreSi
07d45c6be0 Add loader when renaming is ongoing 2023-12-13 17:07:34 +01:00
AlexandreSi
4cb08642b6 Do not ask for confirmation when switching version and there are unsaved changes 2023-12-13 17:07:34 +01:00
AlexandreSi
7685aaf90c Conserve VersionHistory component state across version checking out 2023-12-13 17:07:34 +01:00
AlexandreSi
79983841b7 Add confirmation dialog before restoring cloud project previous version 2023-12-13 17:07:34 +01:00
AlexandreSi
b69e9df277 Improve placeholder messages 2023-12-13 17:07:34 +01:00
AlexandreSi
5945289a2d Add menu items to show version history 2023-12-13 17:07:34 +01:00
AlexandreSi
d4170e324a Disable project sharing when restoring a project 2023-12-13 17:07:34 +01:00
AlexandreSi
6ff69014fc Make the restoration of versions work 2023-12-13 17:07:34 +01:00
AlexandreSi
18898c9a73 Prevent closing of drawer when hitting Esc to cancel version labelling 2023-12-13 17:07:34 +01:00
AlexandreSi
7f347be5df Memoize version history component 2023-12-13 17:07:34 +01:00
AlexandreSi
fd9390e30f Improve fallback state in case of error 2023-12-13 17:07:34 +01:00
AlexandreSi
48143cc8b3 Fix flow 2023-12-13 17:07:34 +01:00
AlexandreSi
d07a463513 Implement version checkout 2023-12-13 17:07:34 +01:00
AlexandreSi
ad209ad035 Add possibility to specify restored from version id 2023-12-13 17:07:34 +01:00
AlexandreSi
38466874e7 Fix possibility to remove version label 2023-12-13 17:07:34 +01:00
AlexandreSi
148f6fc092 Add possibility to rename a version 2023-12-13 17:07:34 +01:00
AlexandreSi
6e5fad024c Update visual feedbacks on rows 2023-12-13 17:07:34 +01:00
AlexandreSi
7be4e7d462 Update version history on project save 2023-12-13 17:07:34 +01:00
AlexandreSi
3b78dafa86 Stabilize the number of version listing API calls 2023-12-13 17:07:34 +01:00
AlexandreSi
add039e90c Implement version pagination 2023-12-13 17:07:34 +01:00
AlexandreSi
100fb7c862 Start implementing version history in editor 2023-12-13 17:07:34 +01:00
AlexandreSi
0547fbf360 Update icon 2023-12-13 17:07:34 +01:00
AlexandreSi
49d19f1ef7 Improve story 2023-12-13 17:07:34 +01:00
AlexandreSi
aa7bc0cf6c Add outline to unsaved changes versions row 2023-12-13 17:07:34 +01:00
AlexandreSi
ba51819c91 Add status chip to project version row 2023-12-13 17:07:34 +01:00
AlexandreSi
43fdc6a872 Use all horizontal space to display label textfield 2023-12-13 17:07:34 +01:00
AlexandreSi
33b442d7e3 Add anonymous avatar when project version has no user 2023-12-13 17:07:33 +01:00
AlexandreSi
232dab4488 Change no more version message UI 2023-12-13 17:07:33 +01:00
AlexandreSi
e3daeaead5 Make whole day row clickable 2023-12-13 17:07:33 +01:00
AlexandreSi
6526b92e88 Add hover effect on project version row 2023-12-13 17:07:33 +01:00
AlexandreSi
755b5cc87e extract project version row in dedicated file 2023-12-13 17:07:33 +01:00
AlexandreSi
daf0852f52 Extract named versions from collapse 2023-12-13 17:07:33 +01:00
AlexandreSi
b540d9e0bd Also rename restored from versions when possible 2023-12-13 17:07:33 +01:00
AlexandreSi
cddd20103c Add fallback anonymous mention if no author 2023-12-13 17:07:33 +01:00
AlexandreSi
84256c3364 Fix restored from version display 2023-12-13 17:07:33 +01:00
AlexandreSi
57134a36c1 Improve date display when long version label 2023-12-13 17:07:33 +01:00
AlexandreSi
62577c9a9a Mention restored from version when applicable 2023-12-13 17:07:33 +01:00
AlexandreSi
f354de912f Add props to checkout version 2023-12-13 17:07:33 +01:00
AlexandreSi
a1e701829d Add flag to mean that all versions were loaded 2023-12-13 17:07:33 +01:00
AlexandreSi
68141bfd87 Add button to load more versions 2023-12-13 17:07:33 +01:00
AlexandreSi
193a743a3f Limit label length 2023-12-13 17:07:33 +01:00
AlexandreSi
6915f41080 Add keyboard shortcuts when editing version label 2023-12-13 17:07:33 +01:00
AlexandreSi
0c4c46a529 Rename version on text field blur 2023-12-13 17:07:33 +01:00
AlexandreSi
3f3da17c72 Add context menu to version history component 2023-12-13 17:07:33 +01:00
AlexandreSi
352ccf00e4 Collapse version under day row 2023-12-13 17:07:33 +01:00
AlexandreSi
f6b8768e07 Group versions by day 2023-12-13 17:07:33 +01:00
AlexandreSi
c76b49bdc2 Start version history component 2023-12-13 17:07:33 +01:00
AlexandreSi
bdca1add48 Refactor User service api client 2023-12-13 17:07:33 +01:00
AlexandreSi
d00a93dedc Update typing 2023-12-13 17:07:33 +01:00
426 changed files with 35927 additions and 29206 deletions

View File

@@ -714,8 +714,6 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
metadata.GetType() == "tilesetResource" ||
metadata.GetType() == "videoResource" ||
metadata.GetType() == "model3DResource" ||
metadata.GetType() == "atlasResource" ||
metadata.GetType() == "spineResource" ||
// Deprecated, old parameter names:
metadata.GetType() == "password" || metadata.GetType() == "musicfile" ||
metadata.GetType() == "soundfile" || metadata.GetType() == "police") {

View File

@@ -1281,8 +1281,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Enable an effect on the object"),
_("Enable effect _PARAM1_ on _PARAM0_: _PARAM2_"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("yesorno", _("Enable?"))
@@ -1297,8 +1297,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"names) in the effects window."),
_("Set _PARAM2_ to _PARAM3_ for effect _PARAM1_ of _PARAM0_"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("objectEffectParameterName", _("Property name"))
@@ -1315,8 +1315,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"names) in the effects window."),
_("Set _PARAM2_ to _PARAM3_ for effect _PARAM1_ of _PARAM0_"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("objectEffectParameterName", _("Property name"))
@@ -1332,8 +1332,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"names) in the effects window."),
_("Enable _PARAM2_ for effect _PARAM1_ of _PARAM0_: _PARAM3_"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("objectEffectParameterName", _("Property name"))
@@ -1347,8 +1347,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Check if the effect on an object is enabled."),
_("Effect _PARAM1_ of _PARAM0_ is enabled"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("objectEffectName", _("Effect name"))
.MarkAsSimple()

View File

@@ -27,7 +27,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
extension.AddInstructionOrExpressionGroupMetadata(_("Layers and cameras"))
.SetIcon("res/conditions/camera24.png");
extension.AddInstructionOrExpressionGroupMetadata(_("Effects"))
.SetIcon("res/actions/effect_black.svg");
.SetIcon("res/actions/effect24.png");
extension
.AddExpressionAndConditionAndAction(
@@ -450,8 +450,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"names) in the effects window."),
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of layer _PARAM1_"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"), "", true)
.SetDefaultValue("\"\"")
@@ -469,8 +469,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"names) in the effects window."),
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of layer _PARAM1_"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"), "", true)
.SetDefaultValue("\"\"")
@@ -488,8 +488,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"names) in the effects window."),
_("Enable _PARAM3_ for effect _PARAM2_ of layer _PARAM1_: _PARAM4_"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"), "", true)
.SetDefaultValue("\"\"")
@@ -504,8 +504,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
_("The effect on a layer is enabled"),
_("Effect _PARAM2_ on layer _PARAM1_ is enabled"),
_(""),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"), "", true)
.SetDefaultValue("\"\"")
@@ -518,8 +518,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
_("Enable an effect on a layer"),
_("Enable effect _PARAM2_ on layer _PARAM1_: _PARAM3_"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"), "", true)
.SetDefaultValue("\"\"")

View File

@@ -24,7 +24,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
"Open source (MIT License)")
.SetExtensionHelpPath("/objects");
extension.AddInstructionOrExpressionGroupMetadata(_("Effects"))
.SetIcon("res/actions/effect_black.svg");
.SetIcon("res/actions/effect24.png");
gd::BehaviorMetadata& aut = extension.AddBehavior(
"EffectBehavior",
@@ -32,7 +32,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
"Effect",
_("Apply visual effects to objects."),
"",
"res/actions/effect_black.svg",
"res/actions/effect24.png",
"EffectBehavior",
std::make_shared<gd::Behavior>(),
std::make_shared<gd::BehaviorsSharedData>())
@@ -43,8 +43,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
_("Enable an effect on the object"),
_("Enable effect _PARAM2_ on _PARAM0_: _PARAM3_"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
.AddParameter("objectEffectName", _("Effect name"))
@@ -58,8 +58,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
"names) in the effects window."),
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of _PARAM0_"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
.AddParameter("objectEffectName", _("Effect name"))
@@ -75,8 +75,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
"names) in the effects window."),
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of _PARAM0_"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
.AddParameter("objectEffectName", _("Effect name"))
@@ -91,8 +91,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
"names) in the effects window."),
_("Enable _PARAM3_ for effect _PARAM2_ of _PARAM0_: _PARAM4_"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
.AddParameter("objectEffectName", _("Effect name"))
@@ -105,8 +105,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
_("Check if the effect on an object is enabled."),
_("Effect _PARAM2_ of _PARAM0_ is enabled"),
_("Effects"),
"res/actions/effect_black.svg",
"res/actions/effect_black.svg")
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
.AddParameter("objectEffectName", _("Effect name"))

View File

@@ -24,7 +24,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFlippableExtension(
"Open source (MIT License)")
.SetExtensionHelpPath("/objects");
extension.AddInstructionOrExpressionGroupMetadata(_("Effects"))
.SetIcon("res/actions/effect_black.svg");
.SetIcon("res/actions/effect24.png");
gd::BehaviorMetadata& aut = extension.AddBehavior(
"FlippableBehavior",

View File

@@ -50,11 +50,11 @@ gd::ExpressionMetadata& ExpressionMetadata::AddParameter(
gd::ParameterMetadata::IsBehavior(type))
// Prefix with the namespace if it's not already there.
&& (supplementaryInformation.find(
PlatformExtension::GetNamespaceSeparator()) == gd::String::npos)
? (supplementaryInformation.empty()
PlatformExtension::GetNamespaceSeparator()) != gd::String::npos)
? supplementaryInformation
: (supplementaryInformation.empty()
? ""
: extensionNamespace + supplementaryInformation)
: supplementaryInformation));
: extensionNamespace + supplementaryInformation)));
// TODO: Assert against supplementaryInformation === "emsc" (when running with
// Emscripten), and warn about a missing argument when calling addParameter.

View File

@@ -68,11 +68,11 @@ InstructionMetadata& InstructionMetadata::AddParameter(
gd::ParameterMetadata::IsBehavior(type))
// Prefix with the namespace if it's not already there.
&& (supplementaryInformation.find(
PlatformExtension::GetNamespaceSeparator()) == gd::String::npos)
? (supplementaryInformation.empty()
PlatformExtension::GetNamespaceSeparator()) != gd::String::npos)
? supplementaryInformation
: (supplementaryInformation.empty()
? ""
: extensionNamespace + supplementaryInformation)
: supplementaryInformation));
: extensionNamespace + supplementaryInformation)));
// TODO: Assert against supplementaryInformation === "emsc" (when running with
// Emscripten), and warn about a missing argument when calling addParameter.

View File

@@ -217,9 +217,7 @@ class GD_CORE_API ValueTypeMetadata {
parameterType == "jsonResource" ||
parameterType == "tilemapResource" ||
parameterType == "tilesetResource" ||
parameterType == "model3DResource" ||
parameterType == "atlasResource" ||
parameterType == "spineResource";
parameterType == "model3DResource";
}
return false;
}

View File

@@ -39,8 +39,7 @@ struct VariableAndItsParent {
};
/**
* \brief Find the last parent (i.e: the variables container) of a node
* representing a variable.
* \brief Find the last parent (i.e: the variables container) of a node representing a variable.
*
* Useful for completions, to know which variables can be entered in a node.
*
@@ -49,12 +48,13 @@ struct VariableAndItsParent {
class GD_CORE_API ExpressionVariableParentFinder
: public ExpressionParser2NodeWorker {
public:
static VariableAndItsParent GetLastParentOfNode(
const gd::Platform& platform,
const gd::ProjectScopedContainers& projectScopedContainers,
gd::ExpressionNode& node) {
gd::ExpressionVariableParentFinder typeFinder(platform,
projectScopedContainers);
gd::ExpressionVariableParentFinder typeFinder(
platform, projectScopedContainers);
node.Visit(typeFinder);
return typeFinder.variableAndItsParent;
}
@@ -70,8 +70,7 @@ class GD_CORE_API ExpressionVariableParentFinder
variableNode(nullptr),
thisIsALegacyPrescopedVariable(false),
bailOutBecauseEmptyVariableName(false),
legacyPrescopedVariablesContainer(nullptr),
variableAndItsParent{} {};
legacyPrescopedVariablesContainer(nullptr){};
void OnVisitSubExpressionNode(SubExpressionNode& node) override {}
void OnVisitOperatorNode(OperatorNode& node) override {}
@@ -136,10 +135,10 @@ class GD_CORE_API ExpressionVariableParentFinder
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
if (node.name.empty() && node.child) {
// A variable accessor should always have a name if it has a child (i.e:
// another accessor). While the parser may have generated an empty name,
// flag this so we avoid finding a wrong parent (and so, run the risk of
// giving wrong autocompletions).
// A variable accessor should always have a name if it has a child (i.e: another accessor).
// While the parser may have generated an empty name,
// flag this so we avoid finding a wrong parent (and so, run the risk of giving
// wrong autocompletions).
bailOutBecauseEmptyVariableName = true;
}
childVariableNames.insert(childVariableNames.begin(), node.name);
@@ -301,8 +300,7 @@ class GD_CORE_API ExpressionVariableParentFinder
const std::vector<gd::String>& childVariableNames,
size_t startIndex = 0) {
if (bailOutBecauseEmptyVariableName)
return {}; // Do not even attempt to find the parent if we had an issue
// when visiting nodes.
return {}; // Do not even attempt to find the parent if we had an issue when visiting nodes.
const gd::Variable* currentVariable = &variable;
@@ -334,8 +332,8 @@ class GD_CORE_API ExpressionVariableParentFinder
}
}
// Return the last parent of the chain of variables (so not the last
// variable but the one before it).
// Return the last parent of the chain of variables (so not the last variable
// but the one before it).
return {.parentVariable = currentVariable};
}
@@ -343,16 +341,14 @@ class GD_CORE_API ExpressionVariableParentFinder
const gd::VariablesContainer& variablesContainer,
const std::vector<gd::String>& childVariableNames) {
if (bailOutBecauseEmptyVariableName)
return {}; // Do not even attempt to find the parent if we had an issue
// when visiting nodes.
return {}; // Do not even attempt to find the parent if we had an issue when visiting nodes.
if (childVariableNames.empty())
return {}; // There is no "parent" to the variables container itself.
const gd::String& firstChildName = *childVariableNames.begin();
const gd::Variable* variable = variablesContainer.Has(firstChildName)
? &variablesContainer.Get(firstChildName)
: nullptr;
const gd::Variable* variable = variablesContainer.Has(firstChildName) ?
&variablesContainer.Get(firstChildName) : nullptr;
if (childVariableNames.size() == 1 || !variable)
return {// Only one child: the parent is the variables container itself.
.parentVariablesContainer = &variablesContainer};

View File

@@ -1,222 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "ObjectAssetSerializer.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h"
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/Project/AssetResourcePathCleaner.h"
#include "GDCore/IDE/Project/ResourcesInUseHelper.h"
#include "GDCore/IDE/Project/ResourcesRenamer.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/CustomBehavior.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Tools/Log.h"
namespace gd {
gd::String
ObjectAssetSerializer::GetObjectExtensionName(const gd::Object &object) {
const gd::String &type = object.GetType();
const auto separatorIndex =
type.find(PlatformExtension::GetNamespaceSeparator());
return separatorIndex != std::string::npos ? type.substr(0, separatorIndex)
: "";
}
void ObjectAssetSerializer::SerializeTo(
gd::Project &project, const gd::Object &object,
const gd::String &objectFullName, SerializerElement &element,
std::map<gd::String, gd::String> &resourcesFileNameMap) {
auto cleanObject = object.Clone();
cleanObject->GetVariables().Clear();
cleanObject->GetEffects().Clear();
for (auto &&behaviorName : cleanObject->GetAllBehaviorNames()) {
cleanObject->RemoveBehavior(behaviorName);
}
gd::String extensionName = GetObjectExtensionName(*cleanObject);
std::map<gd::String, gd::String> resourcesNameReverseMap;
gd::ObjectAssetSerializer::RenameObjectResourceFiles(
project, *cleanObject, "", objectFullName, resourcesFileNameMap,
resourcesNameReverseMap);
element.SetAttribute("id", "");
element.SetAttribute("name", "");
element.SetAttribute("license", "");
if (project.HasEventsFunctionsExtensionNamed(extensionName)) {
auto &extension = project.GetEventsFunctionsExtension(extensionName);
element.SetAttribute("description", extension.GetShortDescription());
}
element.SetAttribute("gdevelopVersion", "");
element.SetAttribute("version", "");
element.SetIntAttribute("animationsCount", 1);
element.SetIntAttribute("maxFramesCount", 1);
// TODO Find the right object dimensions.
element.SetIntAttribute("width", 0);
element.SetIntAttribute("height", 0);
SerializerElement &authorsElement = element.AddChild("authors");
authorsElement.ConsiderAsArrayOf("author");
SerializerElement &tagsElement = element.AddChild("tags");
tagsElement.ConsiderAsArrayOf("tag");
SerializerElement &objectAssetsElement = element.AddChild("objectAssets");
objectAssetsElement.ConsiderAsArrayOf("objectAsset");
SerializerElement &objectAssetElement =
objectAssetsElement.AddChild("objectAsset");
cleanObject->SerializeTo(objectAssetElement.AddChild("object"));
SerializerElement &resourcesElement =
objectAssetElement.AddChild("resources");
resourcesElement.ConsiderAsArrayOf("resource");
auto &resourcesManager = project.GetResourcesManager();
gd::ResourcesInUseHelper resourcesInUse(resourcesManager);
cleanObject->GetConfiguration().ExposeResources(resourcesInUse);
for (auto &&newResourceName : resourcesInUse.GetAllResources()) {
if (newResourceName.length() == 0) {
continue;
}
auto &resource = resourcesManager.GetResource(
resourcesNameReverseMap.find(newResourceName) !=
resourcesNameReverseMap.end()
? resourcesNameReverseMap[newResourceName]
: newResourceName);
SerializerElement &resourceElement = resourcesElement.AddChild("resource");
resource.SerializeTo(resourceElement);
// Override name and file because the project and the asset don't use the
// same one.
resourceElement.SetAttribute("kind", resource.GetKind());
resourceElement.SetAttribute("name", newResourceName);
auto &oldFilePath = resource.GetFile();
resourceElement.SetAttribute("file",
resourcesFileNameMap.find(oldFilePath) !=
resourcesFileNameMap.end()
? resourcesFileNameMap[oldFilePath]
: oldFilePath);
}
SerializerElement &requiredExtensionsElement =
objectAssetElement.AddChild("requiredExtensions");
requiredExtensionsElement.ConsiderAsArrayOf("requiredExtension");
if (project.HasEventsFunctionsExtensionNamed(extensionName)) {
SerializerElement &requiredExtensionElement =
requiredExtensionsElement.AddChild("requiredExtension");
requiredExtensionElement.SetAttribute("extensionName", extensionName);
requiredExtensionElement.SetAttribute("extensionVersion", "1.0.0");
}
// TODO This can be removed when the asset script no longer require it.
SerializerElement &customizationElement =
objectAssetElement.AddChild("customization");
customizationElement.ConsiderAsArrayOf("empty");
}
void ObjectAssetSerializer::RenameObjectResourceFiles(
gd::Project &project, gd::Object &object,
const gd::String &destinationDirectory, const gd::String &objectFullName,
std::map<gd::String, gd::String> &resourcesFileNameMap,
std::map<gd::String, gd::String> &resourcesNameReverseMap) {
gd::AssetResourcePathCleaner assetResourcePathCleaner(
project.GetResourcesManager(), resourcesFileNameMap,
resourcesNameReverseMap);
object.GetConfiguration().ExposeResources(assetResourcePathCleaner);
// Use asset store script naming conventions for sprite resource files.
if (object.GetConfiguration().GetType() == "Sprite") {
gd::SpriteObject &spriteConfiguration =
dynamic_cast<gd::SpriteObject &>(object.GetConfiguration());
std::map<gd::String, gd::String> normalizedFileNames;
for (std::size_t animationIndex = 0;
animationIndex < spriteConfiguration.GetAnimationsCount();
animationIndex++) {
auto &animation = spriteConfiguration.GetAnimation(animationIndex);
auto &direction = animation.GetDirection(0);
const gd::String &animationName =
animation.GetName().empty()
? gd::String::From(animationIndex)
: animation.GetName().FindAndReplace("_", " ", true);
// Search frames that share the same resource.
std::map<gd::String, std::vector<int>> frameIndexes;
for (std::size_t frameIndex = 0; frameIndex < direction.GetSpritesCount();
frameIndex++) {
auto &frame = direction.GetSprite(frameIndex);
if (frameIndexes.find(frame.GetImageName()) == frameIndexes.end()) {
std::vector<int> emptyVector;
frameIndexes[frame.GetImageName()] = emptyVector;
}
auto &indexes = frameIndexes[frame.GetImageName()];
indexes.push_back(frameIndex);
}
for (std::size_t frameIndex = 0; frameIndex < direction.GetSpritesCount();
frameIndex++) {
auto &frame = direction.GetSprite(frameIndex);
auto oldName = frame.GetImageName();
if (normalizedFileNames.find(oldName) != normalizedFileNames.end()) {
gd::LogWarning("The resource \"" + oldName +
"\" is shared by several animations.");
continue;
}
gd::String newName = objectFullName;
if (spriteConfiguration.GetAnimationsCount() > 1) {
newName += "_" + animationName;
}
if (direction.GetSpritesCount() > 1) {
newName += "_";
auto &indexes = frameIndexes[frame.GetImageName()];
for (size_t i = 0; i < indexes.size(); i++) {
newName += gd::String::From(indexes.at(i) + 1);
if (i < indexes.size() - 1) {
newName += ";";
}
}
}
gd::String extension = oldName.substr(oldName.find_last_of("."));
newName += extension;
frame.SetImageName(newName);
normalizedFileNames[oldName] = newName;
}
}
for (std::map<gd::String, gd::String>::const_iterator it =
resourcesFileNameMap.begin();
it != resourcesFileNameMap.end(); ++it) {
if (!it->first.empty()) {
gd::String originFile = it->first;
gd::String destinationFile = it->second;
resourcesFileNameMap[originFile] = normalizedFileNames[destinationFile];
}
}
auto clonedResourcesNameReverseMap = resourcesNameReverseMap;
resourcesNameReverseMap.clear();
for (std::map<gd::String, gd::String>::const_iterator it =
clonedResourcesNameReverseMap.begin();
it != clonedResourcesNameReverseMap.end(); ++it) {
if (!it->first.empty()) {
gd::String newResourceName = it->first;
gd::String oldResourceName = it->second;
resourcesNameReverseMap[normalizedFileNames[newResourceName]] =
oldResourceName;
}
}
}
}
} // namespace gd

View File

@@ -1,64 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include <map>
#include <vector>
#include "GDCore/String.h"
namespace gd {
class Object;
class ExtensionDependency;
class PropertyDescriptor;
class Project;
class Layout;
class ArbitraryResourceWorker;
class InitialInstance;
class SerializerElement;
class EffectsContainer;
class AbstractFileSystem;
} // namespace gd
namespace gd {
/**
* \brief Serialize objects into an asset for the store.
*
* \ingroup IDE
*/
class GD_CORE_API ObjectAssetSerializer {
public:
/**
* \brief Serialize an object into an asset.
*
* \param project The project that contains the object and its resources.
* It's not actually modified.
* \param object The object to serialize as an asset.
* \param objectFullName The object name with spaces instead of PascalCase.
* \param element The element where the asset is serialize.
* \param resourcesFileNameMap The map from project resource file paths to
* asset resource file paths.
*/
static void
SerializeTo(gd::Project &project, const gd::Object &object,
const gd::String &objectFullName, SerializerElement &element,
std::map<gd::String, gd::String> &resourcesFileNameMap);
~ObjectAssetSerializer(){};
private:
ObjectAssetSerializer(){};
static void RenameObjectResourceFiles(
gd::Project &project, gd::Object &object,
const gd::String &destinationDirectory, const gd::String &objectFullName,
std::map<gd::String, gd::String> &resourcesFileNameMap,
std::map<gd::String, gd::String> &resourcesNameReverseMap);
static gd::String GetObjectExtensionName(const gd::Object &object);
};
} // namespace gd

View File

@@ -52,16 +52,6 @@ void ArbitraryResourceWorker::ExposeModel3D(gd::String& resourceName){
// do.
};
void ArbitraryResourceWorker::ExposeAtlas(gd::String& resourceName){
// Nothing to do by default - each child class can define here the action to
// do.
};
void ArbitraryResourceWorker::ExposeSpine(gd::String& resourceName){
// Nothing to do by default - each child class can define here the action to
// do.
};
void ArbitraryResourceWorker::ExposeVideo(gd::String& videoName){
// Nothing to do by default - each child class can define here the action to
// do.
@@ -130,7 +120,6 @@ void ArbitraryResourceWorker::ExposeEmbeddeds(gd::String& resourceName) {
gd::String potentiallyUpdatedTargetResourceName = targetResourceName;
ExposeResourceWithType(targetResource.GetKind(), potentiallyUpdatedTargetResourceName);
ExposeEmbeddeds(potentiallyUpdatedTargetResourceName);
if (potentiallyUpdatedTargetResourceName != targetResourceName) {
// The resource name was renamed. Also update the mapping.
@@ -187,14 +176,6 @@ void ArbitraryResourceWorker::ExposeResourceWithType(
ExposeVideo(resourceName);
return;
}
if (resourceType == "atlas") {
ExposeAtlas(resourceName);
return;
}
if (resourceType == "spine") {
ExposeSpine(resourceName);
return;
}
gd::LogError("Unexpected resource type: " + resourceType + " for: " + resourceName);
return;
}
@@ -263,14 +244,6 @@ bool ResourceWorkerInEventsWorker::DoVisitInstruction(gd::Instruction& instructi
gd::String updatedParameterValue = parameterValue;
worker.ExposeModel3D(updatedParameterValue);
instruction.SetParameter(parameterIndex, updatedParameterValue);
} else if (parameterMetadata.GetType() == "atlasResource") {
gd::String updatedParameterValue = parameterValue;
worker.ExposeAtlas(updatedParameterValue);
instruction.SetParameter(parameterIndex, updatedParameterValue);
} else if (parameterMetadata.GetType() == "spineResource") {
gd::String updatedParameterValue = parameterValue;
worker.ExposeSpine(updatedParameterValue);
instruction.SetParameter(parameterIndex, updatedParameterValue);
}
});

View File

@@ -96,16 +96,6 @@ public:
* \brief Expose a 3D model, which is always a reference to a "model3D" resource.
*/
virtual void ExposeModel3D(gd::String &resourceName);
/**
* \brief Expose an atlas, which is always a reference to a "atlas" resource.
*/
virtual void ExposeAtlas(gd::String &resourceName);
/**
* \brief Expose an spine, which is always a reference to a "spine" resource.
*/
virtual void ExposeSpine(gd::String &resourceName);
/**
* \brief Expose a video, which is always a reference to a "video" resource.
@@ -133,15 +123,14 @@ public:
*/
virtual void ExposeEmbeddeds(gd::String &resourceName);
protected:
gd::ResourcesManager * resourcesManager;
private:
/**
* \brief Expose a resource: resources that have a file are
* exposed as file (see ExposeFile).
*/
void ExposeResource(gd::Resource &resource);
gd::ResourcesManager * resourcesManager;
};
/**

View File

@@ -1,74 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "AssetResourcePathCleaner.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/ResourcesManager.h"
#include "GDCore/String.h"
namespace gd {
void AssetResourcePathCleaner::ExposeImage(gd::String &imageName) {
ExposeResourceAsFile(imageName);
}
void AssetResourcePathCleaner::ExposeAudio(gd::String &audioName) {
ExposeResourceAsFile(audioName);
}
void AssetResourcePathCleaner::ExposeFont(gd::String &fontName) {
ExposeResourceAsFile(fontName);
}
void AssetResourcePathCleaner::ExposeJson(gd::String &jsonName) {
ExposeResourceAsFile(jsonName);
}
void AssetResourcePathCleaner::ExposeTilemap(gd::String &tilemapName) {
ExposeResourceAsFile(tilemapName);
}
void AssetResourcePathCleaner::ExposeTileset(gd::String &tilesetName) {
ExposeResourceAsFile(tilesetName);
}
void AssetResourcePathCleaner::ExposeVideo(gd::String &videoName) {
ExposeResourceAsFile(videoName);
}
void AssetResourcePathCleaner::ExposeBitmapFont(gd::String &bitmapFontName) {
ExposeResourceAsFile(bitmapFontName);
}
void AssetResourcePathCleaner::ExposeResourceAsFile(gd::String &resourceName) {
auto &resource = resourcesManager->GetResource(resourceName);
gd::String file = resource.GetFile();
ExposeFile(file);
resourcesNameReverseMap[file] = resourceName;
resourceName = file;
}
void AssetResourcePathCleaner::ExposeFile(gd::String &resourceFilePath) {
size_t slashPos = resourceFilePath.find_last_of("/");
size_t antiSlashPos = resourceFilePath.find_last_of("\\");
size_t baseNamePos =
slashPos == String::npos
? antiSlashPos == String::npos ? 0 : (antiSlashPos + 1)
: antiSlashPos == String::npos ? (slashPos + 1)
: slashPos > antiSlashPos ? (slashPos + 1)
: (antiSlashPos + 1);
gd::String baseName =
baseNamePos != 0
? resourceFilePath.substr(baseNamePos, resourceFilePath.length())
: resourceFilePath;
resourcesFileNameMap[resourceFilePath] = baseName;
resourceFilePath = baseName;
}
} // namespace gd

View File

@@ -1,65 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
#include "GDCore/IDE/Project/ResourcesMergingHelper.h"
#include "GDCore/String.h"
#include <map>
#include <memory>
#include <vector>
namespace gd {
class AbstractFileSystem;
class Project;
} // namespace gd
namespace gd {
/**
* \brief AssetResourcePathCleaner is used when exporting an object as an asset.
* It removes the folder from the path.
*
* \see ArbitraryResourceWorker
*
* \ingroup IDE
*/
class GD_CORE_API AssetResourcePathCleaner : public ArbitraryResourceWorker {
public:
AssetResourcePathCleaner(
gd::ResourcesManager &resourcesManager,
std::map<gd::String, gd::String> &resourcesFileNameMap_,
std::map<gd::String, gd::String> &resourcesNameReverseMap_)
: ArbitraryResourceWorker(resourcesManager),
resourcesFileNameMap(resourcesFileNameMap_),
resourcesNameReverseMap(resourcesNameReverseMap_){};
virtual ~AssetResourcePathCleaner(){};
void ExposeImage(gd::String &imageName) override;
void ExposeAudio(gd::String &audioName) override;
void ExposeFont(gd::String &fontName) override;
void ExposeJson(gd::String &jsonName) override;
void ExposeTilemap(gd::String &tilemapName) override;
void ExposeTileset(gd::String &tilesetName) override;
void ExposeVideo(gd::String &videoName) override;
void ExposeBitmapFont(gd::String &bitmapFontName) override;
void ExposeFile(gd::String &resource) override;
protected:
void ExposeResourceAsFile(gd::String &resourceName);
/**
* New file names that can be accessed by their original name.
*/
std::map<gd::String, gd::String> &resourcesFileNameMap;
/**
* Original resource names that can be accessed by their new name.
*/
std::map<gd::String, gd::String> &resourcesNameReverseMap;
};
} // namespace gd

View File

@@ -79,12 +79,6 @@ public:
virtual void ExposeModel3D(gd::String& otherResourceName) override {
MatchResourceName(otherResourceName);
};
virtual void ExposeAtlas(gd::String& otherResourceName) override {
MatchResourceName(otherResourceName);
};
virtual void ExposeSpine(gd::String& otherResourceName) override {
MatchResourceName(otherResourceName);
};
void MatchResourceName(gd::String& otherResourceName) {
if (otherResourceName == resourceName) matchesResourceName = true;

View File

@@ -3,10 +3,9 @@
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#ifndef PROJECTRESOURCESCOPIER_H
#define PROJECTRESOURCESCOPIER_H
#include "GDCore/String.h"
namespace gd {
class Project;
class AbstractFileSystem;
@@ -48,7 +47,6 @@ class GD_CORE_API ProjectResourcesCopier {
bool updateOriginalProject,
bool preserveAbsoluteFilenames = true,
bool preserveDirectoryStructure = true);
private:
static bool CopyAllResourcesTo(gd::Project& originalProject,
gd::Project& clonedProject,
@@ -59,3 +57,5 @@ private:
};
} // namespace gd
#endif // PROJECTRESOURCESCOPIER_H

View File

@@ -1,25 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "ResourcesInUseHelper.h"
namespace gd {
const std::vector<gd::String> ResourcesInUseHelper::resourceTypes = {
"image", "audio", "font", "json", "tilemap",
"tileset", "video", "bitmapFont", "model3D"};
const std::vector<gd::String> &ResourcesInUseHelper::GetAllResources() {
allResources.clear();
for (auto &&resourceType : gd::ResourcesInUseHelper::resourceTypes) {
for (auto &&resourceName : GetAll(resourceType)) {
allResources.push_back(resourceName);
}
}
return allResources;
}
} // namespace gd

View File

@@ -4,7 +4,9 @@
* reserved. This project is released under the MIT License.
*/
#pragma once
#if defined(GD_IDE_ONLY)
#ifndef IMAGESUSEDINVENTORIZER_H
#define IMAGESUSEDINVENTORIZER_H
#include <set>
#include <vector>
@@ -36,7 +38,6 @@ public:
: gd::ArbitraryResourceWorker(resourcesManager){};
virtual ~ResourcesInUseHelper(){};
const std::vector<gd::String>& GetAllResources();
std::set<gd::String>& GetAllImages() { return GetAll("image"); };
std::set<gd::String>& GetAllAudios() { return GetAll("audio"); };
std::set<gd::String>& GetAllFonts() { return GetAll("font"); };
@@ -46,8 +47,6 @@ public:
std::set<gd::String>& GetAllVideos() { return GetAll("video"); };
std::set<gd::String>& GetAllBitmapFonts() { return GetAll("bitmapFont"); };
std::set<gd::String>& GetAll3DModels() { return GetAll("model3D"); };
std::set<gd::String>& GetAllAtlases() { return GetAll("atlas"); };
std::set<gd::String>& GetAllSpines() { return GetAll("spine"); };
std::set<gd::String>& GetAll(const gd::String& resourceType) {
if (resourceType == "image") return allImages;
if (resourceType == "audio") return allAudios;
@@ -58,8 +57,6 @@ public:
if (resourceType == "video") return allVideos;
if (resourceType == "bitmapFont") return allBitmapFonts;
if (resourceType == "model3D") return allModel3Ds;
if (resourceType == "atlas") return allAtlases;
if (resourceType == "spine") return allSpines;
return emptyResources;
};
@@ -67,42 +64,35 @@ public:
virtual void ExposeFile(gd::String& resource) override{
/*Don't care, we just list resource names*/
};
virtual void ExposeImage(gd::String& resourceName) override {
allImages.insert(resourceName);
virtual void ExposeImage(gd::String& imageResourceName) override {
allImages.insert(imageResourceName);
};
virtual void ExposeAudio(gd::String& resourceName) override {
allAudios.insert(resourceName);
virtual void ExposeAudio(gd::String& audioResourceName) override {
allAudios.insert(audioResourceName);
};
virtual void ExposeFont(gd::String& resourceName) override {
allFonts.insert(resourceName);
virtual void ExposeFont(gd::String& fontResourceName) override {
allFonts.insert(fontResourceName);
};
virtual void ExposeJson(gd::String& resourceName) override {
allJsons.insert(resourceName);
virtual void ExposeJson(gd::String& jsonResourceName) override {
allJsons.insert(jsonResourceName);
};
virtual void ExposeTilemap(gd::String& resourceName) override {
allTilemaps.insert(resourceName);
virtual void ExposeTilemap(gd::String& tilemapResourceName) override {
allTilemaps.insert(tilemapResourceName);
};
virtual void ExposeTileset(gd::String& resourceName) override {
allTilesets.insert(resourceName);
virtual void ExposeTileset(gd::String& tilesetResourceName) override {
allTilesets.insert(tilesetResourceName);
};
virtual void ExposeVideo(gd::String& resourceName) override {
allVideos.insert(resourceName);
virtual void ExposeVideo(gd::String& videoResourceName) override {
allVideos.insert(videoResourceName);
};
virtual void ExposeBitmapFont(gd::String& resourceName) override {
allBitmapFonts.insert(resourceName);
virtual void ExposeBitmapFont(gd::String& bitmapFontResourceName) override {
allBitmapFonts.insert(bitmapFontResourceName);
};
virtual void ExposeModel3D(gd::String& resourceName) override {
allModel3Ds.insert(resourceName);
};
virtual void ExposeAtlas(gd::String& resourceName) override {
allAtlases.insert(resourceName);
};
virtual void ExposeSpine(gd::String& resourceName) override {
allSpines.insert(resourceName);
};
protected:
std::vector<gd::String> allResources;
std::set<gd::String> allImages;
std::set<gd::String> allAudios;
std::set<gd::String> allFonts;
@@ -112,11 +102,10 @@ public:
std::set<gd::String> allVideos;
std::set<gd::String> allBitmapFonts;
std::set<gd::String> allModel3Ds;
std::set<gd::String> allAtlases;
std::set<gd::String> allSpines;
std::set<gd::String> emptyResources;
static const std::vector<gd::String> resourceTypes;
};
} // namespace gd
#endif // IMAGESUSEDINVENTORIZER_H
#endif

View File

@@ -28,7 +28,7 @@ void ResourcesMergingHelper::ExposeFile(gd::String& resourceFilename) {
auto stripToFilenameOnly = [&]() {
fs.MakeAbsolute(resourceFullFilename, baseDirectory);
SetNewFilename(resourceFullFilename, fs.FileNameFrom(resourceFullFilename));
resourceFilename = newFilenames[resourceFullFilename];
resourceFilename = oldFilenames[resourceFullFilename];
};
// if we do not want to preserve the folders at all,
@@ -45,7 +45,7 @@ void ResourcesMergingHelper::ExposeFile(gd::String& resourceFilename) {
gd::String relativeFilename = resourceFullFilename;
if (fs.MakeRelative(relativeFilename, baseDirectory)) {
SetNewFilename(resourceFullFilename, relativeFilename);
resourceFilename = newFilenames[resourceFullFilename];
resourceFilename = oldFilenames[resourceFullFilename];
} else {
// The filename cannot be made relative. Consider that it is absolute.
// Just strip the filename to its file part
@@ -63,7 +63,7 @@ void ResourcesMergingHelper::ExposeFile(gd::String& resourceFilename) {
void ResourcesMergingHelper::SetNewFilename(gd::String oldFilename,
gd::String newFilename) {
if (newFilenames.find(oldFilename) != newFilenames.end()) return;
if (oldFilenames.find(oldFilename) != oldFilenames.end()) return;
// Extract baseName and extension from the new filename
size_t extensionPos = newFilename.find_last_of(".");
@@ -80,13 +80,13 @@ void ResourcesMergingHelper::SetNewFilename(gd::String oldFilename,
gd::NewNameGenerator::Generate(
baseName,
[this, extension](const gd::String& newBaseName) {
return oldFilenames.find(newBaseName + extension) !=
oldFilenames.end();
return newFilenames.find(newBaseName + extension) !=
newFilenames.end();
}) +
extension;
newFilenames[oldFilename] = finalFilename;
oldFilenames[finalFilename] = oldFilename;
oldFilenames[oldFilename] = finalFilename;
newFilenames[finalFilename] = oldFilename;
}
void ResourcesMergingHelper::SetBaseDirectory(

View File

@@ -64,25 +64,19 @@ public:
* the Base Directory.
*/
std::map<gd::String, gd::String>& GetAllResourcesOldAndNewFilename() {
return newFilenames;
return oldFilenames;
};
/**
* Resources merging helper collects all resources filenames and update these
* filenames.
*/
void ExposeFile(gd::String& resource) override;
virtual void ExposeFile(gd::String& resource) override;
protected:
void SetNewFilename(gd::String oldFilename, gd::String newFilename);
/**
* Original file names that can be accessed by their new name.
*/
std::map<gd::String, gd::String> oldFilenames;
/**
* New file names that can be accessed by their original name.
*/
std::map<gd::String, gd::String> newFilenames;
gd::String baseDirectory;
bool preserveDirectoriesStructure; ///< If set to true, the directory

View File

@@ -65,12 +65,6 @@ class ResourcesRenamer : public gd::ArbitraryResourceWorker {
virtual void ExposeModel3D(gd::String& resourceName) override {
RenameIfNeeded(resourceName);
};
virtual void ExposeAtlas(gd::String& resourceName) override {
RenameIfNeeded(resourceName);
};
virtual void ExposeSpine(gd::String& resourceName) override {
RenameIfNeeded(resourceName);
};
private:
void RenameIfNeeded(gd::String& resourceName) {

View File

@@ -80,12 +80,6 @@ private:
void ExposeModel3D(gd::String &resourceName) override {
AddUsedResource(resourceName);
};
void ExposeAtlas(gd::String &resourceName) override {
AddUsedResource(resourceName);
};
void ExposeSpine(gd::String &resourceName) override {
AddUsedResource(resourceName);
};
std::set<gd::String> resourceNames;
};

View File

@@ -16,8 +16,8 @@
#include "GDCore/IDE/Events/BehaviorTypeRenamer.h"
#include "GDCore/IDE/Events/CustomObjectTypeRenamer.h"
#include "GDCore/IDE/Events/EventsBehaviorRenamer.h"
#include "GDCore/IDE/Events/EventsPropertyReplacer.h"
#include "GDCore/IDE/Events/EventsRefactorer.h"
#include "GDCore/IDE/Events/EventsPropertyReplacer.h"
#include "GDCore/IDE/Events/EventsVariableReplacer.h"
#include "GDCore/IDE/Events/ExpressionsParameterMover.h"
#include "GDCore/IDE/Events/ExpressionsRenamer.h"
@@ -138,8 +138,7 @@ void WholeProjectRefactorer::EnsureObjectEventsFunctionsProperParameters(
}
}
VariablesChangeset
WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
VariablesChangeset WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
gd::Project &project,
const gd::SerializerElement &oldSerializedVariablesContainer,
const gd::VariablesContainer &newVariablesContainer) {
@@ -150,9 +149,9 @@ WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
if (oldVariablesContainer.GetPersistentUuid() !=
newVariablesContainer.GetPersistentUuid()) {
gd::LogWarning(_(
"Called ComputeChangesetForVariablesContainer on variables containers "
"that are different - they can't be compared."));
gd::LogWarning(
_("Called ComputeChangesetForVariablesContainer on variables containers "
"that are different - they can't be compared."));
return changeset;
}
@@ -193,11 +192,14 @@ WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
}
void WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
gd::Project &project, const gd::VariablesContainer &newVariablesContainer,
const gd::VariablesChangeset &changeset) {
gd::Project &project,
const gd::VariablesContainer &newVariablesContainer,
const gd::VariablesChangeset& changeset) {
gd::EventsVariableReplacer eventsVariableReplacer(
project.GetCurrentPlatform(), newVariablesContainer,
changeset.oldToNewVariableNames, changeset.removedVariableNames);
project.GetCurrentPlatform(),
newVariablesContainer,
changeset.oldToNewVariableNames,
changeset.removedVariableNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
eventsVariableReplacer);
}
@@ -741,14 +743,14 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
EventsBasedBehavior::GetPropertyExpressionName(newPropertyName));
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {
{oldPropertyName, newPropertyName}};
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {{oldPropertyName, newPropertyName}};
std::unordered_set<gd::String> removedPropertyNames;
gd::EventsPropertyReplacer eventsPropertyReplacer(
project.GetCurrentPlatform(), properties, oldToNewPropertyNames,
removedPropertyNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
eventsPropertyReplacer);
project.GetCurrentPlatform(),
properties,
oldToNewPropertyNames,
removedPropertyNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project, eventsPropertyReplacer);
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
@@ -811,14 +813,14 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorSharedProperty(
EventsBasedBehavior::GetSharedPropertyExpressionName(newPropertyName));
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {
{oldPropertyName, newPropertyName}};
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {{oldPropertyName, newPropertyName}};
std::unordered_set<gd::String> removedPropertyNames;
gd::EventsPropertyReplacer eventsPropertyReplacer(
project.GetCurrentPlatform(), properties, oldToNewPropertyNames,
removedPropertyNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
eventsPropertyReplacer);
project.GetCurrentPlatform(),
properties,
oldToNewPropertyNames,
removedPropertyNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project, eventsPropertyReplacer);
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
@@ -868,14 +870,14 @@ void WholeProjectRefactorer::RenameEventsBasedObjectProperty(
EventsBasedObject::GetPropertyExpressionName(newPropertyName));
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {
{oldPropertyName, newPropertyName}};
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {{oldPropertyName, newPropertyName}};
std::unordered_set<gd::String> removedPropertyNames;
gd::EventsPropertyReplacer eventsPropertyReplacer(
project.GetCurrentPlatform(), properties, oldToNewPropertyNames,
removedPropertyNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
eventsPropertyReplacer);
project.GetCurrentPlatform(),
properties,
oldToNewPropertyNames,
removedPropertyNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project, eventsPropertyReplacer);
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
@@ -1349,6 +1351,7 @@ void WholeProjectRefactorer::DoRenameBehavior(
gd::Project &project, const gd::String &oldBehaviorType,
const gd::String &newBehaviorType,
const gd::ProjectBrowser &projectBrowser) {
// Rename behavior in required behavior properties
auto requiredBehaviorRenamer =
gd::RequiredBehaviorRenamer(oldBehaviorType, newBehaviorType);
@@ -1375,6 +1378,7 @@ void WholeProjectRefactorer::DoRenameBehavior(
void WholeProjectRefactorer::DoRenameObject(
gd::Project &project, const gd::String &oldObjectType,
const gd::String &newObjectType, const gd::ProjectBrowser &projectBrowser) {
// Rename object type in objects lists.
auto customObjectTypeRenamer =
gd::CustomObjectTypeRenamer(oldObjectType, newObjectType);
@@ -1394,8 +1398,7 @@ void WholeProjectRefactorer::DoRenameObject(
void WholeProjectRefactorer::ObjectOrGroupRemovedInLayout(
gd::Project &project, gd::Layout &layout, const gd::String &objectName,
bool isObjectGroup, bool removeEventsAndGroups) {
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
auto projectScopedContainers = gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
// Remove object in the current layout
if (removeEventsAndGroups) {
@@ -1444,8 +1447,7 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
if (oldName == newName || newName.empty() || oldName.empty())
return;
auto projectScopedContainers = gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
auto projectScopedContainers = gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
// Rename object in the current layout
gd::EventsRefactorer::RenameObjectInEvents(
@@ -1534,19 +1536,10 @@ void WholeProjectRefactorer::RenameLayer(gd::Project &project,
const gd::String &newName) {
if (oldName == newName || newName.empty() || oldName.empty())
return;
gd::ProjectElementRenamer projectElementRenamer(project.GetCurrentPlatform(),
"layer", oldName, newName);
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
project, layout, projectElementRenamer);
layout.GetInitialInstances().MoveInstancesToLayer(oldName, newName);
std::vector<gd::String> externalLayoutsNames =
GetAssociatedExternalLayouts(project, layout);
for (gd::String name : externalLayoutsNames) {
auto &externalLayout = project.GetExternalLayout(name);
externalLayout.GetInitialInstances().MoveInstancesToLayer(oldName, newName);
}
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(project, layout,
projectElementRenamer);
}
void WholeProjectRefactorer::RenameLayerEffect(gd::Project &project,
@@ -1559,8 +1552,8 @@ void WholeProjectRefactorer::RenameLayerEffect(gd::Project &project,
gd::ProjectElementRenamer projectElementRenamer(
project.GetCurrentPlatform(), "layerEffectName", oldName, newName);
projectElementRenamer.SetLayerConstraint(layer.GetName());
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
project, layout, projectElementRenamer);
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(project, layout,
projectElementRenamer);
}
void WholeProjectRefactorer::RenameObjectAnimation(gd::Project &project,
@@ -1573,8 +1566,8 @@ void WholeProjectRefactorer::RenameObjectAnimation(gd::Project &project,
gd::ProjectElementRenamer projectElementRenamer(
project.GetCurrentPlatform(), "objectAnimationName", oldName, newName);
projectElementRenamer.SetObjectConstraint(object.GetName());
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
project, layout, projectElementRenamer);
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(project, layout,
projectElementRenamer);
}
void WholeProjectRefactorer::RenameObjectPoint(gd::Project &project,
@@ -1587,8 +1580,8 @@ void WholeProjectRefactorer::RenameObjectPoint(gd::Project &project,
gd::ProjectElementRenamer projectElementRenamer(
project.GetCurrentPlatform(), "objectPointName", oldName, newName);
projectElementRenamer.SetObjectConstraint(object.GetName());
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
project, layout, projectElementRenamer);
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(project, layout,
projectElementRenamer);
}
void WholeProjectRefactorer::RenameObjectEffect(gd::Project &project,
@@ -1601,8 +1594,8 @@ void WholeProjectRefactorer::RenameObjectEffect(gd::Project &project,
gd::ProjectElementRenamer projectElementRenamer(
project.GetCurrentPlatform(), "objectEffectName", oldName, newName);
projectElementRenamer.SetObjectConstraint(object.GetName());
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
project, layout, projectElementRenamer);
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(project, layout,
projectElementRenamer);
}
void WholeProjectRefactorer::ObjectOrGroupRemovedInEventsBasedObject(
@@ -1624,12 +1617,9 @@ void WholeProjectRefactorer::ObjectOrGroupRemovedInEventsFunction(
gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer, const gd::String &objectName,
bool isObjectGroup, bool removeEventsAndGroups) {
// In theory we should pass a ProjectScopedContainers to this function so it
// does not have to construct one. In practice, this is ok because we only
// deal with objects.
auto projectScopedContainers =
gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(
globalObjectsContainer, objectsContainer);
// In theory we should pass a ProjectScopedContainers to this function so it does not have to construct one.
// In practice, this is ok because we only deal with objects.
auto projectScopedContainers = gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(globalObjectsContainer, objectsContainer);
if (removeEventsAndGroups) {
gd::EventsRefactorer::RemoveObjectInEvents(
@@ -1665,12 +1655,9 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer, const gd::String &oldName,
const gd::String &newName, bool isObjectGroup) {
// In theory we should pass a ProjectScopedContainers to this function so it
// does not have to construct one. In practice, this is ok because we only
// deal with objects.
auto projectScopedContainers =
gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(
globalObjectsContainer, objectsContainer);
// In theory we should pass a ProjectScopedContainers to this function so it does not have to construct one.
// In practice, this is ok because we only deal with objects.
auto projectScopedContainers = gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(globalObjectsContainer, objectsContainer);
gd::EventsRefactorer::RenameObjectInEvents(
project.GetCurrentPlatform(), projectScopedContainers,
@@ -1718,7 +1705,7 @@ void WholeProjectRefactorer::GlobalObjectOrGroupRemoved(
if (layout.HasObjectNamed(objectName))
continue;
ObjectOrGroupRemovedInLayout(project, layout, objectName, isObjectGroup,
ObjectOrGroupRemovedInLayout(project, layout, objectName, isObjectGroup,
removeEventsAndGroups);
}
}
@@ -1766,8 +1753,7 @@ size_t WholeProjectRefactorer::GetLayoutAndExternalLayoutLayerInstancesCount(
GetAssociatedExternalLayouts(project, layout);
for (gd::String name : externalLayoutsNames) {
auto &externalLayout = project.GetExternalLayout(name);
count +=
externalLayout.GetInitialInstances().GetLayerInstancesCount(layerName);
count += externalLayout.GetInitialInstances().GetLayerInstancesCount(layerName);
}
return count;
}

View File

@@ -155,10 +155,6 @@ void CustomObjectConfiguration::ExposeResources(gd::ArbitraryResourceWorker& wor
worker.ExposeBitmapFont(newPropertyValue);
} else if (resourceType == "model3D") {
worker.ExposeModel3D(newPropertyValue);
} else if (resourceType == "atlas") {
worker.ExposeAtlas(newPropertyValue);
} else if (resourceType == "spine") {
worker.ExposeSpine(newPropertyValue);
}
if (newPropertyValue != oldPropertyValue) {

View File

@@ -39,7 +39,6 @@ void Layer::SetCameraCount(std::size_t n) {
void Layer::SerializeTo(SerializerElement& element) const {
element.SetAttribute("name", GetName());
element.SetAttribute("renderingType", GetRenderingType());
element.SetAttribute("cameraType", GetCameraType());
element.SetAttribute("visibility", GetVisibility());
element.SetAttribute("isLocked", IsLocked());
element.SetAttribute("isLightingLayer", IsLightingLayer());
@@ -79,7 +78,6 @@ void Layer::SerializeTo(SerializerElement& element) const {
void Layer::UnserializeFrom(const SerializerElement& element) {
SetName(element.GetStringAttribute("name", "", "Name"));
SetRenderingType(element.GetStringAttribute("renderingType", ""));
SetCameraType(element.GetStringAttribute("cameraType", "perspective"));
SetVisibility(element.GetBoolAttribute("visibility", true, "Visibility"));
SetLocked(element.GetBoolAttribute("isLocked", false));
SetLightingLayer(element.GetBoolAttribute("isLightingLayer", false));

View File

@@ -104,17 +104,10 @@ class GD_CORE_API Layer {
const gd::String& GetName() const { return name; }
const gd::String& GetRenderingType() const { return renderingType; }
void SetRenderingType(const gd::String& renderingType_) {
renderingType = renderingType_;
}
const gd::String& GetCameraType() const { return cameraType; }
void SetCameraType(const gd::String& cameraType_) {
cameraType = cameraType_;
}
/**
* \brief Change if layer is displayed or not
*/
@@ -275,7 +268,6 @@ class GD_CORE_API Layer {
gd::String name; ///< The name of the layer
gd::String renderingType; ///< The rendering type: "" (empty), "2d", "3d" or
///< "2d+3d".
gd::String cameraType;
bool isVisible; ///< True if the layer is visible
bool isLocked; ///< True if the layer is locked
bool isLightingLayer; ///< True if the layer is used to display lights and

View File

@@ -30,9 +30,6 @@ void PropertyDescriptor::SerializeTo(SerializerElement& element) const {
extraInformationElement.AddChild("").SetStringValue(information);
}
element.AddChild("hidden").SetBoolValue(hidden);
if (deprecated) {
element.AddChild("deprecated").SetBoolValue(deprecated);
}
}
void PropertyDescriptor::UnserializeFrom(const SerializerElement& element) {
@@ -61,9 +58,6 @@ void PropertyDescriptor::UnserializeFrom(const SerializerElement& element) {
hidden = element.HasChild("hidden")
? element.GetChild("hidden").GetBoolValue()
: false;
deprecated = element.HasChild("deprecated")
? element.GetChild("deprecated").GetBoolValue()
: false;
}
void PropertyDescriptor::SerializeValuesTo(SerializerElement& element) const {

View File

@@ -30,16 +30,12 @@ class GD_CORE_API PropertyDescriptor {
* \param propertyValue The value of the property.
*/
PropertyDescriptor(gd::String propertyValue)
: currentValue(propertyValue), type("string"), label(""), hidden(false),
deprecated(false),
measurementUnit(gd::MeasurementUnit::GetUndefined()) {}
: currentValue(propertyValue), type("string"), label(""), hidden(false), measurementUnit(gd::MeasurementUnit::GetUndefined()) {}
/**
* \brief Empty constructor creating an empty property to be displayed.
*/
PropertyDescriptor()
: hidden(false), deprecated(false),
measurementUnit(gd::MeasurementUnit::GetUndefined()){};
PropertyDescriptor() : hidden(false), measurementUnit(gd::MeasurementUnit::GetUndefined()) {};
/**
* \brief Destructor
@@ -146,19 +142,6 @@ class GD_CORE_API PropertyDescriptor {
*/
bool IsHidden() const { return hidden; }
/**
* \brief Set if the property is deprecated.
*/
PropertyDescriptor& SetDeprecated(bool enable = true) {
deprecated = enable;
return *this;
}
/**
* \brief Check if the property is deprecated.
*/
bool IsDeprecated() const { return deprecated; }
/** \name Serialization
*/
///@{
@@ -196,7 +179,6 @@ class GD_CORE_API PropertyDescriptor {
///< choices, if a property is a displayed as a combo
///< box.
bool hidden;
bool deprecated;
gd::MeasurementUnit measurementUnit; //< The unit of measurement of the property vale.
};

View File

@@ -93,10 +93,6 @@ std::shared_ptr<Resource> ResourcesManager::CreateResource(
return std::make_shared<BitmapFontResource>();
else if (kind == "model3D")
return std::make_shared<Model3DResource>();
else if (kind == "atlas")
return std::make_shared<AtlasResource>();
else if (kind == "spine")
return std::make_shared<SpineResource>();
std::cout << "Bad resource created (type: " << kind << ")" << std::endl;
return std::make_shared<Resource>();
@@ -760,20 +756,6 @@ void Model3DResource::SerializeTo(SerializerElement& element) const {
element.SetAttribute("file", GetFile());
}
void AtlasResource::SetFile(const gd::String& newFile) {
file = NormalizePathSeparator(newFile);
}
void AtlasResource::UnserializeFrom(const SerializerElement& element) {
SetUserAdded(element.GetBoolAttribute("userAdded"));
SetFile(element.GetStringAttribute("file"));
}
void AtlasResource::SerializeTo(SerializerElement& element) const {
element.SetAttribute("userAdded", IsUserAdded());
element.SetAttribute("file", GetFile());
}
ResourceFolder::ResourceFolder(const ResourceFolder& other) { Init(other); }
ResourceFolder& ResourceFolder::operator=(const ResourceFolder& other) {

View File

@@ -373,21 +373,6 @@ class GD_CORE_API JsonResource : public Resource {
gd::String file;
};
/**
* \brief Describe a spine json file used by a project.
*
* \see Resource
* \ingroup ResourcesManagement
*/
class GD_CORE_API SpineResource : public JsonResource {
public:
SpineResource() : JsonResource() { SetKind("spine"); };
virtual ~SpineResource(){};
virtual SpineResource* Clone() const override {
return new SpineResource(*this);
}
};
/**
* \brief Describe a tilemap file used by a project.
*
@@ -522,32 +507,6 @@ class GD_CORE_API Model3DResource : public Resource {
gd::String file;
};
/**
* \brief Describe an atlas file used by a project.
*
* \see Resource
* \ingroup ResourcesManagement
*/
class GD_CORE_API AtlasResource : public Resource {
public:
AtlasResource() : Resource() { SetKind("atlas"); };
virtual ~AtlasResource(){};
virtual AtlasResource* Clone() const override {
return new AtlasResource(*this);
}
virtual const gd::String& GetFile() const override { return file; };
virtual void SetFile(const gd::String& newFile) override;
virtual bool UseFile() const override { return true; }
void SerializeTo(SerializerElement& element) const override;
void UnserializeFrom(const SerializerElement& element) override;
private:
gd::String file;
};
/**
* \brief Inventory all resources used by a project
*

View File

@@ -489,7 +489,7 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
"Effect",
_("Apply visual effects to objects."),
"",
"res/actions/effect_black.svg", "EffectBehavior",
"res/actions/effect24.png", "EffectBehavior",
std::make_shared<gd::Behavior>(),
std::make_shared<gd::BehaviorsSharedData>())
.SetHidden();

View File

@@ -203,23 +203,6 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
auto node = parser.ParseExpression("abcd[0]");
REQUIRE(node != nullptr);
// Also check that if we try to find the last parent of node, it is not defined.
auto lastParentOfNode = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
platform, projectScopedContainers, *node);
REQUIRE(lastParentOfNode.parentVariable == nullptr);
REQUIRE(lastParentOfNode.parentVariablesContainer == nullptr);
gd::ExpressionValidator validator(platform, projectScopedContainers, "string");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 1);
REQUIRE(validator.GetFatalErrors()[0]->GetMessage() ==
"No object, variable or property with this name found.");
REQUIRE(validator.GetFatalErrors()[0]->GetStartPosition() == 0);
}
{
auto node = parser.ParseExpression("abcd[0].efg");
REQUIRE(node != nullptr);
gd::ExpressionValidator validator(platform, projectScopedContainers, "string");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 1);
@@ -231,12 +214,6 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
auto node = parser.ParseExpression("abcd.efg.hij");
REQUIRE(node != nullptr);
// Also check that if we try to find the last parent of node, it is not defined.
auto lastParentOfNode = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
platform, projectScopedContainers, *node);
REQUIRE(lastParentOfNode.parentVariable == nullptr);
REQUIRE(lastParentOfNode.parentVariablesContainer == nullptr);
gd::ExpressionValidator validator(platform, projectScopedContainers, "string");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 1);
@@ -785,12 +762,6 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
auto node = parser.ParseExpression("abcd.efg.hij");
REQUIRE(node != nullptr);
// Also check that if we try to find the last parent of node, it is not defined.
auto lastParentOfNode = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
platform, projectScopedContainers, *node);
REQUIRE(lastParentOfNode.parentVariable == nullptr);
REQUIRE(lastParentOfNode.parentVariablesContainer == nullptr);
gd::ExpressionValidator validator(platform, projectScopedContainers, "number");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 1);
@@ -1524,12 +1495,6 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
auto node =
parser.ParseExpression("MyNonExistingSceneVariable");
// Also check that if we try to find the last parent of node, it is not defined.
auto lastParentOfNode = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
platform, projectScopedContainers, *node);
REQUIRE(lastParentOfNode.parentVariable == nullptr);
REQUIRE(lastParentOfNode.parentVariablesContainer == nullptr);
gd::ExpressionValidator validator(platform, projectScopedContainers, "number|string");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 1);
@@ -1551,25 +1516,6 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
}
}
SECTION("Invalid scene variables (2 levels, variable and child do not exist)") {
{
auto node =
parser.ParseExpression("MyNonExistingSceneVariable.MyNonExistingChild");
// Also check that if we try to find the last parent of node, it is not defined.
auto lastParentOfNode = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
platform, projectScopedContainers, *node);
REQUIRE(lastParentOfNode.parentVariable == nullptr);
REQUIRE(lastParentOfNode.parentVariablesContainer == nullptr);
gd::ExpressionValidator validator(platform, projectScopedContainers, "number|string");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 1);
REQUIRE(validator.GetFatalErrors()[0]->GetMessage() ==
"You must enter a number or a text, wrapped inside double quotes (example: \"Hello world\"), or a variable name.");
}
}
SECTION("Valid object variables (1 level)") {
{
auto node =
@@ -1640,12 +1586,6 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
auto node =
parser.ParseExpression("MyNonExistingSpriteObject.MyVariable");
// Also check that if we try to find the last parent of node, it is not defined.
auto lastParentOfNode = gd::ExpressionVariableParentFinder::GetLastParentOfNode(
platform, projectScopedContainers, *node);
REQUIRE(lastParentOfNode.parentVariable == nullptr);
REQUIRE(lastParentOfNode.parentVariablesContainer == nullptr);
gd::ExpressionValidator validator(platform, projectScopedContainers, "number|string");
node->Visit(validator);
REQUIRE(validator.GetFatalErrors().size() == 1);

View File

@@ -1,148 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
/**
* @file Tests covering common features of GDevelop Core.
*/
#include "GDCore/IDE/ObjectAssetSerializer.h"
#include "DummyPlatform.h"
#include "GDCore/CommonTools.h"
#include "GDCore/Events/Builtin/StandardEvent.h"
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Events/Serialization.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Project/CustomObjectConfiguration.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/Variable.h"
#include "GDCore/Serialization/Serializer.h"
#include "GDCore/Tools/SystemStats.h"
#include "GDCore/Tools/VersionWrapper.h"
#include "catch.hpp"
#include <string>
using namespace gd;
TEST_CASE("ObjectAssetSerializer", "[common]") {
SECTION("Can serialize custom objects as assets") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
auto &eventsExtension =
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
auto &eventsBasedObject = eventsExtension.GetEventsBasedObjects().InsertNew(
"MyEventsBasedObject", 0);
eventsBasedObject.SetFullName("My events based object");
eventsBasedObject.SetDescription("An events based object for test");
eventsBasedObject.InsertNewObject(project, "MyExtension::Sprite", "MyChild",
0);
auto &resourceManager = project.GetResourcesManager();
gd::ImageResource imageResource;
imageResource.SetName("assets/Idle.png");
imageResource.SetFile("assets/Idle.png");
imageResource.SetSmooth(true);
resourceManager.AddResource(imageResource);
gd::Layout &layout = project.InsertNewLayout("Scene", 0);
gd::Object &object = layout.InsertNewObject(
project, "MyEventsExtension::MyEventsBasedObject", "MyObject", 0);
auto &configuration = object.GetConfiguration();
auto *customObjectConfiguration =
dynamic_cast<gd::CustomObjectConfiguration *>(&configuration);
auto *spriteConfiguration = dynamic_cast<gd::SpriteObject *>(
&customObjectConfiguration->GetChildObjectConfiguration("MyChild"));
REQUIRE(spriteConfiguration != nullptr);
{
gd::Animation animation;
animation.SetName("Idle");
animation.SetDirectionsCount(1);
auto &direction = animation.GetDirection(0);
gd::Sprite frame;
frame.SetImageName("assets/Idle.png");
direction.AddSprite(frame);
spriteConfiguration->AddAnimation(animation);
}
SerializerElement assetElement;
std::map<gd::String, gd::String> resourcesFileNameMap;
ObjectAssetSerializer::SerializeTo(project, object, "My Object",
assetElement, resourcesFileNameMap);
// This mapping is used to copy resource files.
REQUIRE(resourcesFileNameMap.find("assets/Idle.png") !=
resourcesFileNameMap.end());
REQUIRE(resourcesFileNameMap["assets/Idle.png"] == "Idle.png");
// Check that the project is left untouched.
REQUIRE(resourceManager.HasResource("assets/Idle.png"));
REQUIRE(resourceManager.GetResource("assets/Idle.png").GetFile() ==
"assets/Idle.png");
REQUIRE(!resourceManager.HasResource("Idle.png"));
REQUIRE(assetElement.HasChild("objectAssets"));
auto &objectAssetsElement = assetElement.GetChild("objectAssets");
objectAssetsElement.ConsiderAsArrayOf("objectAsset");
REQUIRE(objectAssetsElement.GetChildrenCount() == 1);
auto &objectAssetElement = objectAssetsElement.GetChild(0);
REQUIRE(objectAssetElement.HasChild("requiredExtensions"));
auto &requiredExtensionsElement =
objectAssetElement.GetChild("requiredExtensions");
requiredExtensionsElement.ConsiderAsArrayOf("requiredExtension");
REQUIRE(requiredExtensionsElement.GetChildrenCount() == 1);
auto &requiredExtensionElement = requiredExtensionsElement.GetChild(0);
REQUIRE(requiredExtensionElement.GetStringAttribute("extensionName") ==
"MyEventsExtension");
// Resources are renamed according to asset script naming conventions.
REQUIRE(objectAssetElement.HasChild("resources"));
auto &resourcesElement = objectAssetElement.GetChild("resources");
resourcesElement.ConsiderAsArrayOf("resource");
REQUIRE(resourcesElement.GetChildrenCount() == 1);
{
auto &resourceElement = resourcesElement.GetChild(0);
REQUIRE(resourceElement.GetStringAttribute("name") == "Idle.png");
REQUIRE(resourceElement.GetStringAttribute("file") == "Idle.png");
REQUIRE(resourceElement.GetStringAttribute("kind") == "image");
REQUIRE(resourceElement.GetBoolAttribute("smoothed") == true);
}
// Resources used in object configuration are updated.
REQUIRE(objectAssetElement.HasChild("object"));
auto &objectElement = objectAssetElement.GetChild("object");
REQUIRE(objectElement.GetStringAttribute("name") == "MyObject");
REQUIRE(objectElement.GetStringAttribute("type") ==
"MyEventsExtension::MyEventsBasedObject");
auto &childrenContentElement = objectElement.GetChild("childrenContent");
REQUIRE(childrenContentElement.HasChild("MyChild"));
auto &childElement = childrenContentElement.GetChild("MyChild");
REQUIRE(childElement.HasChild("animations"));
auto &animationsElement = childElement.GetChild("animations");
animationsElement.ConsiderAsArrayOf("animation");
REQUIRE(animationsElement.GetChildrenCount() == 1);
auto &animationElement = animationsElement.GetChild(0);
REQUIRE(animationElement.GetStringAttribute("name") == "Idle");
auto &directionsElement = animationElement.GetChild("directions");
directionsElement.ConsiderAsArrayOf("direction");
REQUIRE(directionsElement.GetChildrenCount() == 1);
auto &directionElement = directionsElement.GetChild(0);
auto &spritesElement = directionElement.GetChild("sprites");
spritesElement.ConsiderAsArrayOf("sprite");
REQUIRE(spritesElement.GetChildrenCount() == 1);
auto &spriteElement = spritesElement.GetChild(0);
REQUIRE(spriteElement.GetStringAttribute("image") == "Idle.png");
}
}

View File

@@ -3474,72 +3474,6 @@ TEST_CASE("RenameLayer", "[common]") {
"MyExtension::CameraCenterX(\"layerA\")");
}
SECTION("Renaming a layer also moves the instances on this layer and of the associated external layouts") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &layout = project.InsertNewLayout("My layout", 0);
auto &otherLayout = project.InsertNewLayout("My other layout", 1);
layout.InsertNewLayer("My layer", 0);
otherLayout.InsertNewLayer("My layer", 0);
auto &externalLayout =
project.InsertNewExternalLayout("My external layout", 0);
auto &otherExternalLayout =
project.InsertNewExternalLayout("My other external layout", 0);
externalLayout.SetAssociatedLayout("My layout");
otherExternalLayout.SetAssociatedLayout("My other layout");
auto &initialInstances = layout.GetInitialInstances();
auto &initialInstance1 = initialInstances.InsertNewInitialInstance();
initialInstance1.SetLayer("My layer");
auto &initialInstance2 = initialInstances.InsertNewInitialInstance();
initialInstance2.SetLayer("My layer");
auto &initialInstance3 = initialInstances.InsertNewInitialInstance();
initialInstance3.SetLayer("");
auto &externalInitialInstances = externalLayout.GetInitialInstances();
auto &externalInitialInstance1 = externalInitialInstances.InsertNewInitialInstance();
externalInitialInstance1.SetLayer("My layer");
auto &externalInitialInstance2 = externalInitialInstances.InsertNewInitialInstance();
externalInitialInstance2.SetLayer("My layer");
auto &externalInitialInstance3 = externalInitialInstances.InsertNewInitialInstance();
externalInitialInstance3.SetLayer("");
auto &otherInitialInstances = otherLayout.GetInitialInstances();
auto &otherInitialInstance1 = otherInitialInstances.InsertNewInitialInstance();
otherInitialInstance1.SetLayer("My layer");
auto &otherExternalInitialInstances = otherExternalLayout.GetInitialInstances();
auto &otherExternalInitialInstance1 = otherExternalInitialInstances.InsertNewInitialInstance();
otherExternalInitialInstance1.SetLayer("My layer");
REQUIRE(initialInstance1.GetLayer() == "My layer");
REQUIRE(initialInstance2.GetLayer() == "My layer");
REQUIRE(initialInstance3.GetLayer() == "");
REQUIRE(externalInitialInstance1.GetLayer() == "My layer");
REQUIRE(externalInitialInstance2.GetLayer() == "My layer");
REQUIRE(externalInitialInstance3.GetLayer() == "");
REQUIRE(otherInitialInstance1.GetLayer() == "My layer");
REQUIRE(otherExternalInitialInstance1.GetLayer() == "My layer");
gd::WholeProjectRefactorer::RenameLayer(project, layout, "My layer", "My new layer");
// Instances on the renamed layer are moved to the new layer.
REQUIRE(initialInstance1.GetLayer() == "My new layer");
REQUIRE(initialInstance2.GetLayer() == "My new layer");
REQUIRE(initialInstance3.GetLayer() == "");
// Instances on the renamed layer of external layouts are moved to the new layer.
REQUIRE(externalInitialInstance1.GetLayer() == "My new layer");
REQUIRE(externalInitialInstance2.GetLayer() == "My new layer");
REQUIRE(externalInitialInstance3.GetLayer() == "");
// Instances on the renamed layer of other layouts & external layouts are not moved.
REQUIRE(otherInitialInstance1.GetLayer() == "My layer");
REQUIRE(otherExternalInitialInstance1.GetLayer() == "My layer");
}
SECTION("Can rename a layer when a layer parameter is empty") {
gd::Project project;
gd::Platform platform;

View File

@@ -1 +0,0 @@
Spine/pixi-spine

View File

@@ -247,7 +247,7 @@ module.exports = {
'Model3DObject',
_('3D Model'),
_('An animated 3D model.'),
'JsPlatform/Extensions/3d_model.svg',
'JsPlatform/Extensions/3d_box.svg',
new gd.Model3DObjectConfiguration()
)
.setCategoryFullName(_('General'))
@@ -2695,7 +2695,7 @@ module.exports = {
}
static getThumbnail(project, resourcesLoader, objectConfiguration) {
return 'JsPlatform/Extensions/3d_model.svg';
return 'JsPlatform/Extensions/3d_box.svg';
}
getOriginX() {

View File

@@ -11,12 +11,7 @@ namespace gdjs {
const layer = runtimeScene.getLayer(layerName);
const layerRenderer = layer.getRenderer();
const threeCamera = layerRenderer.getThreeCamera();
const fov =
threeCamera instanceof THREE.OrthographicCamera
? null
: threeCamera
? threeCamera.fov
: assumedFovIn2D;
const fov = threeCamera ? threeCamera.fov : assumedFovIn2D;
return layer.getCameraZ(fov, cameraIndex);
};
@@ -29,12 +24,7 @@ namespace gdjs {
const layer = runtimeScene.getLayer(layerName);
const layerRenderer = layer.getRenderer();
const threeCamera = layerRenderer.getThreeCamera();
const fov =
threeCamera instanceof THREE.OrthographicCamera
? null
: threeCamera
? threeCamera.fov
: assumedFovIn2D;
const fov = threeCamera ? threeCamera.fov : assumedFovIn2D;
layer.setCameraZ(z, fov, cameraIndex);
};
@@ -223,10 +213,8 @@ namespace gdjs {
const layerRenderer = layer.getRenderer();
const threeCamera = layerRenderer.getThreeCamera();
if (!threeCamera) return assumedFovIn2D;
return threeCamera instanceof THREE.OrthographicCamera
? 0
: threeCamera.fov;
if (!threeCamera) return 45;
return threeCamera.fov;
};
export const setFov = (
@@ -239,8 +227,7 @@ namespace gdjs {
const layerRenderer = layer.getRenderer();
const threeCamera = layerRenderer.getThreeCamera();
if (!threeCamera || threeCamera instanceof THREE.OrthographicCamera)
return;
if (!threeCamera) return;
threeCamera.fov = Math.min(Math.max(angle, 0), 180);
layerRenderer.setThreeCameraDirty(true);

View File

@@ -26,7 +26,6 @@ set(
TextEntryObject
TextObject
TiledSpriteObject
Spine
TopDownMovementBehavior)
# Automatically add all listed extensions

View File

@@ -150,8 +150,7 @@ PlatformerObjectBehavior::GetProperties(
properties["UseLegacyTrajectory"]
.SetLabel(_("Use frame rate dependent trajectories (deprecated, it's "
"recommended to leave this unchecked)"))
.SetGroup(_("Deprecated options"))
.SetDeprecated()
.SetGroup(_("Deprecated options (advanced)"))
.SetValue(behaviorContent.GetBoolAttribute("useLegacyTrajectory", true)
? "true"
: "false")

View File

@@ -62,7 +62,7 @@ namespace gdjs {
private _yGrabOffset: any;
private _xGrabTolerance: any;
_useLegacyTrajectory: boolean;
_useLegacyTrajectory: boolean = true;
_canGoDownFromJumpthru: boolean = false;
@@ -355,25 +355,13 @@ namespace gdjs {
private _updateSpeed(timeDelta: float): float {
const previousSpeed = this._currentSpeed;
// Change the speed according to the player's input.
// TODO Give priority to the last key for faster reaction time.
if (this._leftKey !== this._rightKey) {
if (this._leftKey) {
if (this._currentSpeed <= 0) {
this._currentSpeed -= this._acceleration * timeDelta;
} else {
// Turn back at least as fast as it would stop.
this._currentSpeed -=
Math.max(this._acceleration, this._deceleration) * timeDelta;
}
} else if (this._rightKey) {
if (this._currentSpeed >= 0) {
this._currentSpeed += this._acceleration * timeDelta;
} else {
this._currentSpeed +=
Math.max(this._acceleration, this._deceleration) * timeDelta;
}
}
//Change the speed according to the player's input.
// @ts-ignore
if (this._leftKey) {
this._currentSpeed -= this._acceleration * timeDelta;
}
if (this._rightKey) {
this._currentSpeed += this._acceleration * timeDelta;
}
//Take deceleration into account only if no key is pressed.

View File

@@ -169,23 +169,6 @@ module.exports = {
)
.setFunctionName('gdjs.playerAuthentication.getUsername');
extension
.addStrExpression(
'UserID',
_('User ID'),
_('Get the unique user ID of the authenticated player.'),
'',
'JsPlatform/Extensions/authentication.svg'
)
.getCodeExtraInformation()
.setIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationcomponents.js'
)
.addIncludeFile(
'Extensions/PlayerAuthentication/playerauthenticationtools.js'
)
.setFunctionName('gdjs.playerAuthentication.getUserId');
extension
.addCondition(
'IsPlayerAuthenticated',

View File

@@ -171,7 +171,7 @@ namespace gdjs {
if (!_checkedLocalStorage) {
readAuthenticatedUserFromLocalStorage();
}
return _userId || '';
return _userId || null;
};
/**

View File

@@ -163,9 +163,9 @@ void DeclarePrimitiveDrawingExtension(gd::PlatformExtension& extension) {
obj.AddAction("Torus",
_("Torus"),
_("Draw a torus on screen"),
_("Draw at _PARAM1_;_PARAM2_ a torus with "
"inner radius: _PARAM3_, outer radius: _PARAM4_ and "
"with start arc angle: _PARAM5_°, end angle: _PARAM6_° "
_("Draw at _PARAM1_;_PARAM2_ a torus with inner radius"
"_PARAM3_ and outer radius _PARAM4_ and "
"with start arc _PARAM5_° and end arc _PARAM6_°"
"with _PARAM0_"),
_("Drawing"),
"res/actions/torus24.png",

View File

@@ -1,20 +0,0 @@
cmake_minimum_required(VERSION 2.6)
cmake_policy(SET CMP0015 NEW)
project(SpineObject)
gd_add_extension_includes()
#Defines
###
gd_add_extension_definitions(SpineObject)
#The targets
###
include_directories(.)
file(GLOB source_files *.cpp *.h)
gd_add_clang_utils(SpineObject "${source_files}")
gd_add_extension_target(SpineObject "${source_files}")
#Linker files for the IDE extension
###
gd_extension_link_libraries(SpineObject)

View File

@@ -1,323 +0,0 @@
// @flow
/**
* This is a declaration of an extension for GDevelop 5.
*
* Changes in this file are watched and automatically imported if the editor
* is running. You can also manually run `node import-GDJS-Runtime.js` (in newIDE/app/scripts).
*
* The file must be named "JsExtension.js", otherwise GDevelop won't load it.
* ⚠️ If you make a change and the extension is not loaded, open the developer console
* and search for any errors.
*
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
*/
/*::
// Import types to allow Flow to do static type checking on this file.
// Extensions declaration are typed using Flow (like the editor), but the files
// for the game engine are checked with TypeScript annotations.
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
*/
module.exports = {
createExtension: function (
_ /*: (string) => string */,
gd /*: libGDevelop */
) {
const extension = new gd.PlatformExtension();
extension
.setExtensionInformation(
'SpineObject',
_('Spine (experimental)'),
_('Displays a Spine animation.'),
'Vladyslav Pohorielov',
'Open source (MIT License)'
)
.setExtensionHelpPath('/objects/spine')
.setCategory('Advanced');
extension
.addInstructionOrExpressionGroupMetadata(_('Spine'))
.setIcon('JsPlatform/Extensions/spine.svg');
const object = extension
.addObject(
'SpineObject',
_('Spine (experimental)'),
_(
'Display and smoothly animate a 2D object with skeletal animations made with Spine. Use files exported from Spine (json, atlas and image).'
),
'JsPlatform/Extensions/spine.svg',
new gd.SpineObjectConfiguration()
)
.addDefaultBehavior('EffectCapability::EffectBehavior')
.addDefaultBehavior('ResizableCapability::ResizableBehavior')
.addDefaultBehavior('ScalableCapability::ScalableBehavior')
.addDefaultBehavior('FlippableCapability::FlippableBehavior')
.addDefaultBehavior('OpacityCapability::OpacityBehavior')
.addDefaultBehavior('AnimatableCapability::AnimatableBehavior')
.setIncludeFile('Extensions/Spine/spineruntimeobject.js')
.addIncludeFile('Extensions/Spine/spineruntimeobject-pixi-renderer.js')
.addIncludeFile('Extensions/Spine/pixi-spine/pixi-spine.js')
.addIncludeFile('Extensions/Spine/managers/pixi-spine-atlas-manager.js')
.addIncludeFile('Extensions/Spine/managers/pixi-spine-manager.js')
.setCategoryFullName(_('Advanced'));
object
.addExpressionAndConditionAndAction(
'number',
'Animation',
_('Animation mixing duration'),
_(
'the duration of the smooth transition between 2 animations (in second)'
),
_('the animation mixing duration'),
_('Animations and images'),
'JsPlatform/Extensions/spine.svg'
)
.addParameter('object', _('Spine'), 'SpineObject')
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
.setFunctionName('setAnimationMixingDuration')
.setGetter('getAnimationMixingDuration');
return extension;
},
/**
* You can optionally add sanity tests that will check the basic working
* of your extension behaviors/objects by instantiating behaviors/objects
* and setting the property to a given value.
*
* If you don't have any tests, you can simply return an empty array.
*
* But it is recommended to create tests for the behaviors/objects properties you created
* to avoid mistakes.
*/
runExtensionSanityTests: function (
gd /*: libGDevelop */,
extension /*: gdPlatformExtension*/
) {
return [];
},
/**
* Register editors for objects.
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerEditorConfigurations: function (
objectsEditorService /*: ObjectsEditorService */
) {},
/**
* Register renderers for instance of objects on the scene editor.
*
* Run `node import-GDJS-Runtime.js` (in newIDE/app/scripts) if you make any change.
*/
registerInstanceRenderers: function (
objectsRenderingService /*: ObjectsRenderingService */
) {
const { PIXI, RenderedInstance, gd } = objectsRenderingService;
class RenderedSpineInstance extends RenderedInstance {
_spine = null;
_rect = new PIXI.Graphics();
_initialWidth = null;
_initialHeight = null;
_animationIndex = -1;
_spineOriginOffsetX = 0;
_spineOriginOffsetY = 0;
constructor(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
) {
super(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
);
// there is issue with spine selection. mouse events are not triggering during interaction.
// create the invisible background rectangle to fill spine range.
this._rect.alpha = 0;
this._pixiObject = new PIXI.Container();
this._pixiObject.addChild(this._rect);
this._pixiContainer.addChild(this._pixiObject);
this._loadSpine();
}
static getThumbnail(project, resourcesLoader, objectConfiguration) {
return 'JsPlatform/Extensions/spine.svg';
}
update() {
this._pixiObject.position.set(
this._instance.getX(),
this._instance.getY()
);
this.setAnimation(this._instance.getRawDoubleProperty('animation'));
const width = this.getWidth();
const height = this.getHeight();
const { _spine: spine } = this;
if (spine) {
spine.width = width;
spine.height = height;
const localBounds = spine.getLocalBounds(undefined, true);
this._spineOriginOffsetX = localBounds.x * spine.scale.x;
this._spineOriginOffsetY = localBounds.y * spine.scale.y;
this._rect.position.set(
this._spineOriginOffsetX,
this._spineOriginOffsetY
);
}
this._rect.clear();
this._rect.beginFill(0xffffff);
this._rect.lineStyle(1, 0xff0000);
this._rect.drawRect(0, 0, width, height);
}
/**
* @returns x coordinate of this spine origin offset
*/
getOriginX() {
return -this._spineOriginOffsetX;
}
/**
* @returns y coordinate of this spine origin offset
*/
getOriginY() {
return -this._spineOriginOffsetY;
}
/**
* @param {number} index - animation index
*/
setAnimation(index) {
const { _spine: spine } = this;
const configuration = this._getConfiguration();
if (
!spine ||
configuration.hasNoAnimations() ||
index === this._animationIndex
) {
return;
}
if (!Number.isInteger(index) || index < 0) {
index = 0;
} else if (configuration.getAnimationsCount() <= index) {
index = configuration.getAnimationsCount() - 1;
}
this._animationIndex = index;
const animation = configuration.getAnimation(index);
const source = animation.getSource();
const shouldLoop = animation.shouldLoop();
const scale = this.getScale();
// reset scale to track new animation range
// if custom size is set it will be reinitialized in update method
spine.scale.set(1, 1);
spine.state.setAnimation(0, source, shouldLoop);
spine.state.tracks[0].trackTime = 0;
spine.update(0);
spine.autoUpdate = false;
this._initialWidth = spine.width * this.getScale();
this._initialHeight = spine.height * this.getScale();
}
/**
* @returns {number} default width
*/
getDefaultWidth() {
return this._initialWidth !== null ? this._initialWidth : 256;
}
/**
* @returns {number} default height
*/
getDefaultHeight() {
return this._initialHeight !== null ? this._initialHeight : 256;
}
/**
* @returns {number} defined scale
*/
getScale() {
return Number(this._getProperties().get('scale').getValue()) || 1;
}
onRemovedFromScene() {
super.onRemovedFromScene();
this._pixiObject.destroy({ children: true });
}
/**
* @returns this spine object configuration
*/
_getConfiguration() {
return gd.asSpineConfiguration(this._associatedObjectConfiguration);
}
/**
* @returns this object properties container
*/
_getProperties() {
return this._associatedObjectConfiguration.getProperties();
}
_loadSpine() {
const properties = this._getProperties();
const spineResourceName = properties
.get('spineResourceName')
.getValue();
this._pixiResourcesLoader
.getSpineData(this._project, spineResourceName)
.then((spineDataOrLoadingError) => {
if (!spineDataOrLoadingError.skeleton) {
console.error(
'Unable to load Spine (' +
(spineDataOrLoadingError.loadingErrorReason ||
'Unknown reason') +
')',
spineDataOrLoadingError.loadingError
);
this._spine = null;
return;
}
try {
this._spine = new PIXI.Spine(spineDataOrLoadingError.skeleton);
} catch (error) {
console.error('Exception while loading Spine.', error);
this._spine = null;
return;
}
this._pixiObject.addChild(this._spine);
this.update();
});
}
}
objectsRenderingService.registerInstanceRenderer(
'SpineObject::SpineObject',
RenderedSpineInstance
);
},
};

View File

@@ -1,165 +0,0 @@
/**
GDevelop - Spine Extension
Copyright (c) 2010-2016 Florian Rival (Florian.Rival@gmail.com)
This project is released under the MIT License.
*/
#include "SpineObjectConfiguration.h"
#include "GDCore/CommonTools.h"
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
#include "GDCore/Project/InitialInstance.h"
#include "GDCore/Project/MeasurementUnit.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Tools/Localization.h"
using namespace std;
SpineAnimation SpineObjectConfiguration::badAnimation;
SpineObjectConfiguration::SpineObjectConfiguration()
: scale(1), spineResourceName("") {};
bool SpineObjectConfiguration::UpdateProperty(const gd::String &propertyName, const gd::String &newValue) {
if (propertyName == "scale") {
scale = newValue.To<double>();
return true;
}
if (propertyName == "spineResourceName") {
spineResourceName = newValue;
return true;
}
return false;
}
std::map<gd::String, gd::PropertyDescriptor>
SpineObjectConfiguration::GetProperties() const {
std::map<gd::String, gd::PropertyDescriptor> objectProperties;
objectProperties["scale"]
.SetValue(gd::String::From(scale))
.SetType("number")
.SetLabel(_("Scale"))
.SetGroup(_("Default size"));
objectProperties["spineResourceName"]
.SetValue(spineResourceName)
.SetType("resource")
.AddExtraInfo("spine")
.SetLabel(_("Spine json"));
return objectProperties;
}
bool SpineObjectConfiguration::UpdateInitialInstanceProperty(
gd::InitialInstance &instance, const gd::String &propertyName,
const gd::String &newValue, gd::Project &project, gd::Layout &layout
) {
if (propertyName == "animation") {
instance.SetRawDoubleProperty("animation", std::max(0, newValue.empty() ? 0 : newValue.To<int>()));
}
return true;
}
std::map<gd::String, gd::PropertyDescriptor>
SpineObjectConfiguration::GetInitialInstanceProperties(const gd::InitialInstance &instance, gd::Project &project, gd::Layout &layout) {
std::map<gd::String, gd::PropertyDescriptor> properties;
properties["animation"] =
gd::PropertyDescriptor(gd::String::From(instance.GetRawDoubleProperty("animation")))
.SetLabel(_("Animation"))
.SetType("number");
return properties;
}
void SpineObjectConfiguration::DoUnserializeFrom(gd::Project &project, const gd::SerializerElement &element) {
auto &content = element.GetChild("content");
scale = content.GetDoubleAttribute("scale");
spineResourceName = content.GetStringAttribute("spineResourceName");
RemoveAllAnimations();
auto &animationsElement = content.GetChild("animations");
animationsElement.ConsiderAsArrayOf("animation");
for (std::size_t i = 0; i < animationsElement.GetChildrenCount(); ++i) {
auto &animationElement = animationsElement.GetChild(i);
SpineAnimation animation;
animation.SetName(animationElement.GetStringAttribute("name", ""));
animation.SetSource(animationElement.GetStringAttribute("source", ""));
animation.SetShouldLoop(animationElement.GetBoolAttribute("loop", false));
AddAnimation(animation);
}
}
void SpineObjectConfiguration::DoSerializeTo(gd::SerializerElement &element) const {
auto &content = element.AddChild("content");
content.SetAttribute("scale", scale);
content.SetAttribute("spineResourceName", spineResourceName);
auto &animationsElement = content.AddChild("animations");
animationsElement.ConsiderAsArrayOf("animation");
for (auto &animation : animations) {
auto &animationElement = animationsElement.AddChild("animation");
animationElement.SetAttribute("name", animation.GetName());
animationElement.SetAttribute("source", animation.GetSource());
animationElement.SetAttribute("loop", animation.ShouldLoop());
}
}
void SpineObjectConfiguration::ExposeResources(gd::ArbitraryResourceWorker &worker) {
worker.ExposeSpine(spineResourceName);
worker.ExposeEmbeddeds(spineResourceName);
}
const SpineAnimation &
SpineObjectConfiguration::GetAnimation(std::size_t nb) const {
if (nb >= animations.size()) return badAnimation;
return animations[nb];
}
SpineAnimation &SpineObjectConfiguration::GetAnimation(std::size_t nb) {
if (nb >= animations.size()) return badAnimation;
return animations[nb];
}
bool SpineObjectConfiguration::HasAnimationNamed(const gd::String &name) const {
return !name.empty() && (find_if(animations.begin(), animations.end(),
[&name](const SpineAnimation &animation) {
return animation.GetName() == name;
}) != animations.end());
}
void SpineObjectConfiguration::AddAnimation(const SpineAnimation &animation) {
animations.push_back(animation);
}
bool SpineObjectConfiguration::RemoveAnimation(std::size_t nb) {
if (nb >= GetAnimationsCount())
return false;
animations.erase(animations.begin() + nb);
return true;
}
void SpineObjectConfiguration::SwapAnimations(std::size_t firstIndex, std::size_t secondIndex) {
if (firstIndex < animations.size() && secondIndex < animations.size() && firstIndex != secondIndex) {
std::swap(animations[firstIndex], animations[secondIndex]);
}
}
void SpineObjectConfiguration::MoveAnimation(std::size_t oldIndex, std::size_t newIndex) {
if (oldIndex >= animations.size() || newIndex >= animations.size()) {
return;
}
auto animation = animations[oldIndex];
animations.erase(animations.begin() + oldIndex);
animations.insert(animations.begin() + newIndex, animation);
}

View File

@@ -1,162 +0,0 @@
/**
GDevelop - Spine Extension
Copyright (c) 2010-2016 Florian Rival (Florian.Rival@gmail.com)
This project is released under the MIT License.
*/
#pragma once
#include "GDCore/Project/ObjectConfiguration.h"
namespace gd {
class InitialInstance;
class Project;
} // namespace gd
class GD_EXTENSION_API SpineAnimation {
public:
SpineAnimation() : shouldLoop(false) {};
virtual ~SpineAnimation(){};
/**
* \brief Return the name of the animation
*/
const gd::String &GetName() const { return name; }
/**
* \brief Change the name of the animation
*/
void SetName(const gd::String &name_) { name = name_; }
/**
* \brief Return the name of the animation from the spine file.
*/
const gd::String &GetSource() const { return source; }
/**
* \brief Change the name of the animation from the spine file.
*/
void SetSource(const gd::String &source_) { source = source_; }
/**
* \brief Return true if the animation should loop.
*/
const bool ShouldLoop() const { return shouldLoop; }
/**
* \brief Change whether the animation should loop or not.
*/
void SetShouldLoop(bool shouldLoop_) { shouldLoop = shouldLoop_; }
private:
gd::String name;
gd::String source;
bool shouldLoop;
};
/**
* \brief Spine object configuration is used for storage and for the IDE.
*/
class GD_EXTENSION_API SpineObjectConfiguration : public gd::ObjectConfiguration {
public:
SpineObjectConfiguration();
virtual ~SpineObjectConfiguration(){};
virtual std::unique_ptr<gd::ObjectConfiguration> Clone() const override {
return gd::make_unique<SpineObjectConfiguration>(*this);
}
virtual void ExposeResources(gd::ArbitraryResourceWorker &worker) override;
virtual std::map<gd::String, gd::PropertyDescriptor>GetProperties() const override;
virtual bool UpdateProperty(const gd::String &name, const gd::String &value) override;
virtual std::map<gd::String, gd::PropertyDescriptor>
GetInitialInstanceProperties(const gd::InitialInstance &instance,
gd::Project &project,
gd::Layout &layout) override;
virtual bool UpdateInitialInstanceProperty(gd::InitialInstance &instance,
const gd::String &name,
const gd::String &value,
gd::Project &project,
gd::Layout &layout) override;
/** \name Animations
* Methods related to animations management
*/
///@{
/**
* \brief Return the animation at the specified index.
* If the index is out of bound, a "bad animation" object is returned.
*/
const SpineAnimation &GetAnimation(std::size_t nb) const;
/**
* \brief Return the animation at the specified index.
* If the index is out of bound, a "bad animation" object is returned.
*/
SpineAnimation &GetAnimation(std::size_t nb);
/**
* \brief Return the number of animations this object has.
*/
std::size_t GetAnimationsCount() const { return animations.size(); };
/**
* \brief Return true if the animation called "name" exists.
*/
bool HasAnimationNamed(const gd::String& name) const;
/**
* \brief Add an animation at the end of the existing ones.
*/
void AddAnimation(const SpineAnimation &animation);
/**
* \brief Remove an animation.
*/
bool RemoveAnimation(std::size_t nb);
/**
* \brief Remove all animations.
*/
void RemoveAllAnimations() { animations.clear(); }
/**
* \brief Return true if the object hasn't any animation.
*/
bool HasNoAnimations() const { return animations.empty(); }
/**
* \brief Swap the position of two animations
*/
void SwapAnimations(std::size_t firstIndex, std::size_t secondIndex);
/**
* \brief Change the position of the specified animation
*/
void MoveAnimation(std::size_t oldIndex, std::size_t newIndex);
/**
* \brief Return a read-only reference to the vector containing all the
* animation of the object.
*/
const std::vector<SpineAnimation> &GetAllAnimations() const {
return animations;
}
///@}
protected:
virtual void DoUnserializeFrom(gd::Project &project, const gd::SerializerElement &element) override;
virtual void DoSerializeTo(gd::SerializerElement &element) const override;
private:
double scale;
gd::String spineResourceName;
std::vector<SpineAnimation> animations;
static SpineAnimation badAnimation;
};

View File

@@ -1,199 +0,0 @@
/*
* GDevelop JS Platform
* Copyright 2013-present Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
namespace gdjs {
/** The callback called when a text that was requested is loaded (or an error occurred). */
export type SpineAtlasManagerRequestCallback = (
error: Error | null,
content?: pixi_spine.TextureAtlas
) => void;
const atlasKinds: ResourceKind[] = ['atlas'];
/**
* AtlasManager loads atlas files with pixi loader, using the "atlas" resources
* registered in the game resources and process them to Pixi TextureAtlas.
*
* Contrary to audio/fonts, text files are loaded asynchronously, when requested.
* You should properly handle errors, and give the developer/player a way to know
* that loading failed.
*/
export class SpineAtlasManager implements gdjs.ResourceManager {
private _imageManager: ImageManager;
private _resourceLoader: ResourceLoader;
private _loadedSpineAtlases = new gdjs.ResourceCache<
pixi_spine.TextureAtlas
>();
private _loadingSpineAtlases = new gdjs.ResourceCache<
Promise<pixi_spine.TextureAtlas>
>();
/**
* @param resources The resources data of the game.
* @param resourcesLoader The resources loader of the game.
*/
constructor(
resourceLoader: gdjs.ResourceLoader,
imageManager: ImageManager
) {
this._resourceLoader = resourceLoader;
this._imageManager = imageManager;
}
getResourceKinds(): ResourceKind[] {
return atlasKinds;
}
async processResource(resourceName: string): Promise<void> {
// Do nothing because pixi-spine parses resources by itself.
}
async loadResource(resourceName: string): Promise<void> {
await this.getOrLoad(resourceName);
}
/**
* Returns promisified loaded atlas resource if it is availble, loads it otherwise.
*
* @param resources The data of resource to load.
*/
getOrLoad(resourceName: string): Promise<pixi_spine.TextureAtlas> {
const resource = this._getAtlasResource(resourceName);
if (!resource) {
return Promise.reject(
`Unable to find atlas for resource '${resourceName}'.`
);
}
let loadingPromise = this._loadingSpineAtlases.get(resource);
if (!loadingPromise) {
loadingPromise = new Promise<pixi_spine.TextureAtlas>(
(resolve, reject) => {
const onLoad: SpineAtlasManagerRequestCallback = (
error,
content
) => {
if (error) {
return reject(
`Error while preloading a spine atlas resource: ${error}`
);
}
if (!content) {
return reject(
`Cannot reach texture atlas for resource '${resourceName}'.`
);
}
resolve(content);
};
this.load(resource, onLoad);
}
);
this._loadingSpineAtlases.set(resource, loadingPromise);
}
return loadingPromise;
}
/**
* Load specified atlas resource and pass it to callback once it is loaded.
*
* @param resources The data of resource to load.
* @param callback The callback to pass atlas to it once it is loaded.
*/
load(
resource: ResourceData,
callback: SpineAtlasManagerRequestCallback
): void {
const game = this._resourceLoader.getRuntimeGame();
const embeddedResourcesNames = game.getEmbeddedResourcesNames(
resource.name
);
if (!embeddedResourcesNames.length)
return callback(
new Error(`${resource.name} do not have image metadata!`)
);
const images = embeddedResourcesNames.reduce<{
[key: string]: PIXI.Texture;
}>((imagesMap, embeddedResourceName) => {
const mappedResourceName = game.resolveEmbeddedResource(
resource.name,
embeddedResourceName
);
imagesMap[
embeddedResourceName
] = this._imageManager.getOrLoadPIXITexture(mappedResourceName);
return imagesMap;
}, {});
const onLoad = (atlas: pixi_spine.TextureAtlas) => {
this._loadedSpineAtlases.set(resource, atlas);
callback(null, atlas);
};
PIXI.Assets.setPreferences({
preferWorkers: false,
crossOrigin: this._resourceLoader.checkIfCredentialsRequired(
resource.file
)
? 'use-credentials'
: 'anonymous',
});
PIXI.Assets.add(resource.name, resource.file, { images });
PIXI.Assets.load<pixi_spine.TextureAtlas | string>(resource.name).then(
(atlas) => {
/**
* Ideally atlas of TextureAtlas should be passed here
* but there is known issue in case of preloaded images (see https://github.com/pixijs/spine/issues/537)
*
* Here covered all possible ways to make it work fine if issue is fixed in pixi-spine or after migration to spine-pixi
*/
if (typeof atlas === 'string') {
new pixi_spine.TextureAtlas(
atlas,
(textureName, textureCb) =>
textureCb(images[textureName].baseTexture),
onLoad
);
} else {
onLoad(atlas);
}
}
);
}
/**
* Check if the given atlas resource was loaded (preloaded or loaded with `load`).
* @param resourceName The name of the atlas resource.
* @returns true if the content of the atlas resource is loaded, false otherwise.
*/
isLoaded(resourceName: string): boolean {
return !!this._loadedSpineAtlases.getFromName(resourceName);
}
/**
* Get the Pixi TextureAtlas for the given resource that is already loaded (preloaded or loaded with `load`).
* If the resource is not loaded, `null` will be returned.
* @param resourceName The name of the atlas resource.
* @returns the TextureAtlas of the atlas if loaded, `null` otherwise.
*/
getAtlasTexture(resourceName: string): pixi_spine.TextureAtlas | null {
return this._loadedSpineAtlases.getFromName(resourceName);
}
private _getAtlasResource(resourceName: string): ResourceData | null {
const resource = this._resourceLoader.getResource(resourceName);
return resource && this.getResourceKinds().includes(resource.kind)
? resource
: null;
}
}
}

View File

@@ -1,120 +0,0 @@
/*
* GDevelop JS Platform
* Copyright 2013-present Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
namespace gdjs {
const logger = new gdjs.Logger('Spine Manager');
const resourceKinds: ResourceKind[] = ['spine'];
/**
* SpineManager manages pixi spine skeleton data.
*/
export class SpineManager implements gdjs.ResourceManager {
private _spineAtlasManager: SpineAtlasManager;
private _resourceLoader: ResourceLoader;
private _loadedSpines = new gdjs.ResourceCache<pixi_spine.ISkeletonData>();
/**
* @param resourceDataArray The resources data of the game.
* @param resourcesLoader The resources loader of the game.
*/
constructor(
resourceLoader: gdjs.ResourceLoader,
spineAtlasManager: SpineAtlasManager
) {
this._resourceLoader = resourceLoader;
this._spineAtlasManager = spineAtlasManager;
}
getResourceKinds(): ResourceKind[] {
return resourceKinds;
}
async processResource(resourceName: string): Promise<void> {
// Do nothing because pixi-spine parses resources by itself.
}
async loadResource(resourceName: string): Promise<void> {
const resource = this._getSpineResource(resourceName);
if (!resource) {
return logger.error(
`Unable to find spine json for resource ${resourceName}.`
);
}
try {
const game = this._resourceLoader.getRuntimeGame();
const embeddedResourcesNames = game.getEmbeddedResourcesNames(
resource.name
);
// there should be exactly one file which is pointing to atlas
if (embeddedResourcesNames.length !== 1) {
return logger.error(
`Unable to find atlas metadata for resource spine json ${resourceName}.`
);
}
const atlasResourceName = game.resolveEmbeddedResource(
resource.name,
embeddedResourcesNames[0]
);
const spineAtlas = await this._spineAtlasManager.getOrLoad(
atlasResourceName
);
PIXI.Assets.setPreferences({
preferWorkers: false,
crossOrigin: this._resourceLoader.checkIfCredentialsRequired(
resource.file
)
? 'use-credentials'
: 'anonymous',
});
PIXI.Assets.add(resource.name, resource.file, { spineAtlas });
const loadedJson = await PIXI.Assets.load(resource.name);
if (loadedJson.spineData) {
this._loadedSpines.set(resource, loadedJson.spineData);
} else {
logger.error(
`Loader cannot process spine resource ${resource.name} correctly.`
);
}
} catch (error) {
logger.error(
`Error while preloading spine resource ${resource.name}: ${error}`
);
}
}
/**
* Get the object for the given resource that is already loaded (preloaded or loaded with `loadJson`).
* If the resource is not loaded, `null` will be returned.
*
* @param resourceName The name of the spine skeleton.
* @returns the spine skeleton if loaded, `null` otherwise.
*/
getSpine(resourceName: string): pixi_spine.ISkeletonData | null {
return this._loadedSpines.getFromName(resourceName);
}
/**
* Check if the given spine skeleton was loaded.
* @param resourceName The name of the spine skeleton.
* @returns true if the content of the spine skeleton is loaded, false otherwise.
*/
isSpineLoaded(resourceName: string): boolean {
return !!this._loadedSpines.getFromName(resourceName);
}
private _getSpineResource(resourceName: string): ResourceData | null {
const resource = this._resourceLoader.getResource(resourceName);
return resource && this.getResourceKinds().includes(resource.kind)
? resource
: null;
}
}
}

View File

@@ -1,202 +0,0 @@
namespace gdjs {
const isSpine = (obj: any): obj is pixi_spine.Spine =>
obj instanceof pixi_spine.Spine;
export class SpineRuntimeObjectPixiRenderer {
private _object: gdjs.SpineRuntimeObject;
private _rendererObject: pixi_spine.Spine | PIXI.Container;
private _isAnimationComplete = true;
/**
* @param runtimeObject The object to render
* @param instanceContainer The container in which the object is
*/
constructor(
runtimeObject: gdjs.SpineRuntimeObject,
private instanceContainer: gdjs.RuntimeInstanceContainer
) {
this._object = runtimeObject;
this._rendererObject = this.constructRendererObject();
if (isSpine(this._rendererObject)) {
this._rendererObject.autoUpdate = false;
}
this.updatePosition();
this.updateAngle();
this.updateOpacity();
this.updateScale();
instanceContainer
.getLayer('')
.getRenderer()
.addRendererObject(this._rendererObject, runtimeObject.getZOrder());
}
updateAnimation(timeDelta: float) {
if (!isSpine(this._rendererObject)) {
return;
}
this._rendererObject.update(timeDelta);
}
getRendererObject(): pixi_spine.Spine | PIXI.Container {
return this._rendererObject;
}
getOriginOffset(): PIXI.Point {
if (!isSpine(this._rendererObject)) return new PIXI.Point(0, 0);
const localBounds = this._rendererObject.getLocalBounds(undefined, true);
return new PIXI.Point(
localBounds.x * this._rendererObject.scale.x,
localBounds.y * this._rendererObject.scale.y
);
}
onDestroy(): void {
this._rendererObject.destroy();
}
updateScale(): void {
const scaleX = Math.max(
this._object._originalScale * this._object.getScaleX(),
0
);
const scaleY = Math.max(
this._object._originalScale * this._object.getScaleY(),
0
);
this._rendererObject.scale.x = this._object.isFlippedX()
? -scaleX
: scaleX;
this._rendererObject.scale.y = this._object.isFlippedY()
? -scaleY
: scaleY;
}
updatePosition(): void {
this._rendererObject.position.x = this._object.x;
this._rendererObject.position.y = this._object.y;
}
updateAngle(): void {
this._rendererObject.rotation = gdjs.toRad(this._object.angle);
}
updateOpacity(): void {
this._rendererObject.alpha = this._object.getOpacity() / 255;
}
getWidth(): float {
return this._rendererObject.width;
}
getHeight(): float {
return this._rendererObject.height;
}
setWidth(width: float): void {
this._rendererObject.width = width;
}
setHeight(height: float): void {
this._rendererObject.height = height;
}
getUnscaledWidth(): float {
return Math.abs(
(this._rendererObject.width * this._object._originalScale) /
this._rendererObject.scale.x
);
}
getUnscaledHeight(): float {
return Math.abs(
(this._rendererObject.height * this._object._originalScale) /
this._rendererObject.scale.y
);
}
setMixing(from: string, to: string, duration: number): void {
if (!isSpine(this._rendererObject)) return;
this._rendererObject.stateData.setMix(from, to, duration);
}
setAnimation(animation: string, loop: boolean): void {
if (isSpine(this._rendererObject)) {
const onCompleteListener: pixi_spine.IAnimationStateListener = {
complete: () => {
this._isAnimationComplete = true;
(this._rendererObject as pixi_spine.Spine).state.removeListener(
onCompleteListener
);
},
};
this._isAnimationComplete = false;
this._rendererObject.state.addListener(onCompleteListener);
this._rendererObject.state.setAnimation(0, animation, loop);
this._rendererObject.update(0);
}
}
getAnimationDuration(sourceAnimationName: string) {
if (!isSpine(this._rendererObject)) {
return 0;
}
const animation = this._rendererObject.spineData.findAnimation(
sourceAnimationName
);
return animation ? animation.duration : 0;
}
getAnimationElapsedTime(): number {
if (!isSpine(this._rendererObject)) {
return 0;
}
const tracks = this._rendererObject.state.tracks;
if (tracks.length === 0) {
return 0;
}
// This should be fine because only 1 track is used.
const track = tracks[0];
// @ts-ignore TrackEntry.getAnimationTime is not exposed.
return track.getAnimationTime();
}
setAnimationElapsedTime(time: number): void {
if (!isSpine(this._rendererObject)) {
return;
}
const tracks = this._rendererObject.state.tracks;
if (tracks.length === 0) {
return;
}
const track = tracks[0];
track.trackTime = time;
}
isAnimationComplete(): boolean {
return this._isAnimationComplete;
}
private constructRendererObject(): pixi_spine.Spine | PIXI.Container {
const game = this.instanceContainer.getGame();
const spineManager = game.getSpineManager();
if (
!spineManager ||
!spineManager.isSpineLoaded(this._object.spineResourceName)
) {
return new PIXI.Container();
}
return new pixi_spine.Spine(
spineManager.getSpine(this._object.spineResourceName)!
);
}
}
export const SpineRuntimeObjectRenderer = SpineRuntimeObjectPixiRenderer;
}

View File

@@ -1,406 +0,0 @@
namespace gdjs {
type SpineAnimation = { name: string; source: string; loop: boolean };
export type SpineObjectDataType = {
content: {
opacity: float;
scale: float;
timeScale: float;
spineResourceName: string;
animations: SpineAnimation[];
};
};
export type SpineObjectData = ObjectData & SpineObjectDataType;
export class SpineRuntimeObject
extends gdjs.RuntimeObject
implements
gdjs.Resizable,
gdjs.Scalable,
gdjs.Animatable,
gdjs.OpacityHandler {
private _opacity: float = 255;
private _scaleX: number = 1;
private _scaleY: number = 1;
_originalScale: number;
private _flippedX: boolean = false;
private _flippedY: boolean = false;
private _animations: SpineAnimation[];
private _currentAnimationIndex = -1;
private _animationSpeedScale: float = 1;
private _animationPaused: boolean = false;
private _isPausedFrameDirty = false;
/** The duration in second for the smooth transition between 2 animations */
private _animationMixingDuration: number;
private _renderer: gdjs.SpineRuntimeObjectPixiRenderer;
readonly spineResourceName: string;
/**
* @param instanceContainer The container the object belongs to.
* @param objectData The object data used to initialize the object
*/
constructor(
instanceContainer: gdjs.RuntimeInstanceContainer,
objectData: SpineObjectData
) {
super(instanceContainer, objectData);
this._animations = objectData.content.animations;
this._originalScale = objectData.content.scale;
this.spineResourceName = objectData.content.spineResourceName;
this._animationMixingDuration = 0.1;
this._renderer = new gdjs.SpineRuntimeObjectRenderer(
this,
instanceContainer
);
this.setAnimationIndex(0);
this._renderer.updateAnimation(0);
// *ALWAYS* call `this.onCreated()` at the very end of your object constructor.
this.onCreated();
}
update(instanceContainer: gdjs.RuntimeInstanceContainer): void {
if (this._animationPaused) {
if (this._isPausedFrameDirty) {
this._renderer.updateAnimation(0);
this.invalidateHitboxes();
this._isPausedFrameDirty = false;
}
return;
}
const elapsedTime = this.getElapsedTime() / 1000;
this._renderer.updateAnimation(elapsedTime * this._animationSpeedScale);
this.invalidateHitboxes();
}
getRendererObject(): pixi_spine.Spine | PIXI.Container {
return this._renderer.getRendererObject();
}
updateFromObjectData(
oldObjectData: SpineObjectData,
newObjectData: SpineObjectData
): boolean {
super.updateFromObjectData(oldObjectData, newObjectData);
if (oldObjectData.content.scale !== newObjectData.content.scale) {
this._originalScale = newObjectData.content.scale;
this._renderer.updateScale();
this.invalidateHitboxes();
}
return true;
}
extraInitializationFromInitialInstance(
initialInstanceData: InstanceData
): void {
const animationData = initialInstanceData.numberProperties.find(
(data) => data.name === 'animation'
);
const animationIndex = animationData
? animationData.value
: this._currentAnimationIndex;
this.setAnimationIndexWithMixing(animationIndex, 0);
if (initialInstanceData.customSize) {
this.setSize(initialInstanceData.width, initialInstanceData.height);
this.invalidateHitboxes();
}
}
getDrawableX(): number {
const originOffset = this._renderer.getOriginOffset();
return this.getX() + originOffset.x;
}
getDrawableY(): number {
const originOffset = this._renderer.getOriginOffset();
return this.getY() + originOffset.y;
}
onDestroyed(): void {
super.onDestroyed();
this._renderer.onDestroy();
}
setX(x: float): void {
super.setX(x);
this._renderer.updatePosition();
}
setY(y: float): void {
super.setY(y);
this._renderer.updatePosition();
}
setAngle(angle: float): void {
super.setAngle(angle);
this._renderer.updateAngle();
}
setOpacity(opacity: float): void {
this._opacity = Math.max(0, Math.min(255, opacity));
this._renderer.updateOpacity();
}
getOpacity(): float {
return this._opacity;
}
getWidth(): float {
return this._renderer.getWidth();
}
getHeight(): float {
return this._renderer.getHeight();
}
setWidth(newWidth: float): void {
const unscaledWidth = this._renderer.getUnscaledWidth();
if (unscaledWidth !== 0) {
this.setScaleX(newWidth / unscaledWidth);
}
}
setHeight(newHeight: float): void {
const unscaledHeight = this._renderer.getUnscaledHeight();
if (unscaledHeight !== 0) {
this.setScaleY(newHeight / unscaledHeight);
}
}
setSize(newWidth: number, newHeight: number): void {
this.setWidth(newWidth);
this.setHeight(newHeight);
}
setScale(newScale: float): void {
if (newScale < 0) {
newScale = 0;
}
if (
newScale === Math.abs(this._scaleX) &&
newScale === Math.abs(this._scaleY)
) {
return;
}
this._scaleX = newScale * (this._flippedX ? -1 : 1);
this._scaleY = newScale * (this._flippedY ? -1 : 1);
this._renderer.updateScale();
this.invalidateHitboxes();
}
setScaleX(newScale: float): void {
if (newScale < 0) {
newScale = 0;
}
if (newScale === Math.abs(this._scaleX)) {
return;
}
this._scaleX = newScale * (this._flippedX ? -1 : 1);
this._renderer.updateScale();
this.invalidateHitboxes();
}
setScaleY(newScale: float): void {
if (newScale < 0) {
newScale = 0;
}
if (newScale === Math.abs(this._scaleY)) {
return;
}
this._scaleY = newScale * (this._flippedY ? -1 : 1);
this._renderer.updateScale();
this.invalidateHitboxes();
}
/**
* Get the scale of the object (or the geometric mean of the X and Y scale in case they are different).
*
* @return the scale of the object (or the geometric mean of the X and Y scale in case they are different).
*/
getScale(): float {
const scaleX = Math.abs(this._scaleX);
const scaleY = Math.abs(this._scaleY);
return scaleX === scaleY ? scaleX : Math.sqrt(scaleX * scaleY);
}
getScaleY(): float {
return Math.abs(this._scaleY);
}
getScaleX(): float {
return Math.abs(this._scaleX);
}
isFlippedX(): boolean {
return this._flippedX;
}
isFlippedY(): boolean {
return this._flippedY;
}
flipX(enable: boolean) {
if (enable !== this._flippedX) {
this._scaleX *= -1;
this._flippedX = enable;
this.invalidateHitboxes();
this._renderer.updateScale();
}
}
flipY(enable: boolean) {
if (enable !== this._flippedY) {
this._scaleY *= -1;
this._flippedY = enable;
this.invalidateHitboxes();
this._renderer.updateScale();
}
}
setAnimationIndex(animationIndex: number): void {
this.setAnimationIndexWithMixing(
animationIndex,
this._animationMixingDuration
);
}
setAnimationIndexWithMixing(
animationIndex: number,
mixingDuration: number
): void {
if (
this._animations.length === 0 ||
this._currentAnimationIndex === animationIndex ||
!this.isAnimationIndex(animationIndex)
) {
return;
}
const previousAnimation = this._animations[this._currentAnimationIndex];
const newAnimation = this._animations[animationIndex];
this._currentAnimationIndex = animationIndex;
if (previousAnimation) {
this._renderer.setMixing(
previousAnimation.source,
newAnimation.source,
mixingDuration
);
}
this._renderer.setAnimation(newAnimation.source, newAnimation.loop);
this._isPausedFrameDirty = true;
}
setAnimationName(animationName: string): void {
this.setAnimationNameWithMixing(
animationName,
this._animationMixingDuration
);
}
setAnimationNameWithMixing(
animationName: string,
mixingDuration: number
): void {
this.setAnimationIndexWithMixing(
this.getAnimationIndexFor(animationName),
mixingDuration
);
}
getAnimationIndexFor(animationName: string): number {
return this._animations.findIndex(
(animation) => animation.name === animationName
);
}
/**
* Return the duration in second for the smooth transition between 2 animations.
*/
getAnimationMixingDuration(): number {
return this._animationMixingDuration;
}
/**
* Change the duration in second for the smooth transition between 2 animations.
*/
setAnimationMixingDuration(animationMixingDuration: number): void {
this._animationMixingDuration = animationMixingDuration;
}
getAnimationIndex(): number {
return this._currentAnimationIndex;
}
getAnimationName(): string {
return this.isAnimationIndex(this._currentAnimationIndex)
? this._animations[this._currentAnimationIndex].name
: '';
}
isAnimationIndex(animationIndex: number): boolean {
return (
Number.isInteger(animationIndex) &&
animationIndex >= 0 &&
animationIndex < this._animations.length
);
}
hasAnimationEnded(): boolean {
return this._renderer.isAnimationComplete();
}
isAnimationPaused() {
return this._animationPaused;
}
pauseAnimation() {
this._animationPaused = true;
}
resumeAnimation() {
this._animationPaused = false;
}
getAnimationSpeedScale() {
return this._animationSpeedScale;
}
setAnimationSpeedScale(ratio: float): void {
this._animationSpeedScale = ratio;
}
getAnimationElapsedTime(): number {
if (this._animations.length === 0) {
return 0;
}
return this._renderer.getAnimationElapsedTime();
}
setAnimationElapsedTime(time: number): void {
if (this._animations.length === 0) {
return;
}
this._renderer.setAnimationElapsedTime(time);
this._isPausedFrameDirty = true;
}
getAnimationDuration(): number {
if (this._animations.length === 0) {
return 0;
}
return this._renderer.getAnimationDuration(
this._animations[this._currentAnimationIndex].source
);
}
}
gdjs.registerObject('SpineObject::SpineObject', gdjs.SpineRuntimeObject);
}

View File

@@ -893,7 +893,7 @@ module.exports = {
.getCodeExtraInformation()
.setFunctionName('addObjectPositionXTween2');
// deprecated
// deprecated use the 3D Tween extension
behavior
.addAction(
'AddObjectPositionZTween',
@@ -926,38 +926,6 @@ module.exports = {
.getCodeExtraInformation()
.setFunctionName('addObjectPositionZTween');
behavior
.addAction(
'AddObjectPositionZTween2',
_('Tween object Z position'),
_(
'Tweens an object Z position (3D objects only) from its current Z position to a new one.'
),
_(
'Tween the Z position of _PARAM0_ to _PARAM4_ with easing _PARAM5_ over _PARAM6_ seconds as _PARAM3_'
),
_('Position'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'TweenBehavior', false)
.addParameter("behavior", _("3D capability"), "Scene3D::Base3DBehavior")
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
.addParameter('expression', _('To Z'), '', false)
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.addParameter(
'yesorno',
_('Destroy this object when tween finishes'),
'',
false
)
.setDefaultValue('no')
.getCodeExtraInformation()
.setFunctionName('addObjectPositionZTween2');
// deprecated
behavior
.addAction(
@@ -1111,38 +1079,6 @@ module.exports = {
.getCodeExtraInformation()
.setFunctionName('addObjectDepthTween');
behavior
.addAction(
'AddObjectDepthTween2',
_('Tween object depth'),
_(
'Tweens an object depth (suitable 3D objects only) from its current depth to a new one.'
),
_(
'Tween the depth of _PARAM0_ to _PARAM4_ with easing _PARAM5_ over _PARAM6_ seconds as _PARAM3_'
),
_('Size'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'TweenBehavior', false)
.addParameter("behavior", _("3D capability"), "Scene3D::Base3DBehavior")
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
.addParameter('expression', _('To depth'), '', false)
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.addParameter(
'yesorno',
_('Destroy this object when tween finishes'),
'',
false
)
.setDefaultValue('no')
.getCodeExtraInformation()
.setFunctionName('addObjectDepthTween2');
// deprecated
behavior
.addAction(
@@ -1267,66 +1203,6 @@ module.exports = {
.getCodeExtraInformation()
.setFunctionName('addObjectAngleTween2');
behavior
.addScopedAction(
'AddObjectRotationXTween',
_('Tween object rotation on X axis'),
_('Tweens an object rotation on X axis from its current angle to a new one.'),
_(
'Tween the rotation on X axis of _PARAM0_ to _PARAM4_° with easing _PARAM5_ over _PARAM6_ seconds as _PARAM3_'
),
_('Angle'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'TweenBehavior', false)
.addParameter("behavior", _("3D capability"), "Scene3D::Base3DBehavior")
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
.addParameter('expression', _('To angle (in degrees)'), '', false)
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.addParameter(
'yesorno',
_('Destroy this object when tween finishes'),
'',
false
)
.setDefaultValue('no')
.getCodeExtraInformation()
.setFunctionName('addObjectRotationXTween');
behavior
.addScopedAction(
'AddObjectRotationYTween',
_('Tween object rotation on Y axis'),
_('Tweens an object rotation on Y axis from its current angle to a new one.'),
_(
'Tween the rotation on Y axis of _PARAM0_ to _PARAM4_° with easing _PARAM5_ over _PARAM6_ seconds as _PARAM3_'
),
_('Angle'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'TweenBehavior', false)
.addParameter("behavior", _("3D capability"), "Scene3D::Base3DBehavior")
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
.addParameter('expression', _('To angle (in degrees)'), '', false)
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.addParameter(
'yesorno',
_('Destroy this object when tween finishes'),
'',
false
)
.setDefaultValue('no')
.getCodeExtraInformation()
.setFunctionName('addObjectRotationYTween');
// deprecated
behavior
.addAction(
@@ -1363,7 +1239,6 @@ module.exports = {
.getCodeExtraInformation()
.setFunctionName('addObjectScaleTween');
// deprecated
behavior
.addScopedAction(
'AddObjectScaleTween2',
@@ -1378,7 +1253,6 @@ module.exports = {
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.setHidden()
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'TweenBehavior', false)
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
@@ -1399,39 +1273,6 @@ module.exports = {
.getCodeExtraInformation()
.setFunctionName('addObjectScaleTween2');
behavior
.addScopedAction(
'AddObjectScaleTween3',
_('Tween object scale'),
_(
'Tweens an object scale from its current value to a new one (note: the scale can never be 0 or less).'
),
_(
'Tween the scale of _PARAM0_ to _PARAM3_ (from center: _PARAM7_) with easing _PARAM4_ over _PARAM5_ seconds as _PARAM2_'
),
_('Size'),
'JsPlatform/Extensions/tween_behavior24.png',
'JsPlatform/Extensions/tween_behavior32.png'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'TweenBehavior', false)
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
.addParameter('expression', _('To scale'), '', false)
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
.setDefaultValue('linear')
.addParameter('expression', _('Duration (in seconds)'), '', false)
.addParameter(
'yesorno',
_('Destroy this object when tween finishes'),
'',
false
)
.setDefaultValue('no')
.addParameter('yesorno', _('Scale from center of object'), '', false)
.setDefaultValue('no')
.getCodeExtraInformation()
.setFunctionName('addObjectScaleTween3');
// deprecated
behavior
.addAction(

View File

@@ -10,256 +10,210 @@ describe('gdjs.TweenRuntimeBehavior', () => {
};
/** @type {gdjs.RuntimeScene} */
let runtimeScene;
let layout;
/** @type {gdjs.TweenRuntimeBehavior} */
beforeEach(() => {
runtimeScene = createScene();
runtimeScene.getLayer('').setTimeScale(1.5);
layout = createScene();
layout.getLayer('').setTimeScale(1.5);
});
const tween = gdjs.evtTools.tween;
const camera = gdjs.evtTools.camera;
it("can get default values for tweens that don't exist", () => {
expect(tween.sceneTweenExists(runtimeScene, 'MyTween')).to.be(false);
expect(tween.getValue(runtimeScene, 'MyTween')).to.be(0);
expect(tween.getProgress(runtimeScene, 'MyTween')).to.be(0);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(false);
expect(tween.sceneTweenExists(layout, 'MyTween')).to.be(false);
expect(tween.getValue(layout, 'MyTween')).to.be(0);
expect(tween.getProgress(layout, 'MyTween')).to.be(0);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(false);
});
it('can play a tween till the end', () => {
camera.setCameraRotation(runtimeScene, 200, '', 0);
tween.tweenCameraRotation2(
runtimeScene,
'MyTween',
600,
'',
'linear',
0.25
);
camera.setCameraRotation(layout, 200, '', 0);
tween.tweenCameraRotation2(layout, 'MyTween', 600, '', 'linear', 0.25);
// Tween actions don't change the value directly.
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(200);
expect(tween.getValue(runtimeScene, 'MyTween')).to.be(200);
expect(tween.getProgress(runtimeScene, 'MyTween')).to.be(0);
expect(camera.getCameraRotation(layout, '', 0)).to.be(200);
expect(tween.getValue(layout, 'MyTween')).to.be(200);
expect(tween.getProgress(layout, 'MyTween')).to.be(0);
let oldAngle;
let oldValue;
let oldProgress;
for (let i = 0; i < 10; i++) {
oldAngle = camera.getCameraRotation(runtimeScene, '', 0);
oldValue = tween.getValue(runtimeScene, 'MyTween');
oldProgress = tween.getProgress(runtimeScene, 'MyTween');
oldAngle = camera.getCameraRotation(layout, '', 0);
oldValue = tween.getValue(layout, 'MyTween');
oldProgress = tween.getProgress(layout, 'MyTween');
runtimeScene.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(false);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be.above(
oldAngle
);
expect(tween.getValue(runtimeScene, 'MyTween')).to.be.above(oldValue);
expect(tween.getProgress(runtimeScene, 'MyTween')).to.be.above(
oldProgress
);
layout.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(false);
expect(camera.getCameraRotation(layout, '', 0)).to.be.above(oldAngle);
expect(tween.getValue(layout, 'MyTween')).to.be.above(oldValue);
expect(tween.getProgress(layout, 'MyTween')).to.be.above(oldProgress);
}
// The tween reaches the end
runtimeScene.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(true);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(600);
expect(tween.getValue(runtimeScene, 'MyTween')).to.be(600);
expect(tween.getProgress(runtimeScene, 'MyTween')).to.be(1);
layout.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(true);
expect(camera.getCameraRotation(layout, '', 0)).to.be(600);
expect(tween.getValue(layout, 'MyTween')).to.be(600);
expect(tween.getProgress(layout, 'MyTween')).to.be(1);
// The value is not changed after the tween is finished
runtimeScene.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(true);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(600);
expect(tween.getValue(runtimeScene, 'MyTween')).to.be(600);
expect(tween.getProgress(runtimeScene, 'MyTween')).to.be(1);
layout.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(true);
expect(camera.getCameraRotation(layout, '', 0)).to.be(600);
expect(tween.getValue(layout, 'MyTween')).to.be(600);
expect(tween.getProgress(layout, 'MyTween')).to.be(1);
// The value is not set to the targeted value over and over
// after the tween is finished.
camera.setCameraRotation(runtimeScene, 123, '', 0);
runtimeScene.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(123);
camera.setCameraRotation(layout, 123, '', 0);
layout.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(layout, '', 0)).to.be(123);
});
it('can pause and resume a tween', () => {
camera.setCameraRotation(runtimeScene, 200, '', 0);
tween.tweenCameraRotation2(
runtimeScene,
'MyTween',
600,
'',
'linear',
0.25
);
camera.setCameraRotation(layout, 200, '', 0);
tween.tweenCameraRotation2(layout, 'MyTween', 600, '', 'linear', 0.25);
// The tween starts
for (let i = 0; i < 5; i++) {
runtimeScene.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(false);
layout.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(false);
}
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(400);
expect(camera.getCameraRotation(layout, '', 0)).to.be(400);
// Pause the tween
tween.pauseSceneTween(runtimeScene, 'MyTween');
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(400);
tween.pauseSceneTween(layout, 'MyTween');
expect(camera.getCameraRotation(layout, '', 0)).to.be(400);
for (let i = 0; i < 5; i++) {
runtimeScene.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(false);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(400);
layout.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(false);
expect(camera.getCameraRotation(layout, '', 0)).to.be(400);
}
// The value is not overridden during the pause.
camera.setCameraRotation(runtimeScene, 123, '', 0);
runtimeScene.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(123);
camera.setCameraRotation(layout, 123, '', 0);
layout.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(layout, '', 0)).to.be(123);
// Resume the tween
tween.resumeSceneTween(runtimeScene, 'MyTween');
tween.resumeSceneTween(layout, 'MyTween');
// Tween actions don't change the value directly.
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(123);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(false);
runtimeScene.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(440);
expect(camera.getCameraRotation(layout, '', 0)).to.be(123);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(false);
layout.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(layout, '', 0)).to.be(440);
});
it('can stop and restart a tween', () => {
camera.setCameraRotation(runtimeScene, 200, '', 0);
camera.setCameraRotation(layout, 200, '', 0);
// Start the tween
tween.tweenCameraRotation2(
runtimeScene,
'MyTween',
600,
'',
'linear',
0.25
);
tween.tweenCameraRotation2(layout, 'MyTween', 600, '', 'linear', 0.25);
for (let i = 0; i < 5; i++) {
runtimeScene.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(false);
layout.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(false);
}
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(400);
expect(camera.getCameraRotation(layout, '', 0)).to.be(400);
// Stop the tween
tween.stopSceneTween(runtimeScene, 'MyTween', false);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(400);
tween.stopSceneTween(layout, 'MyTween', false);
expect(camera.getCameraRotation(layout, '', 0)).to.be(400);
for (let i = 0; i < 5; i++) {
runtimeScene.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(true);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(400);
layout.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(true);
expect(camera.getCameraRotation(layout, '', 0)).to.be(400);
}
// The value is not overridden by a stopped tween.
camera.setCameraRotation(runtimeScene, 123, '', 0);
runtimeScene.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(123);
camera.setCameraRotation(layout, 123, '', 0);
layout.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(layout, '', 0)).to.be(123);
// A stopped tween can't be resumed.
tween.resumeSceneTween(runtimeScene, 'MyTween');
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(true);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(123);
tween.resumeSceneTween(layout, 'MyTween');
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(true);
expect(camera.getCameraRotation(layout, '', 0)).to.be(123);
runtimeScene.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(123);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(true);
layout.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(layout, '', 0)).to.be(123);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(true);
// Restart the tween
tween.tweenCameraRotation2(
runtimeScene,
'MyTween',
623,
'',
'linear',
0.25
);
tween.tweenCameraRotation2(layout, 'MyTween', 623, '', 'linear', 0.25);
for (let i = 0; i < 5; i++) {
runtimeScene.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(false);
layout.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(false);
}
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(373);
expect(camera.getCameraRotation(layout, '', 0)).to.be(373);
});
it('can remove and recreate a tween', () => {
camera.setCameraRotation(runtimeScene, 200, '', 0);
camera.setCameraRotation(layout, 200, '', 0);
// Start the tween
expect(tween.sceneTweenExists(runtimeScene, 'MyTween')).to.be(false);
tween.tweenCameraRotation2(
runtimeScene,
'MyTween',
600,
'',
'linear',
0.25
);
expect(tween.sceneTweenExists(runtimeScene, 'MyTween')).to.be(true);
expect(tween.sceneTweenExists(layout, 'MyTween')).to.be(false);
tween.tweenCameraRotation2(layout, 'MyTween', 600, '', 'linear', 0.25);
expect(tween.sceneTweenExists(layout, 'MyTween')).to.be(true);
for (let i = 0; i < 5; i++) {
runtimeScene.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(false);
layout.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(false);
}
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(400);
expect(camera.getCameraRotation(layout, '', 0)).to.be(400);
// Remove the tween
expect(tween.sceneTweenExists(runtimeScene, 'MyTween')).to.be(true);
tween.removeSceneTween(runtimeScene, 'MyTween');
expect(tween.sceneTweenExists(runtimeScene, 'MyTween')).to.be(false);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(400);
expect(tween.sceneTweenExists(layout, 'MyTween')).to.be(true);
tween.removeSceneTween(layout, 'MyTween');
expect(tween.sceneTweenExists(layout, 'MyTween')).to.be(false);
expect(camera.getCameraRotation(layout, '', 0)).to.be(400);
for (let i = 0; i < 5; i++) {
runtimeScene.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(false);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(400);
layout.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(false);
expect(camera.getCameraRotation(layout, '', 0)).to.be(400);
}
// The value is not overridden after the tween has been removed.
camera.setCameraRotation(runtimeScene, 123, '', 0);
runtimeScene.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(123);
camera.setCameraRotation(layout, 123, '', 0);
layout.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(layout, '', 0)).to.be(123);
// A removed tween can't be resumed.
tween.resumeSceneTween(runtimeScene, 'MyTween');
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(false);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(123);
tween.resumeSceneTween(layout, 'MyTween');
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(false);
expect(camera.getCameraRotation(layout, '', 0)).to.be(123);
runtimeScene.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(123);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(false);
layout.renderAndStep(1000 / 60);
expect(camera.getCameraRotation(layout, '', 0)).to.be(123);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(false);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(false);
// Recreate the tween
expect(tween.sceneTweenExists(runtimeScene, 'MyTween')).to.be(false);
tween.tweenCameraRotation2(
runtimeScene,
'MyTween',
623,
'',
'linear',
0.25
);
expect(tween.sceneTweenExists(runtimeScene, 'MyTween')).to.be(true);
expect(tween.sceneTweenExists(layout, 'MyTween')).to.be(false);
tween.tweenCameraRotation2(layout, 'MyTween', 623, '', 'linear', 0.25);
expect(tween.sceneTweenExists(layout, 'MyTween')).to.be(true);
for (let i = 0; i < 5; i++) {
runtimeScene.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(runtimeScene, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(runtimeScene, 'MyTween')).to.be(false);
layout.renderAndStep(1000 / 60);
expect(tween.sceneTweenIsPlaying(layout, 'MyTween')).to.be(true);
expect(tween.sceneTweenHasFinished(layout, 'MyTween')).to.be(false);
}
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(373);
expect(tween.sceneTweenExists(runtimeScene, 'MyTween')).to.be(true);
expect(camera.getCameraRotation(layout, '', 0)).to.be(373);
expect(tween.sceneTweenExists(layout, 'MyTween')).to.be(true);
});
const checkProgress = (steps, getValueFunctions) => {
@@ -268,7 +222,7 @@ describe('gdjs.TweenRuntimeBehavior', () => {
}
for (let i = 0; i < steps; i++) {
const oldValues = getValueFunctions.map((getValue) => getValue());
runtimeScene.renderAndStep(1000 / 60);
layout.renderAndStep(1000 / 60);
for (let index = 0; index < oldValues.length; index++) {
expect(getValueFunctions[index]()).not.to.be(oldValues[index]);
@@ -277,10 +231,10 @@ describe('gdjs.TweenRuntimeBehavior', () => {
};
it('can tween a scene variable', () => {
const variable = runtimeScene.getVariables().get('MyVariable');
const variable = layout.getVariables().get('MyVariable');
variable.setNumber(200);
tween.tweenVariableNumber3(
runtimeScene,
layout,
'MyTween',
variable,
600,
@@ -293,7 +247,7 @@ describe('gdjs.TweenRuntimeBehavior', () => {
it('can tween a layer value', () => {
tween.addLayerValueTween(
runtimeScene,
layout,
'MyTween',
200,
600,
@@ -302,13 +256,13 @@ describe('gdjs.TweenRuntimeBehavior', () => {
false,
''
);
checkProgress(6, () => tween.getValue(runtimeScene, 'MyTween'));
expect(tween.getValue(runtimeScene, 'MyTween')).to.be(440);
checkProgress(6, () => tween.getValue(layout, 'MyTween'));
expect(tween.getValue(layout, 'MyTween')).to.be(440);
});
it('can tween a layout value', () => {
tween.addLayoutValueTween(
runtimeScene,
layout,
'MyTween',
200,
600,
@@ -316,69 +270,39 @@ describe('gdjs.TweenRuntimeBehavior', () => {
0.25 / 1.5,
false
);
checkProgress(6, () => tween.getValue(runtimeScene, 'MyTween'));
expect(tween.getValue(runtimeScene, 'MyTween')).to.be(440);
checkProgress(6, () => tween.getValue(layout, 'MyTween'));
expect(tween.getValue(layout, 'MyTween')).to.be(440);
});
it('can tween a layer camera position', () => {
camera.setCameraX(runtimeScene, 200, '', 0);
camera.setCameraY(runtimeScene, 300, '', 0);
tween.tweenCamera2(runtimeScene, 'MyTween', 600, 900, '', 'linear', 0.25);
camera.setCameraX(layout, 200, '', 0);
camera.setCameraY(layout, 300, '', 0);
tween.tweenCamera2(layout, 'MyTween', 600, 900, '', 'linear', 0.25);
checkProgress(6, [
() => camera.getCameraX(runtimeScene, '', 0),
() => camera.getCameraY(runtimeScene, '', 0),
() => camera.getCameraX(layout, '', 0),
() => camera.getCameraY(layout, '', 0),
]);
expect(camera.getCameraX(runtimeScene, '', 0)).to.be(440);
expect(camera.getCameraY(runtimeScene, '', 0)).to.be(660);
expect(camera.getCameraX(layout, '', 0)).to.be(440);
expect(camera.getCameraY(layout, '', 0)).to.be(660);
});
it('can tween a layer camera zoom', () => {
camera.setCameraZoom(runtimeScene, 200, '', 0);
tween.tweenCameraZoom2(runtimeScene, 'MyTween', 600, '', 'linear', 0.25);
checkProgress(6, () => camera.getCameraZoom(runtimeScene, '', 0));
camera.setCameraZoom(layout, 200, '', 0);
tween.tweenCameraZoom2(layout, 'MyTween', 600, '', 'linear', 0.25);
checkProgress(6, () => camera.getCameraZoom(layout, '', 0));
// The interpolation is exponential.
expect(camera.getCameraZoom(runtimeScene, '', 0)).to.be(386.6364089863524);
});
it('can tween a layer camera zoom to 0', () => {
camera.setCameraZoom(runtimeScene, 1, '', 0);
tween.tweenCameraZoom2(runtimeScene, 'MyTween', 0, '', 'linear', 0.25);
// A camera zoom of 0 doesn't make sense.
// Check that there is no NaN.
for (let i = 0; i < 11; i++) {
runtimeScene.renderAndStep(1000 / 60);
expect(camera.getCameraZoom(runtimeScene, '', 0)).to.be(0);
}
});
it('can tween a layer camera zoom from 0', () => {
camera.setCameraZoom(runtimeScene, 0, '', 0);
tween.tweenCameraZoom2(runtimeScene, 'MyTween', 1, '', 'linear', 0.25);
// A camera zoom of 0 doesn't make sense.
// Check that there is no NaN.
for (let i = 0; i < 11; i++) {
expect(camera.getCameraZoom(runtimeScene, '', 0)).to.be(0);
runtimeScene.renderAndStep(1000 / 60);
}
expect(camera.getCameraZoom(runtimeScene, '', 0)).to.be(1);
expect(camera.getCameraZoom(layout, '', 0)).to.be(386.6364089863524);
});
it('can tween a layer camera rotation', () => {
camera.setCameraRotation(runtimeScene, 200, '', 0);
tween.tweenCameraRotation2(
runtimeScene,
'MyTween',
600,
'',
'linear',
0.25
);
checkProgress(6, () => camera.getCameraRotation(runtimeScene, '', 0));
expect(camera.getCameraRotation(runtimeScene, '', 0)).to.be(440);
camera.setCameraRotation(layout, 200, '', 0);
tween.tweenCameraRotation2(layout, 'MyTween', 600, '', 'linear', 0.25);
checkProgress(6, () => camera.getCameraRotation(layout, '', 0));
expect(camera.getCameraRotation(layout, '', 0)).to.be(440);
});
it('can tween a number effect property', () => {
const layer = runtimeScene.getLayer('');
const layer = layout.getLayer('');
layer.addEffect({
effectType: 'Outline',
name: 'MyEffect',
@@ -387,7 +311,7 @@ describe('gdjs.TweenRuntimeBehavior', () => {
booleanParameters: {},
});
tween.tweenNumberEffectPropertyTween(
runtimeScene,
layout,
'MyTween',
600,
'',
@@ -405,7 +329,7 @@ describe('gdjs.TweenRuntimeBehavior', () => {
});
it('can tween a color effect property', () => {
const layer = runtimeScene.getLayer('');
const layer = layout.getLayer('');
layer.addEffect({
effectType: 'Outline',
name: 'MyEffect',
@@ -414,7 +338,7 @@ describe('gdjs.TweenRuntimeBehavior', () => {
booleanParameters: {},
});
tween.tweenColorEffectPropertyTween(
runtimeScene,
layout,
'MyTween',
'255;192;128',
'',

View File

@@ -85,32 +85,6 @@ describe('gdjs.TweenRuntimeBehavior', () => {
return object;
};
/**
* @param {gdjs.RuntimeScene} runtimeScene
*/
const addCube = (runtimeScene) => {
const object = new gdjs.Cube3DRuntimeObject(runtimeScene, {
name: 'Cube',
type: 'Scene3D::Cube3DObject',
effects: [],
variables: [],
behaviors: [
{
type: 'Tween::TweenBehavior',
name: behaviorName,
},
],
// @ts-ignore
content: {
width: 64,
height: 64,
depth: 64,
},
});
runtimeScene.addObject(object);
return object;
};
/**
* @param {gdjs.RuntimeScene} runtimeScene
*/
@@ -149,8 +123,6 @@ describe('gdjs.TweenRuntimeBehavior', () => {
let object;
/** @type {gdjs.SpriteRuntimeObject} */
let sprite;
/** @type {gdjs.Cube3DRuntimeObject} */
let cube;
/** @type {gdjs.TextRuntimeObject} */
let textObject;
/** @type {gdjs.TweenRuntimeBehavior} */
@@ -158,23 +130,18 @@ describe('gdjs.TweenRuntimeBehavior', () => {
/** @type {gdjs.TweenRuntimeBehavior} */
let spriteBehavior;
/** @type {gdjs.TweenRuntimeBehavior} */
let cubeBehavior;
/** @type {gdjs.TweenRuntimeBehavior} */
let textObjectBehavior;
beforeEach(() => {
runtimeScene = createScene();
runtimeScene.getLayer('').setTimeScale(1.5);
object = addObject(runtimeScene);
sprite = addSprite(runtimeScene);
cube = addCube(runtimeScene);
textObject = addTextObject(runtimeScene);
//@ts-ignore
behavior = object.getBehavior(behaviorName);
//@ts-ignore
spriteBehavior = sprite.getBehavior(behaviorName);
//@ts-ignore
cubeBehavior = cube.getBehavior(behaviorName);
//@ts-ignore
textObjectBehavior = textObject.getBehavior(behaviorName);
});
@@ -249,19 +216,6 @@ describe('gdjs.TweenRuntimeBehavior', () => {
expect(object.getY()).to.be(440);
});
it('can tween the position on Z axis', () => {
cube.setZ(200);
cubeBehavior.addObjectPositionZTween(
'MyTween',
600,
'linear',
250 / 1.5,
false
);
checkProgress(6, () => cube.getZ());
expect(cube.getZ()).to.be(440);
});
it('can tween the angle', () => {
object.setAngle(200);
behavior.addObjectAngleTween('MyTween', 600, 'linear', 250 / 1.5, false);
@@ -283,19 +237,6 @@ describe('gdjs.TweenRuntimeBehavior', () => {
expect(object.getHeight()).to.be(440);
});
it('can tween the depth', () => {
cube.setDepth(200);
cubeBehavior.addObjectDepthTween(
'MyTween',
600,
'linear',
250 / 1.5,
false
);
checkProgress(6, () => cube.getDepth());
expect(cube.getDepth()).to.be(440);
});
it('can tween the opacity', () => {
sprite.setOpacity(128);
spriteBehavior.addObjectOpacityTween(
@@ -483,46 +424,4 @@ describe('gdjs.TweenRuntimeBehavior', () => {
expect(sprite.getX()).to.be(-7580);
expect(sprite.getY()).to.be(-11120);
});
it('can tween the scales in seconds', () => {
sprite.setPosition(100, 400);
sprite.setScaleX(200);
sprite.setScaleY(300);
spriteBehavior.addObjectScaleTween2(
'MyTween',
600,
900,
'linear',
0.25,
false,
false
);
checkProgress(6, [() => sprite.getScaleX(), () => sprite.getScaleY()]);
// The interpolation is exponential.
expect(sprite.getScaleX()).to.be(386.6364089863524);
expect(sprite.getScaleY()).to.be(579.9546134795287);
expect(sprite.getX()).to.be(100);
expect(sprite.getY()).to.be(400);
});
it('can tween the scales from center in seconds', () => {
sprite.setPosition(100, 400);
sprite.setScaleX(200);
sprite.setScaleY(300);
spriteBehavior.addObjectScaleTween2(
'MyTween',
600,
900,
'linear',
0.25,
false,
true
);
checkProgress(6, [() => sprite.getScaleX(), () => sprite.getScaleY()]);
// The interpolation is exponential.
expect(sprite.getScaleX()).to.be(386.6364089863524);
expect(sprite.getScaleY()).to.be(579.9546134795287);
expect(sprite.getX()).to.be(-5872.3650875632775);
expect(sprite.getY()).to.be(-8558.547631344918);
});
});

View File

@@ -85,32 +85,6 @@ describe('gdjs.TweenRuntimeBehavior', () => {
return object;
};
/**
* @param {gdjs.RuntimeScene} runtimeScene
*/
const addCube = (runtimeScene) => {
const object = new gdjs.Cube3DRuntimeObject(runtimeScene, {
name: 'Cube',
type: 'Scene3D::Cube3DObject',
effects: [],
variables: [],
behaviors: [
{
type: 'Tween::TweenBehavior',
name: behaviorName,
},
],
// @ts-ignore
content: {
width: 64,
height: 64,
depth: 64,
},
});
runtimeScene.addObject(object);
return object;
};
/**
* @param {gdjs.RuntimeScene} runtimeScene
*/
@@ -149,8 +123,6 @@ describe('gdjs.TweenRuntimeBehavior', () => {
let object;
/** @type {gdjs.SpriteRuntimeObject} */
let sprite;
/** @type {gdjs.Cube3DRuntimeObject} */
let cube;
/** @type {gdjs.TextRuntimeObject} */
let textObject;
/** @type {gdjs.TweenRuntimeBehavior} */
@@ -158,23 +130,18 @@ describe('gdjs.TweenRuntimeBehavior', () => {
/** @type {gdjs.TweenRuntimeBehavior} */
let spriteBehavior;
/** @type {gdjs.TweenRuntimeBehavior} */
let cubeBehavior;
/** @type {gdjs.TweenRuntimeBehavior} */
let textObjectBehavior;
beforeEach(() => {
runtimeScene = createScene();
runtimeScene.getLayer('').setTimeScale(1.5);
object = addObject(runtimeScene);
sprite = addSprite(runtimeScene);
cube = addCube(runtimeScene);
textObject = addTextObject(runtimeScene);
//@ts-ignore
behavior = object.getBehavior(behaviorName);
//@ts-ignore
spriteBehavior = sprite.getBehavior(behaviorName);
//@ts-ignore
cubeBehavior = cube.getBehavior(behaviorName);
//@ts-ignore
textObjectBehavior = textObject.getBehavior(behaviorName);
});
@@ -437,20 +404,6 @@ describe('gdjs.TweenRuntimeBehavior', () => {
expect(object.getY()).to.be(440);
});
it('can tween the position on Z axis', () => {
cube.setZ(200);
cubeBehavior.addObjectPositionZTween2(
null,
'MyTween',
600,
'linear',
0.25,
false
);
checkProgress(6, () => cube.getZ());
expect(cube.getZ()).to.be(440);
});
it('can tween the angle', () => {
object.setAngle(200);
behavior.addObjectAngleTween2('MyTween', 600, 'linear', 0.25, false);
@@ -458,34 +411,6 @@ describe('gdjs.TweenRuntimeBehavior', () => {
expect(object.getAngle()).to.be(440);
});
it('can tween the rotation X', () => {
cube.setRotationX(200);
cubeBehavior.addObjectRotationXTween(
null,
'MyTween',
600,
'linear',
0.25,
false
);
checkProgress(6, () => cube.getRotationX());
expect(cube.getRotationX()).to.be(440);
});
it('can tween the rotation Y', () => {
cube.setRotationY(200);
cubeBehavior.addObjectRotationYTween(
null,
'MyTween',
600,
'linear',
0.25,
false
);
checkProgress(6, () => cube.getRotationY());
expect(cube.getRotationY()).to.be(440);
});
it('can tween the width', () => {
object.setWidth(200);
behavior.addObjectWidthTween2('MyTween', 600, 'linear', 0.25, false);
@@ -500,20 +425,6 @@ describe('gdjs.TweenRuntimeBehavior', () => {
expect(object.getHeight()).to.be(440);
});
it('can tween the depth', () => {
cube.setDepth(200);
cubeBehavior.addObjectDepthTween2(
null,
'MyTween',
600,
'linear',
0.25,
false
);
checkProgress(6, () => cube.getDepth());
expect(cube.getDepth()).to.be(440);
});
it('can tween a number effect property', () => {
sprite.addEffect({
effectType: 'Outline',
@@ -629,53 +540,6 @@ describe('gdjs.TweenRuntimeBehavior', () => {
expect(sprite.getY()).to.be(400);
});
it('can tween the scale on X axis to 0', () => {
sprite.setPosition(100, 400);
sprite.setScaleX(1);
spriteBehavior.addObjectScaleTween3(
'MyTween',
0,
'linear',
0.25,
false,
false
);
// The interpolation is exponential.
// It would need an infinite speed to go away from 0.
// This is why the scale is set to 0 directly.
for (let i = 0; i < 11; i++) {
runtimeScene.renderAndStep(1000 / 60);
expect(sprite.getScaleX()).to.be(0);
}
expect(spriteBehavior.hasFinished('MyTween')).to.be(true);
expect(sprite.getX()).to.be(100);
expect(sprite.getY()).to.be(400);
});
it('can tween the scale on X axis from 0', () => {
sprite.setPosition(100, 400);
sprite.setScaleX(0);
spriteBehavior.addObjectScaleTween3(
'MyTween',
1,
'linear',
0.25,
false,
false
);
// The interpolation is exponential.
// It would need an infinite speed to go away from 0.
// This is why the scale is set to 1 directly at the end.
for (let i = 0; i < 11; i++) {
expect(sprite.getScale()).to.be(0);
runtimeScene.renderAndStep(1000 / 60);
}
expect(spriteBehavior.hasFinished('MyTween')).to.be(true);
expect(sprite.getScaleX()).to.be(1);
expect(sprite.getX()).to.be(100);
expect(sprite.getY()).to.be(400);
});
it('can tween the scale on X axis from center', () => {
sprite.setPosition(100, 400);
sprite.setScaleX(200);
@@ -712,53 +576,6 @@ describe('gdjs.TweenRuntimeBehavior', () => {
expect(sprite.getY()).to.be(400);
});
it('can tween the scale on Y axis to 0', () => {
sprite.setPosition(100, 400);
sprite.setScaleY(1);
spriteBehavior.addObjectScaleTween3(
'MyTween',
0,
'linear',
0.25,
false,
false
);
// The interpolation is exponential.
// It would need an infinite speed to go away from 0.
// This is why the scale is set to 0 directly.
for (let i = 0; i < 11; i++) {
runtimeScene.renderAndStep(1000 / 60);
expect(sprite.getScaleY()).to.be(0);
}
expect(spriteBehavior.hasFinished('MyTween')).to.be(true);
expect(sprite.getX()).to.be(100);
expect(sprite.getY()).to.be(400);
});
it('can tween the scale on Y axis from 0', () => {
sprite.setPosition(100, 400);
sprite.setScaleY(0);
spriteBehavior.addObjectScaleTween3(
'MyTween',
1,
'linear',
0.25,
false,
false
);
// The interpolation is exponential.
// It would need an infinite speed to go away from 0.
// This is why the scale is set to 1 directly at the end.
for (let i = 0; i < 11; i++) {
expect(sprite.getScale()).to.be(0);
runtimeScene.renderAndStep(1000 / 60);
}
expect(spriteBehavior.hasFinished('MyTween')).to.be(true);
expect(sprite.getScaleY()).to.be(1);
expect(sprite.getX()).to.be(100);
expect(sprite.getY()).to.be(400);
});
it('can tween the scale on Y axis from center', () => {
sprite.setPosition(100, 400);
sprite.setScaleY(200);
@@ -806,126 +623,45 @@ describe('gdjs.TweenRuntimeBehavior', () => {
expect(object.getY()).to.be(660);
});
it('can tween the scale', () => {
it('can tween the scales', () => {
sprite.setPosition(100, 400);
sprite.setScale(200);
spriteBehavior.addObjectScaleTween3(
sprite.setScaleX(200);
sprite.setScaleY(300);
spriteBehavior.addObjectScaleTween2(
'MyTween',
600,
900,
'linear',
0.25,
false,
false
);
checkProgress(6, () => sprite.getScale());
checkProgress(6, [() => sprite.getScaleX(), () => sprite.getScaleY()]);
// The interpolation is exponential.
expect(sprite.getScale()).to.be(386.6364089863524);
expect(sprite.getX()).to.be(100);
expect(sprite.getY()).to.be(400);
});
it('can tween the scale to 0', () => {
sprite.setPosition(100, 400);
sprite.setScale(1);
spriteBehavior.addObjectScaleTween3(
'MyTween',
0,
'linear',
0.25,
false,
false
);
// The interpolation is exponential.
// It would need an infinite speed to go away from 0.
// This is why the scale is set to 0 directly.
for (let i = 0; i < 11; i++) {
runtimeScene.renderAndStep(1000 / 60);
expect(sprite.getScale()).to.be(0);
}
expect(spriteBehavior.hasFinished('MyTween')).to.be(true);
expect(sprite.getX()).to.be(100);
expect(sprite.getY()).to.be(400);
});
it('can tween the scale from 0', () => {
sprite.setPosition(100, 400);
sprite.setScale(0);
spriteBehavior.addObjectScaleTween3(
'MyTween',
1,
'linear',
0.25,
false,
false
);
// The interpolation is exponential.
// It would need an infinite speed to go away from 0.
// This is why the scale is set to 1 directly at the end.
for (let i = 0; i < 11; i++) {
expect(sprite.getScale()).to.be(0);
runtimeScene.renderAndStep(1000 / 60);
}
expect(spriteBehavior.hasFinished('MyTween')).to.be(true);
expect(sprite.getScale()).to.be(1);
expect(sprite.getScaleX()).to.be(386.6364089863524);
expect(sprite.getScaleY()).to.be(579.9546134795287);
expect(sprite.getX()).to.be(100);
expect(sprite.getY()).to.be(400);
});
it('can tween the scales from center', () => {
sprite.setPosition(100, 400);
sprite.setScale(200);
spriteBehavior.addObjectScaleTween3(
sprite.setScaleX(200);
sprite.setScaleY(300);
spriteBehavior.addObjectScaleTween2(
'MyTween',
600,
900,
'linear',
0.25,
false,
true
);
checkProgress(6, () => sprite.getScale());
checkProgress(6, [() => sprite.getScaleX(), () => sprite.getScaleY()]);
// The interpolation is exponential.
expect(sprite.getScale()).to.be(386.6364089863524);
expect(sprite.getScaleX()).to.be(386.6364089863524);
expect(sprite.getScaleY()).to.be(579.9546134795287);
expect(sprite.getX()).to.be(-5872.3650875632775);
expect(sprite.getY()).to.be(-5572.3650875632775);
});
it('can tween the scale of a cube', () => {
cube.setPosition(100, 400);
cube.setZ(800);
cube.setScale(200);
cubeBehavior.addObjectScaleTween3(
'MyTween',
600,
'linear',
0.25,
false,
false
);
checkProgress(6, () => cube.getScale());
// The interpolation is exponential.
expect(cube.getScale()).to.be(386.6364089863524);
expect(cube.getX()).to.be(100);
expect(cube.getY()).to.be(400);
expect(cube.getZ()).to.be(800);
});
it('can tween the scales of a cube from center', () => {
cube.setPosition(100, 400);
cube.setZ(800);
cube.setScale(200);
cubeBehavior.addObjectScaleTween3(
'MyTween',
600,
'linear',
0.25,
false,
true
);
checkProgress(6, () => cube.getScale());
// The interpolation is exponential.
expect(cube.getScale()).to.be(386.6364089863524);
expect(cube.getX()).to.be(-5872.3650875632775);
expect(cube.getY()).to.be(-5572.3650875632775);
expect(cube.getZ()).to.be(-5172.3650875632775);
expect(sprite.getY()).to.be(-8558.547631344918);
});
});

View File

@@ -456,7 +456,7 @@ namespace gdjs {
/**
* Tween an object Z position.
* @deprecated Use addObjectPositionZTween2 instead.
* @deprecated Use the 3D Tween extension instead.
* @param identifier Unique id to identify the tween
* @param toZ The target Z position
* @param easing Easing function identifier
@@ -469,59 +469,14 @@ namespace gdjs {
easing: string,
duration: float,
destroyObjectWhenFinished: boolean
) {
this._addObjectPositionZTween(
identifier,
toZ,
easing,
duration / 1000,
destroyObjectWhenFinished,
this.owner.getRuntimeScene()
);
}
/**
* Tween an object Z position.
* @param object3DBehavior Only used by events can be set to null
* @param identifier Unique id to identify the tween
* @param toZ The target Z position
* @param easing Easing function identifier
* @param duration Duration in seconds
* @param destroyObjectWhenFinished Destroy this object when the tween ends
*/
addObjectPositionZTween2(
object3DBehavior: any,
identifier: string,
toZ: number,
easing: string,
duration: float,
destroyObjectWhenFinished: boolean
) {
this._addObjectPositionZTween(
identifier,
toZ,
easing,
duration,
destroyObjectWhenFinished,
this.owner
);
}
private _addObjectPositionZTween(
identifier: string,
toZ: number,
easing: string,
duration: float,
destroyObjectWhenFinished: boolean,
timeSource: gdjs.evtTools.tween.TimeSource
) {
const { owner } = this;
if (!(owner instanceof gdjs.RuntimeObject3D)) return;
this._tweens.addSimpleTween(
identifier,
timeSource,
duration,
this.owner.getRuntimeScene(),
duration / 1000,
easing,
linearInterpolation,
owner.getZ(),
@@ -603,72 +558,6 @@ namespace gdjs {
);
}
/**
* Tween a 3D object rotation X.
* @param object3DBehavior Only used by events can be set to null
* @param identifier Unique id to identify the tween
* @param toAngle The target angle
* @param easing Easing function identifier
* @param duration Duration in seconds
* @param destroyObjectWhenFinished Destroy this object when the tween ends
*/
addObjectRotationXTween(
object3DBehavior: any,
identifier: string,
toAngle: float,
easing: string,
duration: float,
destroyObjectWhenFinished: boolean
) {
const { owner } = this;
if (!(owner instanceof gdjs.RuntimeObject3D)) return;
this._tweens.addSimpleTween(
identifier,
this.owner,
duration,
easing,
linearInterpolation,
owner.getRotationX(),
toAngle,
(value: float) => owner.setRotationX(value),
destroyObjectWhenFinished ? () => this._deleteFromScene() : null
);
}
/**
* Tween a 3D object rotation Y.
* @param object3DBehavior Only used by events can be set to null
* @param identifier Unique id to identify the tween
* @param toAngle The target angle
* @param easing Easing function identifier
* @param duration Duration in seconds
* @param destroyObjectWhenFinished Destroy this object when the tween ends
*/
addObjectRotationYTween(
object3DBehavior: any,
identifier: string,
toAngle: float,
easing: string,
duration: float,
destroyObjectWhenFinished: boolean
) {
const { owner } = this;
if (!(owner instanceof gdjs.RuntimeObject3D)) return;
this._tweens.addSimpleTween(
identifier,
this.owner,
duration,
easing,
linearInterpolation,
owner.getRotationY(),
toAngle,
(value: float) => owner.setRotationY(value),
destroyObjectWhenFinished ? () => this._deleteFromScene() : null
);
}
/**
* Tween an object scale.
* @deprecated Use addObjectScaleTween2 instead.
@@ -704,7 +593,6 @@ namespace gdjs {
/**
* Tween an object scale.
* @deprecated Use addObjectScaleXTween2 and addObjectScaleYTween2 instead.
* @param identifier Unique id to identify the tween
* @param toScaleX The target X-scale
* @param toScaleY The target Y-scale
@@ -778,65 +666,6 @@ namespace gdjs {
);
}
/**
* Tween an object scale.
* @param identifier Unique id to identify the tween
* @param toScale The target scale
* @param easing Easing function identifier
* @param duration Duration in seconds
* @param destroyObjectWhenFinished Destroy this object when the tween ends
* @param scaleFromCenterOfObject Scale the transform from the center of the object (or point that is called center), not the top-left origin
*/
addObjectScaleTween3(
identifier: string,
toScale: number,
easing: string,
duration: float,
destroyObjectWhenFinished: boolean,
scaleFromCenterOfObject: boolean
) {
this._addObjectScaleXTween(
identifier,
toScale,
easing,
duration,
destroyObjectWhenFinished,
scaleFromCenterOfObject,
this.owner,
exponentialInterpolation
);
const owner = this.owner;
if (!isScalable(owner)) return;
const owner3d = owner instanceof gdjs.RuntimeObject3D ? owner : null;
const setValue = scaleFromCenterOfObject
? (scale: float) => {
const oldX = owner.getCenterXInScene();
const oldY = owner.getCenterYInScene();
const oldZ = owner3d ? owner3d.getCenterZInScene() : 0;
owner.setScale(scale);
owner.setCenterXInScene(oldX);
owner.setCenterYInScene(oldY);
if (owner3d) {
owner3d.setCenterZInScene(oldZ);
}
}
: (scale: float) => owner.setScale(scale);
this._tweens.addSimpleTween(
identifier,
this.owner,
duration,
easing,
exponentialInterpolation,
owner.getScale(),
toScale,
setValue,
destroyObjectWhenFinished ? () => this._deleteFromScene() : null
);
}
/**
* Tween an object X-scale.
* @deprecated Use addObjectScaleXTween2 instead.
@@ -1690,7 +1519,7 @@ namespace gdjs {
/**
* Tween an object depth.
* @deprecated Use addObjectDepthTween2 instead.
* @deprecated Use the 3D Tween extension instead.
* @param identifier Unique id to identify the tween
* @param toDepth The target depth
* @param easing Easing function identifier
@@ -1703,59 +1532,14 @@ namespace gdjs {
easing: string,
duration: float,
destroyObjectWhenFinished: boolean
) {
this._addObjectDepthTween(
identifier,
toDepth,
easing,
duration / 1000,
destroyObjectWhenFinished,
this.owner.getRuntimeScene()
);
}
/**
* Tween an object depth.
* @param object3DBehavior Only used by events can be set to null
* @param identifier Unique id to identify the tween
* @param toDepth The target depth
* @param easing Easing function identifier
* @param duration Duration in seconds
* @param destroyObjectWhenFinished Destroy this object when the tween ends
*/
addObjectDepthTween2(
object3DBehavior: any,
identifier: string,
toDepth: float,
easing: string,
duration: float,
destroyObjectWhenFinished: boolean
) {
this._addObjectDepthTween(
identifier,
toDepth,
easing,
duration,
destroyObjectWhenFinished,
this.owner
);
}
private _addObjectDepthTween(
identifier: string,
toDepth: float,
easing: string,
duration: float,
destroyObjectWhenFinished: boolean,
timeSource: gdjs.evtTools.tween.TimeSource
) {
const { owner } = this;
if (!(owner instanceof gdjs.RuntimeObject3D)) return;
this._tweens.addSimpleTween(
identifier,
timeSource,
duration,
this.owner.getRuntimeScene(),
duration / 1000,
easing,
linearInterpolation,
owner.getDepth(),

2
GDJS/.gitignore vendored
View File

@@ -1 +1 @@
/node_modules
/node_modules

View File

@@ -124,8 +124,6 @@ namespace gdjs {
private _jsonManager: JsonManager;
private _model3DManager: Model3DManager;
private _bitmapFontManager: BitmapFontManager;
private _spineAtlasManager: SpineAtlasManager | null = null;
private _spineManager: SpineManager | null = null;
/**
* Only used by events.
@@ -174,18 +172,6 @@ namespace gdjs {
);
this._model3DManager = new gdjs.Model3DManager(this);
// add spine related managers only if spine extension is used
if (gdjs.SpineAtlasManager && gdjs.SpineManager) {
this._spineAtlasManager = new gdjs.SpineAtlasManager(
this,
this._imageManager
);
this._spineManager = new gdjs.SpineManager(
this,
this._spineAtlasManager
);
}
const resourceManagers: Array<ResourceManager> = [
this._imageManager,
this._soundManager,
@@ -194,11 +180,6 @@ namespace gdjs {
this._bitmapFontManager,
this._model3DManager,
];
if (this._spineAtlasManager)
resourceManagers.push(this._spineAtlasManager);
if (this._spineManager) resourceManagers.push(this._spineManager);
this._resourceManagersMap = new Map<ResourceKind, ResourceManager>();
for (const resourceManager of resourceManagers) {
for (const resourceKind of resourceManager.getResourceKinds()) {
@@ -207,13 +188,6 @@ namespace gdjs {
}
}
/**
* @returns the runtime game instance.
*/
getRuntimeGame(): RuntimeGame {
return this._runtimeGame;
}
/**
* Update the resources data of the game. Useful for hot-reloading, should
* not be used otherwise.
@@ -602,24 +576,6 @@ namespace gdjs {
getModel3DManager(): gdjs.Model3DManager {
return this._model3DManager;
}
/**
* Get the Spine manager of the game, used to load and construct spine skeletons from game
* resources.
* @return The Spine manager for the game
*/
getSpineManager(): gdjs.SpineManager | null {
return this._spineManager;
}
/**
* Get the Spine Atlas manager of the game, used to load atlases from game
* resources.
* @return The Spine Atlas manager for the game
*/
getSpineAtlasManager(): gdjs.SpineAtlasManager | null {
return this._spineAtlasManager;
}
}
type PromiseError<T> = { item: T; error: Error };

View File

@@ -56,7 +56,7 @@ namespace gdjs {
setCameraZ(z: float, fov: float, cameraId?: integer): void {}
getCameraZ(fov: float | null, cameraId?: integer): float {
getCameraZ(fov: float = 45, cameraId?: integer): float {
return 0;
}

View File

@@ -19,15 +19,6 @@ namespace gdjs {
? RuntimeLayerRenderingType.TWO_D_PLUS_THREE_D
: RuntimeLayerRenderingType.TWO_D;
export enum RuntimeLayerCameraType {
PERSPECTIVE,
ORTHOGRAPHIC,
}
const getCameraTypeFromString = (renderingTypeAsString: string | undefined) =>
renderingTypeAsString === 'orthographic'
? RuntimeLayerCameraType.ORTHOGRAPHIC
: RuntimeLayerCameraType.PERSPECTIVE;
/**
* Represents a layer of a "container", used to display objects.
* The container can be a scene (see gdjs.Layer)
@@ -36,7 +27,6 @@ namespace gdjs {
export abstract class RuntimeLayer implements EffectsTarget {
_name: string;
_renderingType: RuntimeLayerRenderingType;
_cameraType: RuntimeLayerCameraType;
_timeScale: float = 1;
_defaultZOrder: integer = 0;
_hidden: boolean;
@@ -69,13 +59,12 @@ namespace gdjs {
) {
this._name = layerData.name;
this._renderingType = getRenderingTypeFromString(layerData.renderingType);
this._cameraType = getCameraTypeFromString(layerData.cameraType);
this._hidden = !layerData.visibility;
this._initialCamera3DFieldOfView = layerData.camera3DFieldOfView || 45;
this._initialCamera3DNearPlaneDistance =
layerData.camera3DNearPlaneDistance || 0.1;
this._initialCamera3DFarPlaneDistance =
layerData.camera3DFarPlaneDistance || 2000;
layerData.camera3DFarPlaneDistance || 0.1;
this._initialCamera3DNearPlaneDistance =
layerData.camera3DNearPlaneDistance || 2000;
this._initialEffectsData = layerData.effects || [];
this._runtimeScene = instanceContainer;
this._effectsManager = instanceContainer.getGame().getEffectsManager();
@@ -114,10 +103,6 @@ namespace gdjs {
return this._renderingType;
}
getCameraType(): RuntimeLayerCameraType {
return this._cameraType;
}
/**
* Get the default Z order to be attributed to objects created on this layer
* (usually from events generated code).
@@ -261,7 +246,7 @@ namespace gdjs {
* @param fov The field of view.
* @param cameraId The camera number. Currently ignored.
*/
abstract setCameraZ(z: float, fov: float | null, cameraId?: integer): void;
abstract setCameraZ(z: float, fov: float, cameraId?: integer): void;
/**
* Get the camera center Z position.
@@ -270,7 +255,7 @@ namespace gdjs {
* @param cameraId The camera number. Currently ignored.
* @return The z position of the camera
*/
abstract getCameraZ(fov: float | null, cameraId?: integer): float;
abstract getCameraZ(fov: float, cameraId?: integer): float;
/**
* Get the rotation of the camera, expressed in degrees.

View File

@@ -290,16 +290,6 @@ namespace gdjs {
end: float,
progress: float
) => {
if (progress === 0) {
return start;
}
if (progress === 1) {
return end;
}
if (start <= 0 || end <= 0) {
// The exponential function is flattened to something like a 90° corner.
return 0;
}
const startLog = Math.log(start);
const endLog = Math.log(end);
return Math.exp(startLog + (endLog - startLog) * progress);

View File

@@ -43,22 +43,17 @@ namespace gdjs {
oldGameResolutionOriginX: float,
oldGameResolutionOriginY: float
): void {
// Adapt position of the camera center only if the camera has never moved as:
// * When the camera follows a player/object, it will rarely be at the default position.
// Adapt position of the camera center as:
// * Most cameras following a player/object on the scene will be updating this
// in events anyway.
// * Cameras not following a player/object are usually UIs which are intuitively
// expected not to "move". Not adapting the center position would make the camera
// move from its initial position (which is centered in the screen) - and anchor
// behavior would behave counterintuitively.
if (
this._cameraX === oldGameResolutionOriginX &&
this._cameraY === oldGameResolutionOriginY &&
this._zoomFactor === 1
) {
this._cameraX +=
this._runtimeScene.getViewportOriginX() - oldGameResolutionOriginX;
this._cameraY +=
this._runtimeScene.getViewportOriginY() - oldGameResolutionOriginY;
}
this._cameraX +=
this._runtimeScene.getViewportOriginX() - oldGameResolutionOriginX;
this._cameraY +=
this._runtimeScene.getViewportOriginY() - oldGameResolutionOriginY;
this._renderer.updatePosition();
}
@@ -159,20 +154,18 @@ namespace gdjs {
* @param fov The field of view.
* @param cameraId The camera number. Currently ignored.
*/
setCameraZ(z: float, fov: float | null, cameraId?: integer): void {
if (fov) {
const cameraFovInRadians = gdjs.toRad(fov);
setCameraZ(z: float, fov: float = 45, cameraId?: integer): void {
const cameraFovInRadians = gdjs.toRad(fov);
// The zoom factor is capped to a not too big value to avoid infinity.
// MAX_SAFE_INTEGER is an arbitrary choice. It's big but not too big.
const zoomFactor = Math.min(
Number.MAX_SAFE_INTEGER,
(0.5 * this.getHeight()) / (z * Math.tan(0.5 * cameraFovInRadians))
);
// The zoom factor is capped to a not too big value to avoid infinity.
// MAX_SAFE_INTEGER is an arbitrary choice. It's big but not too big.
const zoomFactor = Math.min(
Number.MAX_SAFE_INTEGER,
(0.5 * this.getHeight()) / (z * Math.tan(0.5 * cameraFovInRadians))
);
if (zoomFactor > 0) {
this._zoomFactor = zoomFactor;
}
if (zoomFactor > 0) {
this._zoomFactor = zoomFactor;
}
this._cameraZ = z;
@@ -187,8 +180,8 @@ namespace gdjs {
* @param cameraId The camera number. Currently ignored.
* @return The z position of the camera
*/
getCameraZ(fov: float | null, cameraId?: integer): float {
if (!this._isCameraZDirty || !fov) {
getCameraZ(fov: float = 45, cameraId?: integer): float {
if (!this._isCameraZDirty) {
return this._cameraZ;
}

View File

@@ -29,6 +29,8 @@ namespace gdjs {
*/
setAnimationName(newAnimationName: string): void;
isCurrentAnimationName(name: string): boolean;
/**
* Return true if animation has ended.
* The animation had ended if:
@@ -115,6 +117,10 @@ namespace gdjs {
this.object.setAnimationName(newAnimationName);
}
isCurrentAnimationName(name: string): boolean {
return this.object.isCurrentAnimationName(name);
}
hasAnimationEnded(): boolean {
return this.object.hasAnimationEnded();
}

View File

@@ -34,10 +34,7 @@ namespace gdjs {
// For a 3D (or 2D+3D) layer:
private _threeGroup: THREE.Group | null = null;
private _threeScene: THREE.Scene | null = null;
private _threeCamera:
| THREE.PerspectiveCamera
| THREE.OrthographicCamera
| null = null;
private _threeCamera: THREE.PerspectiveCamera | null = null;
private _threeCameraDirty: boolean = false;
// For a 2D+3D layer, the 2D rendering is done on the render texture
@@ -104,23 +101,13 @@ namespace gdjs {
}
private _update3DCameraAspectAndPosition() {
if (!this._threeCamera) {
return;
}
if (this._threeCamera instanceof THREE.OrthographicCamera) {
const width = this._layer.getWidth();
const height = this._layer.getHeight();
this._threeCamera.left = -width / 2;
this._threeCamera.right = width / 2;
this._threeCamera.top = height / 2;
this._threeCamera.bottom = -height / 2;
} else {
if (this._threeCamera) {
this._threeCamera.aspect =
this._layer.getWidth() / this._layer.getHeight();
}
this._threeCamera.updateProjectionMatrix();
this._threeCamera.updateProjectionMatrix();
this.updatePosition();
this.updatePosition();
}
}
getRendererObject(): PIXI.Container {
@@ -131,10 +118,7 @@ namespace gdjs {
return this._threeScene;
}
getThreeCamera():
| THREE.PerspectiveCamera
| THREE.OrthographicCamera
| null {
getThreeCamera(): THREE.PerspectiveCamera | null {
return this._threeCamera;
}
@@ -180,28 +164,12 @@ namespace gdjs {
this._threeGroup = new THREE.Group();
this._threeScene.add(this._threeGroup);
if (
this._layer.getCameraType() ===
gdjs.RuntimeLayerCameraType.ORTHOGRAPHIC
) {
const width = this._layer.getWidth();
const height = this._layer.getHeight();
this._threeCamera = new THREE.OrthographicCamera(
-width / 2,
width / 2,
height / 2,
-height / 2,
this._layer.getInitialCamera3DNearPlaneDistance(),
this._layer.getInitialCamera3DFarPlaneDistance()
);
} else {
this._threeCamera = new THREE.PerspectiveCamera(
this._layer.getInitialCamera3DFieldOfView(),
1,
this._layer.getInitialCamera3DNearPlaneDistance(),
this._layer.getInitialCamera3DFarPlaneDistance()
);
}
this._threeCamera = new THREE.PerspectiveCamera(
this._layer.getInitialCamera3DFieldOfView(),
1,
this._layer.getInitialCamera3DNearPlaneDistance(),
this._layer.getInitialCamera3DFarPlaneDistance()
);
this._threeCamera.rotation.order = 'ZYX';
if (
@@ -407,14 +375,9 @@ namespace gdjs {
this._threeCamera.position.y = -this._layer.getCameraY(); // Inverted because the scene is mirrored on Y axis.
this._threeCamera.rotation.z = angle;
if (this._threeCamera instanceof THREE.OrthographicCamera) {
this._threeCamera.zoom = this._layer.getCameraZoom();
this._threeCamera.position.z = this._layer.getCameraZ(null);
} else {
this._threeCamera.position.z = this._layer.getCameraZ(
this._threeCamera.fov
);
}
this._threeCamera.position.z = this._layer.getCameraZ(
this._threeCamera.fov
);
if (this._threePlaneMesh) {
// Adapt the plane size so that it covers the whole screen.
@@ -452,8 +415,6 @@ namespace gdjs {
}
const width = this._layer.getWidth();
const height = this._layer.getHeight();
const normalizedX = (screenX / width) * 2 - 1;
const normalizedY = -(screenY / height) * 2 + 1;
let vector = LayerPixiRenderer.vectorForProjections;
if (!vector) {
@@ -461,31 +422,12 @@ namespace gdjs {
LayerPixiRenderer.vectorForProjections = vector;
}
camera.updateMatrixWorld();
if (camera instanceof THREE.OrthographicCamera) {
// https://discourse.threejs.org/t/how-to-unproject-mouse2d-with-orthographic-camera/4777
vector.set(normalizedX, normalizedY, 0);
vector.unproject(camera);
// The unprojected point is on the camera.
// Find x and y for a given z along the camera direction line.
const direction = new THREE.Vector3();
camera.getWorldDirection(direction);
const distance = (worldZ - vector.z) / direction.z;
vector.x += distance * direction.x;
vector.y += distance * direction.y;
} else {
// https://stackoverflow.com/questions/13055214/mouse-canvas-x-y-to-three-js-world-x-y-z
vector.set(normalizedX, normalizedY, 0.5);
vector.unproject(camera);
// The unprojected point is on the frustum plane.
// Find x and y for a given z along the line between the camera and
// the one on the frustum.
vector.sub(camera.position).normalize();
const distance = (worldZ - camera.position.z) / vector.z;
vector.x = distance * vector.x + camera.position.x;
vector.y = distance * vector.y + camera.position.y;
}
// https://stackoverflow.com/questions/13055214/mouse-canvas-x-y-to-three-js-world-x-y-z
vector.set((screenX / width) * 2 - 1, -(screenY / height) * 2 + 1, 0.5);
vector.unproject(camera);
vector.sub(camera.position).normalize();
const distance = (worldZ - camera.position.z) / vector.z;
vector.multiplyScalar(distance);
// The plane z == worldZ may not be visible on the camera.
if (!Number.isFinite(vector.x) || !Number.isFinite(vector.y)) {
@@ -494,8 +436,8 @@ namespace gdjs {
return result;
}
result[0] = vector.x;
result[1] = -vector.y;
result[0] = camera.position.x + vector.x;
result[1] = -(camera.position.y + vector.y);
return result;
}

View File

@@ -340,15 +340,12 @@ namespace gdjs {
});
const baseTexture = texture.baseTexture;
baseTexture
.on('loaded', () => {
this._loadedTextures.set(resource, texture);
applyTextureSettings(texture, resource);
resolve();
})
.on('error', (error) => {
reject(error);
});
baseTexture.on('loaded', () => {
this._loadedTextures.set(resource, texture);
applyTextureSettings(texture, resource);
resolve();
});
});
} else {
// If the file has no extension, PIXI.assets.load cannot find

View File

@@ -152,7 +152,6 @@ namespace gdjs {
getGlobalResourceNames(data),
data.layouts
);
this._effectsManager = new gdjs.EffectsManager();
this._maxFPS = this._data.properties.maxFPS;
this._minFPS = this._data.properties.minFPS;
@@ -307,24 +306,6 @@ namespace gdjs {
return this._resourcesLoader.getModel3DManager();
}
/**
* Get the Spine manager of the game, used to load and construct spine skeletons from game
* resources.
* @return The Spine manager for the game
*/
getSpineManager(): gdjs.SpineManager | null {
return this._resourcesLoader.getSpineManager();
}
/**
* Get the Spine Atlas manager of the game, used to load atlases from game
* resources.
* @return The Spine Atlas manager for the game
*/
getSpineAtlasManager(): gdjs.SpineAtlasManager | null {
return this._resourcesLoader.getSpineAtlasManager();
}
/**
* Get the input manager of the game, storing mouse, keyboard
* and touches states.
@@ -1171,16 +1152,5 @@ namespace gdjs {
? mapping[embeddedResourceName]
: embeddedResourceName;
}
/**
* Returns the array of resources that are embedded to passed one.
* @param resourceName The name of resource to find embedded resources of.
* @returns The array of related resources names.
*/
getEmbeddedResourcesNames(resourceName: string): string[] {
return this._embeddedResourcesMappings.has(resourceName)
? Object.keys(this._embeddedResourcesMappings.get(resourceName)!)
: [];
}
}
}

View File

@@ -1,4 +0,0 @@
import * as pixi_spine from 'pixi-spine';
export = pixi_spine;
export as namespace pixi_spine;

View File

@@ -146,7 +146,6 @@ declare interface InstanceStringProperty {
declare interface LayerData {
name: string;
renderingType?: '' | '2d' | '3d' | '2d+3d';
cameraType?: 'perspective' | 'orthographic';
visibility: boolean;
cameras: CameraData[];
effects: EffectData[];
@@ -280,6 +279,4 @@ declare type ResourceKind =
| 'tilemap'
| 'tileset'
| 'bitmapFont'
| 'model3D'
| 'atlas'
| 'spine';
| 'model3D';

174
GDJS/package-lock.json generated
View File

@@ -19,7 +19,6 @@
"lebab": "^3.1.0",
"minimist": "^1.2.5",
"patch-package": "^6.4.7",
"pixi-spine": "4.0.4",
"pixi.js": "7.3.0",
"prettier": "2.1.2",
"recursive-readdir": "^2.2.2",
@@ -29,91 +28,6 @@
"typescript": "4.3.2"
}
},
"node_modules/@pixi-spine/base": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@pixi-spine/base/-/base-4.0.3.tgz",
"integrity": "sha512-0bunaWebaDswLFtYZ6whV+ZvgLQ7oANcvbPmIOoVpS/1pOY3Y/GAnWOFbgp3qt9Q/ntLYqNjGve6xq0IqpsTAA==",
"dev": true,
"peerDependencies": {
"@pixi/core": "^7.0.0",
"@pixi/display": "^7.0.0",
"@pixi/graphics": "^7.0.0",
"@pixi/mesh": "^7.0.0",
"@pixi/mesh-extras": "^7.0.0",
"@pixi/sprite": "^7.0.0"
}
},
"node_modules/@pixi-spine/loader-base": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/@pixi-spine/loader-base/-/loader-base-4.0.4.tgz",
"integrity": "sha512-Grgu+PxiUpgYWpuMRr3h5jrN3ZTnwyXfu3HuYdFb6mbJTTMub4xBPALeui+O+tw0k9RNRAr99pUzu9Rc9XTbAw==",
"dev": true,
"peerDependencies": {
"@pixi-spine/base": "^4.0.0",
"@pixi/assets": " ^7.0.0",
"@pixi/core": "^7.0.0"
}
},
"node_modules/@pixi-spine/loader-uni": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@pixi-spine/loader-uni/-/loader-uni-4.0.3.tgz",
"integrity": "sha512-tfhTJrnuog8ObKbbiSG1wV/nIUc3O98WfwS6lCmewaupoMIKF0ujg21MCqXUXJvljQJzU9tbURI+DWu4w9dnnA==",
"dev": true,
"peerDependencies": {
"@pixi-spine/base": "^4.0.0",
"@pixi-spine/loader-base": "^4.0.0",
"@pixi-spine/runtime-3.7": "^4.0.0",
"@pixi-spine/runtime-3.8": "^4.0.0",
"@pixi-spine/runtime-4.1": "^4.0.0",
"@pixi/assets": " ^7.0.0",
"@pixi/core": "^7.0.0",
"@pixi/display": "^7.0.0",
"@pixi/graphics": "^7.0.0",
"@pixi/mesh": "^7.0.0",
"@pixi/mesh-extras": "^7.0.0",
"@pixi/sprite": "^7.0.0"
}
},
"node_modules/@pixi-spine/runtime-3.7": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@pixi-spine/runtime-3.7/-/runtime-3.7-4.0.3.tgz",
"integrity": "sha512-zuopKtSqjRc37wjW5xJ64j9DbiBB7rkPMFeldeWBPCbfZiCcFcwSZwZnrcgC+f4HIGo0NeviAvJGM8Hcf3AyeA==",
"dev": true,
"peerDependencies": {
"@pixi-spine/base": "^4.0.0",
"@pixi/core": "^7.0.0"
}
},
"node_modules/@pixi-spine/runtime-3.8": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@pixi-spine/runtime-3.8/-/runtime-3.8-4.0.3.tgz",
"integrity": "sha512-lIhb4jOTon+FVYLO9AIgcB6jf9hC+RLEn8PesaDRibDocQ1htVCkEIhCIU3Mc00fuqIby7lMBsINeS/Th0q3bw==",
"dev": true,
"peerDependencies": {
"@pixi-spine/base": "^4.0.0",
"@pixi/core": "^7.0.0"
}
},
"node_modules/@pixi-spine/runtime-4.0": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@pixi-spine/runtime-4.0/-/runtime-4.0-4.0.3.tgz",
"integrity": "sha512-2Y8qhxRkg/yH/9VylGsRVAd5W+dXVPhHTjFk0RR9wEUzTCkdZ17pE+56s2nESi2X3sYNKkz8FowfaqIvXnVGxw==",
"dev": true,
"peerDependencies": {
"@pixi-spine/base": "^4.0.0",
"@pixi/core": "^7.0.0"
}
},
"node_modules/@pixi-spine/runtime-4.1": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@pixi-spine/runtime-4.1/-/runtime-4.1-4.0.3.tgz",
"integrity": "sha512-jK433snCQMC4FUPiDgyIcxhiatvRNSxqgs0CgHjjQ0l8GlY6gPpkkdThQ6GsFNme1SUZ4uvnWwawXFIGjW1IpQ==",
"dev": true,
"peerDependencies": {
"@pixi-spine/base": "^4.0.0",
"@pixi/core": "^7.0.0"
}
},
"node_modules/@pixi/accessibility": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/@pixi/accessibility/-/accessibility-7.3.0.tgz",
@@ -1685,30 +1599,6 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/pixi-spine": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/pixi-spine/-/pixi-spine-4.0.4.tgz",
"integrity": "sha512-XRq1yARVoi4av7RXnd9+P37SWI9+e4/f5yTScZPJGB+sY5VcRYN6BYkBQ+y8nUKI1aJIjlms9z+pGxqikm+eFQ==",
"dev": true,
"dependencies": {
"@pixi-spine/base": "^4.0.3",
"@pixi-spine/loader-base": "^4.0.4",
"@pixi-spine/loader-uni": "^4.0.3",
"@pixi-spine/runtime-3.7": "^4.0.3",
"@pixi-spine/runtime-3.8": "^4.0.3",
"@pixi-spine/runtime-4.0": "^4.0.3",
"@pixi-spine/runtime-4.1": "^4.0.3"
},
"peerDependencies": {
"@pixi/assets": "^7.0.0",
"@pixi/core": "^7.0.0",
"@pixi/display": "^7.0.0",
"@pixi/graphics": "^7.0.0",
"@pixi/mesh": "^7.0.0",
"@pixi/mesh-extras": "^7.0.0",
"@pixi/sprite": "^7.0.0"
}
},
"node_modules/pixi.js": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/pixi.js/-/pixi.js-7.3.0.tgz",
@@ -2091,55 +1981,6 @@
}
},
"dependencies": {
"@pixi-spine/base": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@pixi-spine/base/-/base-4.0.3.tgz",
"integrity": "sha512-0bunaWebaDswLFtYZ6whV+ZvgLQ7oANcvbPmIOoVpS/1pOY3Y/GAnWOFbgp3qt9Q/ntLYqNjGve6xq0IqpsTAA==",
"dev": true,
"requires": {}
},
"@pixi-spine/loader-base": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/@pixi-spine/loader-base/-/loader-base-4.0.4.tgz",
"integrity": "sha512-Grgu+PxiUpgYWpuMRr3h5jrN3ZTnwyXfu3HuYdFb6mbJTTMub4xBPALeui+O+tw0k9RNRAr99pUzu9Rc9XTbAw==",
"dev": true,
"requires": {}
},
"@pixi-spine/loader-uni": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@pixi-spine/loader-uni/-/loader-uni-4.0.3.tgz",
"integrity": "sha512-tfhTJrnuog8ObKbbiSG1wV/nIUc3O98WfwS6lCmewaupoMIKF0ujg21MCqXUXJvljQJzU9tbURI+DWu4w9dnnA==",
"dev": true,
"requires": {}
},
"@pixi-spine/runtime-3.7": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@pixi-spine/runtime-3.7/-/runtime-3.7-4.0.3.tgz",
"integrity": "sha512-zuopKtSqjRc37wjW5xJ64j9DbiBB7rkPMFeldeWBPCbfZiCcFcwSZwZnrcgC+f4HIGo0NeviAvJGM8Hcf3AyeA==",
"dev": true,
"requires": {}
},
"@pixi-spine/runtime-3.8": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@pixi-spine/runtime-3.8/-/runtime-3.8-4.0.3.tgz",
"integrity": "sha512-lIhb4jOTon+FVYLO9AIgcB6jf9hC+RLEn8PesaDRibDocQ1htVCkEIhCIU3Mc00fuqIby7lMBsINeS/Th0q3bw==",
"dev": true,
"requires": {}
},
"@pixi-spine/runtime-4.0": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@pixi-spine/runtime-4.0/-/runtime-4.0-4.0.3.tgz",
"integrity": "sha512-2Y8qhxRkg/yH/9VylGsRVAd5W+dXVPhHTjFk0RR9wEUzTCkdZ17pE+56s2nESi2X3sYNKkz8FowfaqIvXnVGxw==",
"dev": true,
"requires": {}
},
"@pixi-spine/runtime-4.1": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@pixi-spine/runtime-4.1/-/runtime-4.1-4.0.3.tgz",
"integrity": "sha512-jK433snCQMC4FUPiDgyIcxhiatvRNSxqgs0CgHjjQ0l8GlY6gPpkkdThQ6GsFNme1SUZ4uvnWwawXFIGjW1IpQ==",
"dev": true,
"requires": {}
},
"@pixi/accessibility": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/@pixi/accessibility/-/accessibility-7.3.0.tgz",
@@ -3362,21 +3203,6 @@
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true
},
"pixi-spine": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/pixi-spine/-/pixi-spine-4.0.4.tgz",
"integrity": "sha512-XRq1yARVoi4av7RXnd9+P37SWI9+e4/f5yTScZPJGB+sY5VcRYN6BYkBQ+y8nUKI1aJIjlms9z+pGxqikm+eFQ==",
"dev": true,
"requires": {
"@pixi-spine/base": "^4.0.3",
"@pixi-spine/loader-base": "^4.0.4",
"@pixi-spine/loader-uni": "^4.0.3",
"@pixi-spine/runtime-3.7": "^4.0.3",
"@pixi-spine/runtime-3.8": "^4.0.3",
"@pixi-spine/runtime-4.0": "^4.0.3",
"@pixi-spine/runtime-4.1": "^4.0.3"
}
},
"pixi.js": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/pixi.js/-/pixi.js-7.3.0.tgz",

View File

@@ -16,7 +16,6 @@
"minimist": "^1.2.5",
"patch-package": "^6.4.7",
"pixi.js": "7.3.0",
"pixi-spine": "4.0.4",
"prettier": "2.1.2",
"recursive-readdir": "^2.2.2",
"shelljs": "^0.8.4",
@@ -24,19 +23,8 @@
"typedoc-plugin-reference-excluder": "^1.0.0",
"typescript": "4.3.2"
},
"overrides": {
"pixi-spine": {
"@pixi/assets": "7.3.0",
"@pixi/core": "7.3.0",
"@pixi/display": "7.3.0",
"@pixi/graphics": "7.3.0",
"@pixi/mesh": "7.3.0",
"@pixi/mesh-extras": "7.3.0",
"@pixi/sprite": "7.3.0"
}
},
"scripts": {
"postinstall": "patch-package && node scripts/install-spine.js",
"postinstall": "patch-package",
"check-types": "tsc",
"build": "node scripts/build.js",
"test": "cd tests && npm run test-benchmark",

View File

@@ -1,36 +0,0 @@
const path = require('path');
const shell = require('shelljs');
const readContent = (path, testErrorMessage) => {
if (!shell.test('-f', path)) throw new Error(`${testErrorMessage} Should exist by ${path}.`);
const readingResult = shell.cat(path);
if (readingResult.stderr) throw new Error(readingResult.stderr);
return readingResult.toString();
};
try {
shell.echo(`Start pixi-spine.js copying...`);
const originalSpineDir = path.resolve('node_modules/pixi-spine');
const originalSpinePackage = JSON.parse(readContent(path.join(originalSpineDir, 'package.json'), 'Cannot find pixi-spine package.json file.'));
const originalSpineContent = readContent(path.join(originalSpineDir, originalSpinePackage.extensionConfig.bundle), 'Cannot find pixi-spine.js.');
const varSpineExport = '\nvar pixi_spine = this.PIXI.spine;\n';
const runtimeSpineDir = '../Extensions/Spine/pixi-spine';
if (!shell.test('-d', runtimeSpineDir)) {
shell.echo(`Creating directory for pixi-spine.js ${runtimeSpineDir}.`);
shell.mkdir(runtimeSpineDir);
}
const runtimeSpinePath = path.join(runtimeSpineDir, 'pixi-spine.js');
new shell.ShellString(originalSpineContent + varSpineExport).to(runtimeSpinePath);
shell.echo(`✅ Properly copied pixi-spine.js from node_modules to ${runtimeSpinePath}.`);
} catch(error) {
shell.echo(`❌ Unable to copy pixi-spine.js from node_modules. Error is: ${error}`)
shell.exit(1);
}

View File

@@ -23,7 +23,6 @@ const transformExcludedExtensions = ['.min.js', '.d.ts'];
const untransformedPaths = [
// GDJS prebuilt files:
'GDJS/Runtime/pixi-renderers/pixi.js',
'GDJS/Runtime/pixi-renderers/pixi-spine.js',
'GDJS/Runtime/pixi-renderers/three.js',
'GDJS/Runtime/pixi-renderers/ThreeAddons.js',
'GDJS/Runtime/pixi-renderers/draco/gltf/draco_wasm_wrapper.js',

View File

@@ -1,101 +0,0 @@
spineboy.png
size: 1024, 256
filter: Linear, Linear
scale: 0.5
crosshair
bounds: 813, 160, 45, 45
eye-indifferent
bounds: 569, 2, 47, 45
eye-surprised
bounds: 643, 7, 47, 45
rotate: 90
front-bracer
bounds: 811, 51, 29, 40
front-fist-closed
bounds: 807, 93, 38, 41
front-fist-open
bounds: 815, 210, 43, 44
front-foot
bounds: 706, 64, 63, 35
rotate: 90
front-shin
bounds: 80, 11, 41, 92
front-thigh
bounds: 754, 12, 23, 56
front-upper-arm
bounds: 618, 5, 23, 49
goggles
bounds: 214, 20, 131, 83
gun
bounds: 347, 14, 105, 102
rotate: 90
head
bounds: 80, 105, 136, 149
hoverboard-board
bounds: 2, 8, 246, 76
rotate: 90
hoverboard-thruster
bounds: 478, 2, 30, 32
hoverglow-small
bounds: 218, 117, 137, 38
rotate: 90
mouth-grind
bounds: 775, 80, 47, 30
rotate: 90
mouth-oooo
bounds: 779, 31, 47, 30
rotate: 90
mouth-smile
bounds: 783, 207, 47, 30
rotate: 90
muzzle-glow
bounds: 779, 4, 25, 25
muzzle-ring
bounds: 451, 14, 25, 105
muzzle01
bounds: 664, 60, 67, 40
rotate: 90
muzzle02
bounds: 580, 56, 68, 42
rotate: 90
muzzle03
bounds: 478, 36, 83, 53
rotate: 90
muzzle04
bounds: 533, 49, 75, 45
rotate: 90
muzzle05
bounds: 624, 56, 68, 38
rotate: 90
neck
bounds: 806, 8, 18, 21
portal-bg
bounds: 258, 121, 133, 133
portal-flare1
bounds: 690, 2, 56, 30
rotate: 90
portal-flare2
bounds: 510, 3, 57, 31
portal-flare3
bounds: 722, 4, 58, 30
rotate: 90
portal-shade
bounds: 393, 121, 133, 133
portal-streaks1
bounds: 528, 126, 126, 128
portal-streaks2
bounds: 656, 129, 125, 125
rear-bracer
bounds: 826, 13, 28, 36
rear-foot
bounds: 743, 70, 57, 30
rotate: 90
rear-shin
bounds: 174, 14, 38, 89
rear-thigh
bounds: 783, 158, 28, 47
rear-upper-arm
bounds: 783, 136, 20, 44
rotate: 90
torso
bounds: 123, 13, 49, 90

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 239 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -41,15 +41,14 @@ module.exports = function (config) {
'./newIDE/app/resources/GDJS/Runtime/AsyncTasksManager.js',
'./newIDE/app/resources/GDJS/Runtime/libs/rbush.js',
'./newIDE/app/resources/GDJS/Runtime/pixi-renderers/pixi.js',
'./newIDE/app/resources/GDJS/Runtime/pixi-renderers/pixi-spine.js',
'./newIDE/app/resources/GDJS/Runtime/pixi-renderers/three.js',
'./newIDE/app/resources/GDJS/Runtime/pixi-renderers/*.js',
'./newIDE/app/resources/GDJS/Runtime/howler-sound-manager/howler.min.js',
'./newIDE/app/resources/GDJS/Runtime/howler-sound-manager/howler-sound-manager.js',
'./newIDE/app/resources/GDJS/Runtime/fontfaceobserver-font-manager/fontfaceobserver.js',
'./newIDE/app/resources/GDJS/Runtime/fontfaceobserver-font-manager/fontfaceobserver-font-manager.js',
'./newIDE/app/resources/GDJS/Runtime/Model3DManager.js',
'./newIDE/app/resources/GDJS/Runtime/jsonmanager.js',
'./newIDE/app/resources/GDJS/Runtime/Model3DManager.js',
'./newIDE/app/resources/GDJS/Runtime/ResourceLoader.js',
'./newIDE/app/resources/GDJS/Runtime/ResourceCache.js',
'./newIDE/app/resources/GDJS/Runtime/timemanager.js',
@@ -121,10 +120,6 @@ module.exports = function (config) {
'./newIDE/app/resources/GDJS/Runtime/Extensions/TextInput/textinputruntimeobject-pixi-renderer.js',
'./newIDE/app/resources/GDJS/Runtime/Extensions/TextObject/textruntimeobject.js',
'./newIDE/app/resources/GDJS/Runtime/Extensions/TextObject/textruntimeobject-pixi-renderer.js',
'./newIDE/app/resources/GDJS/Runtime/Extensions/3D/A_RuntimeObject3D.js',
'./newIDE/app/resources/GDJS/Runtime/Extensions/3D/A_RuntimeObject3DRenderer.js',
'./newIDE/app/resources/GDJS/Runtime/Extensions/3D/Cube3DRuntimeObject.js',
'./newIDE/app/resources/GDJS/Runtime/Extensions/3D/Cube3DRuntimeObjectPixiRenderer.js',
'./newIDE/app/resources/GDJS/Runtime/Extensions/TopDownMovementBehavior/topdownmovementruntimebehavior.js',
'./newIDE/app/resources/GDJS/Runtime/Extensions/TweenBehavior/TweenManager.js',
'./newIDE/app/resources/GDJS/Runtime/Extensions/TweenBehavior/tweentools.js',

View File

@@ -909,8 +909,6 @@ interface Layer {
[Const, Ref] DOMString GetName();
void SetRenderingType([Const] DOMString renderingType);
[Const, Ref] DOMString GetRenderingType();
void SetCameraType([Const] DOMString cameraType);
[Const, Ref] DOMString GetCameraType();
void SetVisibility(boolean visible);
boolean GetVisibility();
void SetLocked(boolean isLocked);
@@ -959,11 +957,9 @@ interface PropertyDescriptor {
[Ref] PropertyDescriptor SetExtraInfo([Const, Ref] VectorString info);
[Ref] VectorString GetExtraInfo();
[Ref] PropertyDescriptor SetHidden(boolean enable);
boolean IsHidden();
[Ref] PropertyDescriptor SetDeprecated(boolean enable);
boolean IsDeprecated();
[Const, Ref] MeasurementUnit GetMeasurementUnit();
[Ref] PropertyDescriptor SetMeasurementUnit([Const, Ref] MeasurementUnit measurementUnit);
boolean IsHidden();
void SerializeTo([Ref] SerializerElement element);
void UnserializeFrom([Const, Ref] SerializerElement element);
@@ -1121,11 +1117,6 @@ interface JsonResource {
};
JsonResource implements Resource;
interface SpineResource {
void SpineResource();
};
SpineResource implements JsonResource;
interface TilemapResource {
void TilemapResource();
};
@@ -1141,11 +1132,6 @@ interface Model3DResource {
};
Model3DResource implements Resource;
interface AtlasResource {
void AtlasResource();
};
AtlasResource implements Resource;
interface InitialInstance {
void InitialInstance();
@@ -1311,12 +1297,6 @@ interface Serializer {
[Value] SerializerElement STATIC_FromJSON([Const] DOMString json);
};
interface ObjectAssetSerializer {
void STATIC_SerializeTo([Ref] Project project, [Const, Ref] gdObject obj,
[Const] DOMString objectFullName, [Ref] SerializerElement element,
[Ref] MapStringString resourcesNewFileNames);
};
interface InstructionsList {
void InstructionsList();
@@ -3048,7 +3028,6 @@ interface ObjectsUsingResourceCollector {
interface ResourcesInUseHelper {
void ResourcesInUseHelper([Ref] ResourcesManager resourcesManager);
[Const, Ref] VectorString GetAllResources();
[Ref] SetString GetAllImages();
[Ref] SetString GetAllAudios();
[Ref] SetString GetAllFonts();
@@ -3220,35 +3199,6 @@ interface Model3DObjectConfiguration {
};
Model3DObjectConfiguration implements ObjectConfiguration;
interface SpineAnimation {
void SpineAnimation();
void SetName([Const] DOMString name);
[Const, Ref] DOMString GetName();
void SetSource([Const] DOMString name);
[Const, Ref] DOMString GetSource();
void SetShouldLoop(boolean shouldLoop);
boolean ShouldLoop();
};
interface SpineObjectConfiguration {
void SpineObjectConfiguration();
void AddAnimation([Const, Ref] SpineAnimation animation);
[Ref] SpineAnimation GetAnimation(unsigned long index);
boolean HasAnimationNamed([Const] DOMString name);
unsigned long GetAnimationsCount();
void RemoveAnimation(unsigned long index);
void RemoveAllAnimations();
boolean HasNoAnimations();
void SwapAnimations(unsigned long first, unsigned long second);
void MoveAnimation(unsigned long oldIndex, unsigned long newIndex);
};
SpineObjectConfiguration implements ObjectConfiguration;
interface Vector2f {
void Vector2f();

View File

@@ -195,10 +195,6 @@ void ObjectJsImplementation::ExposeResources(gd::ArbitraryResourceWorker& worker
worker.ExposeBitmapFont(newPropertyValue);
} else if (resourceType == "model3D") {
worker.ExposeModel3D(newPropertyValue);
} else if (resourceType == "atlas") {
worker.ExposeAtlas(newPropertyValue);
} else if (resourceType == "spine") {
worker.ExposeSpine(newPropertyValue);
}
if (newPropertyValue != oldPropertyValue) {

View File

@@ -86,7 +86,6 @@
#include <GDCore/Project/VariablesContainersList.h>
#include <GDCore/Serialization/Serializer.h>
#include <GDCore/Serialization/SerializerElement.h>
#include <GDCore/IDE/ObjectAssetSerializer.h>
#include <GDJS/Events/Builtin/JsCodeEvent.h>
#include <GDJS/Events/CodeGeneration/BehaviorCodeGenerator.h>
#include <GDJS/Events/CodeGeneration/EventsFunctionsExtensionCodeGenerator.h>
@@ -110,8 +109,6 @@
#include "../../Extensions/TextEntryObject/TextEntryObject.h"
#include "../../Extensions/TextObject/TextObject.h"
#include "../../Extensions/TiledSpriteObject/TiledSpriteObject.h"
#include "../../Extensions/3D/Model3DObjectConfiguration.h"
#include "../../Extensions/Spine/SpineObjectConfiguration.h"
#include "BehaviorJsImplementation.h"
#include "BehaviorSharedDataJsImplementation.h"
#include "ObjectJsImplementation.h"
@@ -542,7 +539,6 @@ typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
#define STATIC_GetSafeName GetSafeName
#define STATIC_ToJSON ToJSON
#define STATIC_FromJSON(x) FromJSON(x)
#define STATIC_SerializeTo SerializeTo
#define STATIC_IsObject IsObject
#define STATIC_IsBehavior IsBehavior
#define STATIC_IsExpression IsExpression
@@ -594,7 +590,6 @@ typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
#define STATIC_ExposeProjectEvents ExposeProjectEvents
#define STATIC_ExposeProjectObjects ExposeProjectObjects
#define STATIC_ExposeWholeProjectResources ExposeWholeProjectResources
#define STATIC_GetResourceTypes GetResourceTypes
#define STATIC_GetBehaviorMetadata GetBehaviorMetadata
#define STATIC_GetObjectMetadata GetObjectMetadata
@@ -759,7 +754,6 @@ typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
#define STATIC_ShiftSentenceParamIndexes ShiftSentenceParamIndexes
#define STATIC_CopyAllResourcesTo CopyAllResourcesTo
#define STATIC_CopyObjectResourcesTo CopyObjectResourcesTo
#define STATIC_IsExtensionLifecycleEventsFunction \
IsExtensionLifecycleEventsFunction

View File

@@ -150,9 +150,6 @@ var adaptNamingConventions = function (gd) {
gd.asModel3DConfiguration = function (evt) {
return gd.castObject(evt, gd.Model3DObjectConfiguration);
};
gd.asSpineConfiguration = function (evt) {
return gd.castObject(evt, gd.SpineObjectConfiguration);
};
gd.asImageResource = function (evt) {
return gd.castObject(evt, gd.ImageResource);

View File

@@ -119,4 +119,3 @@ target_link_libraries(GD PathfindingBehavior)
target_link_libraries(GD PhysicsBehavior)
target_link_libraries(GD ParticleSystem)
target_link_libraries(GD Scene3D)
target_link_libraries(GD SpineObject)

View File

@@ -13,7 +13,7 @@ module.exports = function (grunt) {
let cmakeBinary = 'emcmake cmake';
let cmakeGeneratorArgs = [];
let makeBinary = 'emmake make';
let makeArgs = ['-j 8'];
let makeArgs = ['-j 4'];
// Use more specific paths on Windows
if (isWin) {

View File

@@ -1,4 +1,5 @@
const shell = require('shelljs');
const fs = require('fs');
const path = require('path');
const sourcePath = path.join(__dirname, '../../Binaries/embuild/GDevelop.js');

View File

@@ -199,7 +199,6 @@ type ParticleEmitterObject_RendererType = 0 | 1 | 2`
` asObjectJsImplementation(gdObjectConfiguration): gdObjectJsImplementation;`,
` asCustomObjectConfiguration(gdObjectConfiguration): gdCustomObjectConfiguration;`,
` asModel3DConfiguration(gdObjectConfiguration): gdModel3DObjectConfiguration;`,
` asSpineConfiguration(gdObjectConfiguration): gdSpineObjectConfiguration;`,
'',
` asImageResource(gdResource): gdImageResource;`,
'',
@@ -308,12 +307,6 @@ type ParticleEmitterObject_RendererType = 0 | 1 | 2`
'declare class gdGroupEvent extends gdBaseEvent {',
'types/gdgroupevent.js'
);
shell.sed(
'-i',
'declare class gdAbstractFileSystemJS {',
'declare class gdAbstractFileSystemJS extends gdAbstractFileSystem {',
'types/gdabstractfilesystemjs.js'
);
[
'BaseEvent',
'StandardEvent',
@@ -345,13 +338,13 @@ type ParticleEmitterObject_RendererType = 0 | 1 | 2`
shell.sed(
'-i',
/setKind\(kind: string\): void/,
"setKind(kind: 'image' | 'audio' | 'font' | 'video' | 'json' | 'tilemap' | 'tileset' | 'model3D' | 'atlas' | 'spine'): void",
"setKind(kind: 'image' | 'audio' | 'font' | 'video' | 'json' | 'tilemap' | 'tileset' | 'model3D'): void",
'types/gdresource.js'
);
shell.sed(
'-i',
/getKind\(\): string/,
"getKind(): 'image' | 'audio' | 'font' | 'video' | 'json' | 'tilemap' | 'tileset' | 'model3D' | 'atlas' | 'spine'",
"getKind(): 'image' | 'audio' | 'font' | 'video' | 'json' | 'tilemap' | 'tileset' | 'model3D'",
'types/gdresource.js'
);

View File

@@ -796,8 +796,6 @@ export class Layer extends EmscriptenObject {
getName(): string;
setRenderingType(renderingType: string): void;
getRenderingType(): string;
setCameraType(cameraType: string): void;
getCameraType(): string;
setVisibility(visible: boolean): void;
getVisibility(): boolean;
setLocked(isLocked: boolean): void;
@@ -839,11 +837,9 @@ export class PropertyDescriptor extends EmscriptenObject {
setExtraInfo(info: VectorString): PropertyDescriptor;
getExtraInfo(): VectorString;
setHidden(enable: boolean): PropertyDescriptor;
isHidden(): boolean;
setDeprecated(enable: boolean): PropertyDescriptor;
isDeprecated(): boolean;
getMeasurementUnit(): MeasurementUnit;
setMeasurementUnit(measurementUnit: MeasurementUnit): PropertyDescriptor;
isHidden(): boolean;
serializeTo(element: SerializerElement): void;
unserializeFrom(element: SerializerElement): void;
serializeValuesTo(element: SerializerElement): void;
@@ -978,10 +974,6 @@ export class JsonResource extends EmscriptenObject {
constructor(): void;
}
export class SpineResource extends EmscriptenObject {
constructor(): void;
}
export class TilemapResource extends EmscriptenObject {
constructor(): void;
}
@@ -990,10 +982,6 @@ export class TilesetResource extends EmscriptenObject {
constructor(): void;
}
export class AtlasResource extends EmscriptenObject {
constructor(): void;
}
export class InitialInstance extends EmscriptenObject {
constructor(): void;
setObjectName(name: string): void;
@@ -1126,10 +1114,6 @@ export class Serializer extends EmscriptenObject {
static fromJSON(json: string): SerializerElement;
}
export class ObjectAssetSerializer extends EmscriptenObject {
static serializeTo(project: Project, obj: gdObject, objectFullName: string, element: SerializerElement, resourcesNewFileNames: MapStringString): void;
}
export class InstructionsList extends EmscriptenObject {
constructor(): void;
insert(instr: Instruction, pos: number): Instruction;
@@ -2338,7 +2322,6 @@ export class ObjectsUsingResourceCollector extends EmscriptenObject {
export class ResourcesInUseHelper extends EmscriptenObject {
constructor(resourcesManager: ResourcesManager): void;
getAllResources(): VectorString;
getAllImages(): SetString;
getAllAudios(): SetString;
getAllFonts(): SetString;
@@ -2439,29 +2422,6 @@ export class SpriteObject extends EmscriptenObject {
setAdaptCollisionMaskAutomatically(adaptCollisionMaskAutomatically: boolean): void;
}
export class SpineAnimation extends EmscriptenObject {
constructor(): void;
setName(name: string): void;
getName(): string;
setSource(name: string): void;
getSource(): string;
setShouldLoop(shouldLoop: boolean): void;
shouldLoop(): boolean;
}
export class SpineObjectConfiguration extends EmscriptenObject {
constructor(): void;
addAnimation(animation: SpineAnimation): void;
getAnimation(index: number): SpineAnimation;
hasAnimationNamed(name: string): boolean;
getAnimationsCount(): number;
removeAnimation(index: number): void;
removeAllAnimations(): void;
hasNoAnimations(): boolean;
swapAnimations(first: number, second: number): void;
moveAnimation(oldIndex: number, newIndex: number): void;
}
export class TextObject extends EmscriptenObject {
constructor(): void;
setString(string: string): void;

View File

@@ -1,5 +1,5 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdAbstractFileSystemJS extends gdAbstractFileSystem {
declare class gdAbstractFileSystemJS {
constructor(): void;
mkDir(dir: string): void;
dirExists(dir: string): void;

View File

@@ -1,6 +0,0 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdAtlasResource extends gdResource {
constructor(): void;
delete(): void;
ptr: number;
};

View File

@@ -5,8 +5,6 @@ declare class gdLayer {
getName(): string;
setRenderingType(renderingType: string): void;
getRenderingType(): string;
setCameraType(cameraType: string): void;
getCameraType(): string;
setVisibility(visible: boolean): void;
getVisibility(): boolean;
setLocked(isLocked: boolean): void;

View File

@@ -1,6 +0,0 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdObjectAssetSerializer {
static serializeTo(project: gdProject, obj: gdObject, objectFullName: string, element: gdSerializerElement, resourcesNewFileNames: gdMapStringString): void;
delete(): void;
ptr: number;
};

View File

@@ -15,11 +15,9 @@ declare class gdPropertyDescriptor {
setExtraInfo(info: gdVectorString): gdPropertyDescriptor;
getExtraInfo(): gdVectorString;
setHidden(enable: boolean): gdPropertyDescriptor;
isHidden(): boolean;
setDeprecated(enable: boolean): gdPropertyDescriptor;
isDeprecated(): boolean;
getMeasurementUnit(): gdMeasurementUnit;
setMeasurementUnit(measurementUnit: gdMeasurementUnit): gdPropertyDescriptor;
isHidden(): boolean;
serializeTo(element: gdSerializerElement): void;
unserializeFrom(element: gdSerializerElement): void;
serializeValuesTo(element: gdSerializerElement): void;

View File

@@ -4,8 +4,8 @@ declare class gdResource {
clone(): gdResource;
setName(name: string): void;
getName(): string;
setKind(kind: 'image' | 'audio' | 'font' | 'video' | 'json' | 'tilemap' | 'tileset' | 'model3D' | 'atlas' | 'spine'): void;
getKind(): 'image' | 'audio' | 'font' | 'video' | 'json' | 'tilemap' | 'tileset' | 'model3D' | 'atlas' | 'spine';
setKind(kind: 'image' | 'audio' | 'font' | 'video' | 'json' | 'tilemap' | 'tileset' | 'model3D'): void;
getKind(): 'image' | 'audio' | 'font' | 'video' | 'json' | 'tilemap' | 'tileset' | 'model3D';
isUserAdded(): boolean;
setUserAdded(yes: boolean): void;
useFile(): boolean;

View File

@@ -1,7 +1,6 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdResourcesInUseHelper extends gdArbitraryResourceWorker {
constructor(resourcesManager: gdResourcesManager): void;
getAllResources(): gdVectorString;
getAllImages(): gdSetString;
getAllAudios(): gdSetString;
getAllFonts(): gdSetString;

View File

@@ -1,12 +0,0 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdSpineAnimation {
constructor(): void;
setName(name: string): void;
getName(): string;
setSource(name: string): void;
getSource(): string;
setShouldLoop(shouldLoop: boolean): void;
shouldLoop(): boolean;
delete(): void;
ptr: number;
};

View File

@@ -1,15 +0,0 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdSpineObjectConfiguration extends gdObjectConfiguration {
constructor(): void;
addAnimation(animation: gdSpineAnimation): void;
getAnimation(index: number): gdSpineAnimation;
hasAnimationNamed(name: string): boolean;
getAnimationsCount(): number;
removeAnimation(index: number): void;
removeAllAnimations(): void;
hasNoAnimations(): boolean;
swapAnimations(first: number, second: number): void;
moveAnimation(oldIndex: number, newIndex: number): void;
delete(): void;
ptr: number;
};

View File

@@ -1,6 +0,0 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdSpineResource extends gdJsonResource {
constructor(): void;
delete(): void;
ptr: number;
};

View File

@@ -36,7 +36,6 @@ declare class libGDevelop {
asObjectJsImplementation(gdObjectConfiguration): gdObjectJsImplementation;
asCustomObjectConfiguration(gdObjectConfiguration): gdCustomObjectConfiguration;
asModel3DConfiguration(gdObjectConfiguration): gdModel3DObjectConfiguration;
asSpineConfiguration(gdObjectConfiguration): gdSpineObjectConfiguration;
asImageResource(gdResource): gdImageResource;
@@ -110,11 +109,9 @@ declare class libGDevelop {
BitmapFontResource: Class<gdBitmapFontResource>;
VideoResource: Class<gdVideoResource>;
JsonResource: Class<gdJsonResource>;
SpineResource: Class<gdSpineResource>;
TilemapResource: Class<gdTilemapResource>;
TilesetResource: Class<gdTilesetResource>;
Model3DResource: Class<gdModel3DResource>;
AtlasResource: Class<gdAtlasResource>;
InitialInstance: Class<gdInitialInstance>;
InitialInstancesContainer: Class<gdInitialInstancesContainer>;
HighestZOrderFinder: Class<gdHighestZOrderFinder>;
@@ -125,7 +122,6 @@ declare class libGDevelop {
SerializerElement: Class<gdSerializerElement>;
SharedPtrSerializerElement: Class<gdSharedPtrSerializerElement>;
Serializer: Class<gdSerializer>;
ObjectAssetSerializer: Class<gdObjectAssetSerializer>;
InstructionsList: Class<gdInstructionsList>;
Instruction: Class<gdInstruction>;
Expression: Class<gdExpression>;
@@ -234,8 +230,6 @@ declare class libGDevelop {
SpriteObject: Class<gdSpriteObject>;
Model3DAnimation: Class<gdModel3DAnimation>;
Model3DObjectConfiguration: Class<gdModel3DObjectConfiguration>;
SpineAnimation: Class<gdSpineAnimation>;
SpineObjectConfiguration: Class<gdSpineObjectConfiguration>;
Vector2f: Class<gdVector2f>;
VectorVector2f: Class<gdVectorVector2f>;
TextObject: Class<gdTextObject>;

View File

@@ -16,47 +16,7 @@ skip_tags: true # Don't rebuild on tags.
init:
- ps: Install-Product node 16
- cmd: set NODE_OPTIONS=--max-old-space-size=8192
cache:
- '%APPDATA%\npm-cache' # npm cache
- newIDE\app\node_modules -> newIDE\app\package-lock.json
- newIDE\electron-app\node_modules -> newIDE\electron-app\package-lock.json
- GDevelop.js\node_modules -> GDevelop.js\package-lock.json
install:
# Download and install SSL.com eSigner CKA.
# See https://www.ssl.com/how-to/how-to-integrate-esigner-cka-with-ci-cd-tools-for-automated-code-signing/.
#
# This is necessary because of "signing to be FIPS-140 compliant". See
# https://github.com/electron-userland/electron-builder/issues/6158
#
# Make sure to DISABLE "malware blocker" in SSL.com to avoid errors like:
# Error information: "Error: SignerSign() failed." (-2146893821/0x80090003)
- ps: >-
# Download and Unzip eSignerCKA Setup
Set-StrictMode -Version 'Latest'
Invoke-WebRequest -OutFile eSigner_CKA_Setup.zip "https://github.com/SSLcom/eSignerCKA/releases/download/v1.0.6/SSL.COM-eSigner-CKA_1.0.6.zip"
Expand-Archive -Force eSigner_CKA_Setup.zip
Remove-Item eSigner_CKA_Setup.zip
Move-Item -Destination "eSigner_CKA_Installer.exe" -Path "eSigner_CKA_*\*.exe"
# Install it. See https://www.ssl.com/how-to/how-to-integrate-esigner-cka-with-ci-cd-tools-for-automated-code-signing/
New-Item -ItemType Directory -Force -Path "C:\projects\gdevelop\eSignerCKA"
./eSigner_CKA_Installer.exe /CURRENTUSER /VERYSILENT /SUPPRESSMSGBOXES /DIR="C:\projects\gdevelop\eSignerCKA" | Out-Null
# Disable logger.
# $LogConfig = Get-Content -Path C:\projects\gdevelop\eSignerCKA/log4net.config
# $LogConfig[0] = '<log4net threshold="OFF">'
# $LogConfig | Set-Content -Path C:\projects\gdevelop\eSignerCKA/log4net.config
# Build GDevelop.js (and run tests to ensure it works).
# (in a subshell to avoid Emscripten polluting the Node.js and npm version for the rest of the build)
- cmd: >-
@@ -79,7 +39,7 @@ install:
# setuptools will make distutils available again (but we should migrate our packages probably).
- cmd: >-
pip install setuptools
cd newIDE\app
npm -v && npm install
@@ -90,54 +50,21 @@ install:
cd ..\..
# Package the app for Windows (and sign it).
# Package the app for Windows (and sign it with the certificate set in environment variables).
# Don't sign the appx (it will be signed by the Microsoft Store).
build_script:
- ps: >-
cd newIDE\electron-app
# Prepare certificate. See https://www.ssl.com/how-to/automate-ev-code-signing-with-signtool-or-certutil-esigner/?_gl=1*vuybcy*_gcl_au*MTEwODg1NDM2Mi4xNzA1ODU1NjM4#automated-code-signing
C:\projects\gdevelop\eSignerCKA/eSignerCKATool.exe config -mode product -user "$Env:ESIGNER_USER_NAME" -pass "$Env:ESIGNER_USER_PASSWORD" -totp "$Env:ESIGNER_USER_TOTP" -key "C:\projects\gdevelop\eSignerCKA\master.key" -r
C:\projects\gdevelop\eSignerCKA/eSignerCKATool.exe unload
C:\projects\gdevelop\eSignerCKA/eSignerCKATool.exe load
# Find certificate so we can tell electron-builder which one to use.
$CodeSigningCert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert | Select-Object -First 1
echo Certificate: $CodeSigningCert
# Use a custom signtool path because of the signtool.exe bundled withy electron-builder not working for some reason.
# Can also be found in versioned folders like "C:/Program Files (x86)/Windows Kits/10/bin/10.0.22000.0/x86/signtool.exe".
$Env:SIGNTOOL_PATH = "C:\Program Files (x86)\Windows Kits\10\App Certification Kit\signtool.exe"
# Extract thumbprint and subject name of the certificate (will be passed to electron-builder).
$Env:GD_SIGNTOOL_THUMBPRINT = $CodeSigningCert.Thumbprint
$Env:GD_SIGNTOOL_SUBJECT_NAME = ($CodeSigningCert.Subject -replace ", ?", "`n" | ConvertFrom-StringData).CN
# Build the nsis installer (signed: electron-builder will use SignTool.exe with the certificate)
node scripts/build.js --win nsis --publish=never
# Build the appx (not signed).
$Env:GD_SIGNTOOL_THUMBPRINT = ''
$Env:GD_SIGNTOOL_SUBJECT_NAME = ''
node scripts/build.js --skip-app-build --win appx --publish=never
Remove-Item -Path Env:CSC_LINK ; Remove-Item -Path Env:CSC_KEY_PASSWORD ; node scripts/build.js --skip-app-build --win appx --publish=never
cd ..\..
# Clean dist folder to keep only installers/binaries.
- cmd: >-
rmdir /s /q newIDE\electron-app\dist\win-unpacked
DEL /F/Q/S newIDE\electron-app\dist\win-unpacked
# Run a few tests on Windows.
test_script:

View File

@@ -1,7 +1,6 @@
// @flow
import GDevelopJsInitializerDecorator from '../src/stories/GDevelopJsInitializerDecorator';
import i18nProviderDecorator from '../src/stories/I18nProviderDecorator';
import BrowserDropDownMenuDisablerDecorator from '../src/stories/BrowserDropDownMenuDisablerDecorator';
import '../src/UI/icomoon-font.css'; // Styles for Icomoon font.
import './app-level-styling.css';
@@ -36,6 +35,5 @@ export const parameters = {
export const decorators = [
GDevelopJsInitializerDecorator,
i18nProviderDecorator,
BrowserDropDownMenuDisablerDecorator
i18nProviderDecorator
]

Some files were not shown because too many files have changed in this diff Show More