mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
43 Commits
v5.0.0-bet
...
v5.0.0-bet
Author | SHA1 | Date | |
---|---|---|---|
![]() |
25acb603b4 | ||
![]() |
27d4ead51e | ||
![]() |
1704d196f9 | ||
![]() |
d40e360b8a | ||
![]() |
183a0bd08e | ||
![]() |
8780f2f415 | ||
![]() |
5adb3c92ee | ||
![]() |
a54ee812bd | ||
![]() |
f8db01706d | ||
![]() |
d9368921af | ||
![]() |
12743f6f7e | ||
![]() |
3d3048906e | ||
![]() |
413fbc529e | ||
![]() |
287ebd4244 | ||
![]() |
f2199c8ab4 | ||
![]() |
64b63d4efa | ||
![]() |
3820c2613a | ||
![]() |
c42603bb29 | ||
![]() |
b879d3043f | ||
![]() |
8be448fd0e | ||
![]() |
9535fbca0f | ||
![]() |
6667a0005c | ||
![]() |
860faae853 | ||
![]() |
dd47c7f6c4 | ||
![]() |
c4f76efbcd | ||
![]() |
56d9dc05f1 | ||
![]() |
599ccb677f | ||
![]() |
b97f716c09 | ||
![]() |
58917aec02 | ||
![]() |
fdaba4a6d5 | ||
![]() |
d1f49cd1f7 | ||
![]() |
71a9a3f1d0 | ||
![]() |
9173e704be | ||
![]() |
1a27f689e0 | ||
![]() |
ef198b2c64 | ||
![]() |
d5039b5b51 | ||
![]() |
4b19696523 | ||
![]() |
32978c22e8 | ||
![]() |
1f6f2701ff | ||
![]() |
fbf2340f00 | ||
![]() |
4ff208b39f | ||
![]() |
3d0a893c1c | ||
![]() |
2581021a57 |
@@ -12,8 +12,12 @@ jobs:
|
||||
|
||||
# System dependencies (for Emscripten and upload)
|
||||
- run:
|
||||
name: Install dependencies for Emscripten and AWS S3 upload
|
||||
command: brew install cmake && brew install awscli
|
||||
name: Install dependencies for Emscripten
|
||||
command: brew install cmake
|
||||
|
||||
- run:
|
||||
name: Install dependencies for AWS S3 upload
|
||||
command: curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg" && sudo installer -pkg AWSCLIV2.pkg -target /
|
||||
|
||||
- run:
|
||||
name: Install Emscripten (for GDevelop.js)
|
||||
@@ -64,10 +68,10 @@ jobs:
|
||||
# Upload artifacts (AWS)
|
||||
- run:
|
||||
name: Deploy to S3 (specific commit)
|
||||
command: aws s3 sync newIDE/electron-app/dist s3://gdevelop-releases/$(git rev-parse --abbrev-ref HEAD)/commit/$(git rev-parse HEAD)/
|
||||
command: export PATH=~/.local/bin:$PATH && aws s3 sync newIDE/electron-app/dist s3://gdevelop-releases/$(git rev-parse --abbrev-ref HEAD)/commit/$(git rev-parse HEAD)/
|
||||
- run:
|
||||
name: Deploy to S3 (latest)
|
||||
command: aws s3 sync newIDE/electron-app/dist s3://gdevelop-releases/$(git rev-parse --abbrev-ref HEAD)/latest/
|
||||
command: export PATH=~/.local/bin:$PATH && aws s3 sync newIDE/electron-app/dist s3://gdevelop-releases/$(git rev-parse --abbrev-ref HEAD)/latest/
|
||||
|
||||
build-linux:
|
||||
# CircleCI docker workers are failing if they don't have enough memory (no swap)
|
||||
|
@@ -13,6 +13,5 @@
|
||||
-fPIC
|
||||
-I./ExtLibs/SFML/include
|
||||
-I./Core
|
||||
-I./GDCpp/.
|
||||
-I./GDJS/.
|
||||
-F./ExtLibs/SFML/extlibs/libs-osx/Frameworks
|
||||
|
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1,6 +1,5 @@
|
||||
Core/GDCore/Serialization/rapidjson/rapidjson.h/* linguist-vendored
|
||||
Core/GDCore/TinyXml/* linguist-vendored
|
||||
GDCpp/GDCpp/Runtime/TinyXml/* linguist-vendored
|
||||
Extensions/ParticleSystem/SPARK/* linguist-vendored
|
||||
Extensions/PhysicsBehavior/Box2D/* linguist-vendored
|
||||
Extensions/PhysicsBehavior/box2djs/* linguist-vendored
|
||||
|
8
.github/workflows/issues.yml
vendored
8
.github/workflows/issues.yml
vendored
@@ -18,3 +18,11 @@ jobs:
|
||||
type: "body"
|
||||
regex: ".*_instance.getRawFloatProperty is not a function.*"
|
||||
message: "Hi @${issue.user.login}! 👋 This issue was automatically closed as this seems to be a known bug. It can be solved by **closing entirely the web-app and opening it again**. This will allow the web-app to auto-update and the problem should be gone."
|
||||
- name: Autoclose known beta 114 web-app update bug
|
||||
uses: arkon/issue-closer-action@v1.1
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
type: "body"
|
||||
regex: ".*getAssociatedSettings is not a function.*"
|
||||
message: "Hi @${issue.user.login}! 👋 This issue was automatically closed as this seems to be a known bug. It can be solved by **closing entirely the web-app and opening it again**. This will allow the web-app to auto-update and the problem should be gone."
|
||||
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,4 +1,3 @@
|
||||
/Core/GDCore/Tools/VersionPriv.h
|
||||
/docs
|
||||
/docs-wiki
|
||||
/ExtLibs/SFML
|
||||
@@ -16,7 +15,6 @@
|
||||
*.bc
|
||||
/Binaries/Output
|
||||
*.autosave
|
||||
!/GDCpp/scripts/bcp.exe
|
||||
!/scripts/libgettextlib-0-17.dll
|
||||
!/scripts/libgettextsrc-0-17.dll
|
||||
!/xgettext.exe
|
||||
|
105
.semaphore/semaphore.yml
Normal file
105
.semaphore/semaphore.yml
Normal file
@@ -0,0 +1,105 @@
|
||||
version: v1.0
|
||||
name: Fast tests (not building GDevelop.js - can have false negatives)
|
||||
agent:
|
||||
machine:
|
||||
type: e1-standard-2
|
||||
os_image: ubuntu2004
|
||||
auto_cancel:
|
||||
running:
|
||||
when: "true"
|
||||
blocks:
|
||||
- name: Install
|
||||
task:
|
||||
jobs:
|
||||
- name: Install node_modules and cache them
|
||||
commands:
|
||||
- checkout
|
||||
- node -v
|
||||
- |-
|
||||
if ! cache has_key newIDE-app-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum newIDE/app/package-lock.json); then
|
||||
cd newIDE/app
|
||||
npm i
|
||||
cd ../..
|
||||
cache store newIDE-app-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum newIDE/app/package-lock.json) newIDE/app/node_modules
|
||||
fi
|
||||
- |-
|
||||
if ! cache has_key GDJS-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/package-lock.json); then
|
||||
cd GDJS
|
||||
npm i
|
||||
cd ..
|
||||
cache store GDJS-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/package-lock.json) GDJS/node_modules
|
||||
fi
|
||||
- |-
|
||||
if ! cache has_key GDJS-tests-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/tests/package-lock.json); then
|
||||
cd GDJS/tests
|
||||
npm i
|
||||
cd ../..
|
||||
cache store GDJS-tests-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/tests/package-lock.json) GDJS/tests/node_modules
|
||||
fi
|
||||
dependencies: []
|
||||
- name: Type checks
|
||||
dependencies:
|
||||
- Install
|
||||
task:
|
||||
jobs:
|
||||
- name: newIDE typing
|
||||
commands:
|
||||
- checkout
|
||||
- cache restore newIDE-app-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum newIDE/app/package-lock.json)
|
||||
- cache restore GDJS-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/package-lock.json)
|
||||
- cd newIDE/app
|
||||
- npm run postinstall
|
||||
- npm run flow
|
||||
- cd ../..
|
||||
- name: GDJS typing and documentation generation
|
||||
commands:
|
||||
- checkout
|
||||
- cache restore GDJS-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/package-lock.json)
|
||||
- cache restore GDJS-tests-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/tests/package-lock.json)
|
||||
- cd GDJS
|
||||
- npm run check-types
|
||||
- npm run generate-doc
|
||||
- name: Auto formatting
|
||||
dependencies:
|
||||
- Install
|
||||
task:
|
||||
jobs:
|
||||
- name: newIDE auto-formatting
|
||||
commands:
|
||||
- checkout
|
||||
- cache restore newIDE-app-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum newIDE/app/package-lock.json)
|
||||
- cache restore GDJS-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/package-lock.json)
|
||||
- cd newIDE/app
|
||||
- npm run postinstall
|
||||
- npm run check-format
|
||||
- cd ../..
|
||||
- name: GDJS auto-formatting
|
||||
commands:
|
||||
- checkout
|
||||
- cache restore GDJS-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/package-lock.json)
|
||||
- cd GDJS
|
||||
- npm run check-format
|
||||
- cd ..
|
||||
- name: Tests
|
||||
dependencies:
|
||||
- Install
|
||||
task:
|
||||
jobs:
|
||||
- name: newIDE tests
|
||||
commands:
|
||||
- checkout
|
||||
- cache restore newIDE-app-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum newIDE/app/package-lock.json)
|
||||
- cache restore GDJS-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/package-lock.json)
|
||||
- cd newIDE/app
|
||||
- npm run postinstall
|
||||
- npm run analyze-test-coverage
|
||||
- cd ../..
|
||||
- name: GDJS tests
|
||||
commands:
|
||||
- checkout
|
||||
- cache restore GDJS-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/package-lock.json)
|
||||
- cache restore GDJS-tests-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/tests/package-lock.json)
|
||||
- cd GDJS
|
||||
- npm run build
|
||||
- npm run test
|
||||
- cd ../..
|
11
.travis.yml
11
.travis.yml
@@ -1,5 +1,5 @@
|
||||
# Travis CI configuration to build and run all tests
|
||||
# (and typing/formatting) for the Core, newIDE, GDJS (and even GDCpp).
|
||||
# (and typing/formatting) for the Core, newIDE, GDJS.
|
||||
#
|
||||
# This builds GDevelop.js and store it on a S3 so it can be used to run
|
||||
# GDevelop without building it.
|
||||
@@ -62,7 +62,7 @@ before_install:
|
||||
install:
|
||||
#Get the correct version of gcc/g++
|
||||
- if [ "$CXX" = "g++" ]; then export CXX="g++-${GCC_VERSION}" CC="gcc-${GCC_VERSION}"; fi
|
||||
#Compile the tests only for GDCore and GDCpp
|
||||
#Compile the tests only for GDCore
|
||||
- mkdir .build-tests
|
||||
- cd .build-tests
|
||||
- cmake -DBUILD_GDJS=FALSE -DBUILD_TESTS=TRUE -DCMAKE_CXX_COMPILER=$(which $CXX) -DCMAKE_C_COMPILER=$(which $CC) ..
|
||||
@@ -89,12 +89,9 @@ install:
|
||||
- cd ../..
|
||||
|
||||
script:
|
||||
# GDCore and GDCpp game engine tests:
|
||||
# GDCore tests:
|
||||
- cd .build-tests
|
||||
- Core/GDCore_tests
|
||||
- GDCpp/GDCpp_tests
|
||||
- Extensions/PathfindingBehavior/PathfindingBehavior_Runtime_tests
|
||||
- Extensions/LinkedObjects/LinkedObjects_Runtime_tests
|
||||
- cd ..
|
||||
# GDevelop.js tests
|
||||
- cd GDevelop.js
|
||||
@@ -111,6 +108,6 @@ script:
|
||||
- npm run check-format
|
||||
- cd ..
|
||||
# GDJS game engine tests, disabled on Travis CI because ChromeHeadless can't be started.
|
||||
# See them running on Semaphore-CI instead: https://semaphoreci.com/4ian/gd
|
||||
# See them running on Semaphore-CI instead: https://gdevelop.semaphoreci.com/projects/GDevelop
|
||||
# - cd GDJS/tests && npm test
|
||||
# - cd ../..
|
||||
|
200
.vscode/c_cpp_properties.json
vendored
200
.vscode/c_cpp_properties.json
vendored
@@ -1,98 +1,104 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Mac",
|
||||
"includePath": [
|
||||
"${workspaceRoot}",
|
||||
"${workspaceRoot}/GDCpp",
|
||||
"${workspaceRoot}/GDJS",
|
||||
"${workspaceRoot}/Extensions",
|
||||
"${workspaceRoot}/Core",
|
||||
"${workspaceRoot}/ExtLibs/SFML/include",
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1",
|
||||
"/usr/local/include",
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include",
|
||||
"/usr/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"defines": [
|
||||
"EMSCRIPTEN",
|
||||
"GD_IDE_ONLY",
|
||||
"GD_CORE_API=/* Macro used to export classes on Windows, please ignore */",
|
||||
"GD_API=/* Macro used to export classes on Windows, please ignore */",
|
||||
"GD_EXTENSION_API=/* Macro used to export classes on Windows, please ignore */"
|
||||
],
|
||||
"intelliSenseMode": "clang-x64",
|
||||
"browse": {
|
||||
"path": [
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1",
|
||||
"/usr/local/include",
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include",
|
||||
"/usr/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
},
|
||||
"macFrameworkPath": ["/System/Library/Frameworks", "/Library/Frameworks"],
|
||||
"compilerPath": "/usr/bin/clang",
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++17"
|
||||
},
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceRoot}",
|
||||
"${workspaceRoot}/GDCpp",
|
||||
"${workspaceRoot}/GDJS",
|
||||
"${workspaceRoot}/Extensions",
|
||||
"${workspaceRoot}/Core",
|
||||
"${workspaceRoot}/ExtLibs/SFML/include",
|
||||
"/usr/include",
|
||||
"/usr/local/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"defines": [
|
||||
"EMSCRIPTEN",
|
||||
"GD_IDE_ONLY",
|
||||
"GD_CORE_API=/* Macro used to export classes on Windows, please ignore */",
|
||||
"GD_API=/* Macro used to export classes on Windows, please ignore */",
|
||||
"GD_EXTENSION_API=/* Macro used to export classes on Windows, please ignore */"
|
||||
],
|
||||
"intelliSenseMode": "clang-x64",
|
||||
"browse": {
|
||||
"path": ["/usr/include", "/usr/local/include", "${workspaceRoot}"],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Win32",
|
||||
"includePath": [
|
||||
"${workspaceRoot}",
|
||||
"${workspaceRoot}/GDCpp",
|
||||
"${workspaceRoot}/GDJS",
|
||||
"${workspaceRoot}/Extensions",
|
||||
"${workspaceRoot}/Core",
|
||||
"${workspaceRoot}/ExtLibs/SFML/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"defines": [
|
||||
"_DEBUG",
|
||||
"UNICODE",
|
||||
"EMSCRIPTEN",
|
||||
"GD_IDE_ONLY",
|
||||
"GD_CORE_API=/* Macro used to export classes on Windows, please ignore */",
|
||||
"GD_API=/* Macro used to export classes on Windows, please ignore */",
|
||||
"GD_EXTENSION_API=/* Macro used to export classes on Windows, please ignore */"
|
||||
],
|
||||
"intelliSenseMode": "msvc-x64",
|
||||
"browse": {
|
||||
"path": ["${workspaceRoot}"],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Mac",
|
||||
"includePath": [
|
||||
"${workspaceRoot}",
|
||||
"${workspaceRoot}/GDJS",
|
||||
"${workspaceRoot}/Extensions",
|
||||
"${workspaceRoot}/Core",
|
||||
"${workspaceRoot}/ExtLibs/SFML/include",
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1",
|
||||
"/usr/local/include",
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include",
|
||||
"/usr/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"defines": [
|
||||
"EMSCRIPTEN",
|
||||
"GD_IDE_ONLY",
|
||||
"GD_CORE_API=/* Macro used to export classes on Windows, please ignore */",
|
||||
"GD_API=/* Macro used to export classes on Windows, please ignore */",
|
||||
"GD_EXTENSION_API=/* Macro used to export classes on Windows, please ignore */"
|
||||
],
|
||||
"intelliSenseMode": "clang-x64",
|
||||
"browse": {
|
||||
"path": [
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1",
|
||||
"/usr/local/include",
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include",
|
||||
"/usr/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
},
|
||||
"macFrameworkPath": [
|
||||
"/System/Library/Frameworks",
|
||||
"/Library/Frameworks"
|
||||
],
|
||||
"compilerPath": "/usr/bin/clang",
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++17"
|
||||
},
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceRoot}",
|
||||
"${workspaceRoot}/GDJS",
|
||||
"${workspaceRoot}/Extensions",
|
||||
"${workspaceRoot}/Core",
|
||||
"${workspaceRoot}/ExtLibs/SFML/include",
|
||||
"/usr/include",
|
||||
"/usr/local/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"defines": [
|
||||
"EMSCRIPTEN",
|
||||
"GD_IDE_ONLY",
|
||||
"GD_CORE_API=/* Macro used to export classes on Windows, please ignore */",
|
||||
"GD_API=/* Macro used to export classes on Windows, please ignore */",
|
||||
"GD_EXTENSION_API=/* Macro used to export classes on Windows, please ignore */"
|
||||
],
|
||||
"intelliSenseMode": "clang-x64",
|
||||
"browse": {
|
||||
"path": [
|
||||
"/usr/include",
|
||||
"/usr/local/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Win32",
|
||||
"includePath": [
|
||||
"${workspaceRoot}",
|
||||
"${workspaceRoot}/GDJS",
|
||||
"${workspaceRoot}/Extensions",
|
||||
"${workspaceRoot}/Core",
|
||||
"${workspaceRoot}/ExtLibs/SFML/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"defines": [
|
||||
"_DEBUG",
|
||||
"UNICODE",
|
||||
"EMSCRIPTEN",
|
||||
"GD_IDE_ONLY",
|
||||
"GD_CORE_API=/* Macro used to export classes on Windows, please ignore */",
|
||||
"GD_API=/* Macro used to export classes on Windows, please ignore */",
|
||||
"GD_EXTENSION_API=/* Macro used to export classes on Windows, please ignore */"
|
||||
],
|
||||
"intelliSenseMode": "msvc-x64",
|
||||
"browse": {
|
||||
"path": [
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -108,7 +108,8 @@
|
||||
"xtree": "cpp",
|
||||
"xutility": "cpp",
|
||||
"xlocbuf": "cpp",
|
||||
"xlocmes": "cpp"
|
||||
"xlocmes": "cpp",
|
||||
"xmemory0": "cpp"
|
||||
},
|
||||
"files.exclude": {
|
||||
"Binaries/*build*": true,
|
||||
|
@@ -1,3 +1,3 @@
|
||||
This is the directory where native or WebAssembly binaries of the C++ code of GDCore, GDCpp and GDJS are produced.
|
||||
This is the directory where native or WebAssembly binaries of the C++ code of GDCore and GDJS are produced.
|
||||
|
||||
See GDevelop.js README for the instructions to compile after a change in the C++ source code.
|
@@ -14,12 +14,10 @@ macro(gd_set_option var default type docstring)
|
||||
endif()
|
||||
set(${var} ${${var}} CACHE ${type} ${docstring} FORCE)
|
||||
endmacro()
|
||||
gd_set_option(BUILD_CORE TRUE BOOL "TRUE to build GDevelop Core library, FALSE to use the already compiled binaries")
|
||||
gd_set_option(BUILD_GDCPP TRUE BOOL "TRUE to build GDevelop C++ Platform")
|
||||
gd_set_option(BUILD_CORE TRUE BOOL "TRUE to build GDevelop Core library")
|
||||
gd_set_option(BUILD_GDJS TRUE BOOL "TRUE to build GDevelop JS Platform")
|
||||
gd_set_option(BUILD_EXTENSIONS TRUE BOOL "TRUE to build the extensions")
|
||||
gd_set_option(BUILD_TESTS FALSE BOOL "TRUE to build the tests")
|
||||
gd_set_option(FULL_VERSION_NUMBER TRUE BOOL "TRUE to build GDevelop with its full version number (lastest tag + commit hash), FALSE to only use the lastest tag (avoid rebulding many source file when developping)")
|
||||
|
||||
# Disable deprecated code
|
||||
set(NO_GUI TRUE CACHE BOOL "" FORCE) #Force disable old GUI related code.
|
||||
@@ -55,9 +53,6 @@ IF ("${CMAKE_BUILD_TYPE}" STREQUAL "")
|
||||
message( "CMAKE_BUILD_TYPE is empty, assuming build type is Release" )
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
ENDIF()
|
||||
IF (EMSCRIPTEN)
|
||||
set(BUILD_GDCPP FALSE CACHE BOOL "" FORCE) #Force disable GDC++ when compiling with emscripten.
|
||||
ENDIF()
|
||||
|
||||
IF("${CMAKE_BUILD_TYPE}" STREQUAL "Release" AND NOT WIN32 AND CMAKE_COMPILER_IS_GNUCXX)
|
||||
SET(CMAKE_SHARED_LINKER_FLAGS "-s") #Force stripping to avoid errors when packaging for linux.
|
||||
@@ -84,7 +79,6 @@ endif()
|
||||
set(GD_base_dir ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
#Add all the CMakeLists:
|
||||
ADD_SUBDIRECTORY(Version)
|
||||
ADD_SUBDIRECTORY(ExtLibs)
|
||||
IF(BUILD_CORE)
|
||||
ADD_SUBDIRECTORY(Core)
|
||||
@@ -92,10 +86,7 @@ ENDIF()
|
||||
IF(BUILD_GDJS)
|
||||
ADD_SUBDIRECTORY(GDJS)
|
||||
ENDIF()
|
||||
IF(BUILD_GDCPP)
|
||||
ADD_SUBDIRECTORY(GDCpp)
|
||||
ENDIF()
|
||||
IF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/GDevelop.js/CMakeLists.txt" AND EMSCRIPTEN)
|
||||
IF(EMSCRIPTEN)
|
||||
ADD_SUBDIRECTORY(GDevelop.js)
|
||||
ENDIF()
|
||||
IF(BUILD_EXTENSIONS)
|
||||
|
@@ -57,7 +57,6 @@ IF(EMSCRIPTEN)
|
||||
ELSE()
|
||||
add_library(GDCore SHARED ${source_files})
|
||||
ENDIF()
|
||||
add_dependencies(GDCore GDVersion)
|
||||
IF(EMSCRIPTEN)
|
||||
set_target_properties(GDCore PROPERTIES SUFFIX ".bc")
|
||||
ELSEIF(WIN32)
|
||||
|
@@ -14,9 +14,8 @@
|
||||
*
|
||||
* \section other Other documentations
|
||||
*
|
||||
* GDevelop is architectured around a `Core` (this library), platforms (`GDJS`, `GDCpp`) and extensions (`Extensions` folder). The editor (`newIDE` folder) is using all of these libraries.
|
||||
* GDevelop is architectured around a `Core` (this library), a game engine (`GDJS`) and extensions (`Extensions` folder). The editor (`newIDE` folder) is using all of these libraries.
|
||||
*
|
||||
* - [Open GDevelop C++ Platform documentation](../GDCpp Documentation/index.html)
|
||||
* - [Open GDevelop JS Platform documentation](../GDJS Documentation/index.html)
|
||||
* - <a href="https://github.com/4ian/GDevelop/blob/master/newIDE/README.md">Getting started with the editor</a>
|
||||
* - <a href="https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md">Getting started with the extensions</a>
|
||||
|
@@ -3,14 +3,17 @@
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include <iostream>
|
||||
#include "EffectsCodeGenerator.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "GDCore/Extensions/Metadata/EffectMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Project/Effect.h"
|
||||
#include "GDCore/Project/Layer.h"
|
||||
#include "GDCore/Project/EffectsContainer.h"
|
||||
#include "GDCore/Project/Layer.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
|
||||
namespace gd {
|
||||
@@ -33,6 +36,24 @@ void ExposeProjectEffects(
|
||||
worker(effect);
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t i; i < layout.GetObjectsCount(); i++) {
|
||||
auto& object = layout.GetObject(i);
|
||||
auto& effects = object.GetEffects();
|
||||
for (std::size_t e = 0; e < effects.GetEffectsCount(); e++) {
|
||||
auto& effect = effects.GetEffect(e);
|
||||
worker(effect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add global object effects
|
||||
for (std::size_t s = 0; s < project.GetObjectsCount(); s++) {
|
||||
auto& effects = project.GetObject(s).GetEffects();
|
||||
for (std::size_t e = 0; e < effects.GetEffectsCount(); e++) {
|
||||
auto& effect = effects.GetEffect(e);
|
||||
worker(effect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -261,8 +261,11 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
|
||||
EventsCodeGenerationContext& context) {
|
||||
gd::String conditionCode;
|
||||
|
||||
gd::InstructionMetadata instrInfos =
|
||||
const gd::InstructionMetadata& instrInfos =
|
||||
MetadataProvider::GetConditionMetadata(platform, condition.GetType());
|
||||
if (MetadataProvider::IsBadInstructionMetadata(instrInfos)) {
|
||||
return "/* Unknown instruction - skipped. */";
|
||||
}
|
||||
|
||||
AddIncludeFiles(instrInfos.codeExtraInformation.GetIncludeFiles());
|
||||
maxConditionsListsSize =
|
||||
@@ -299,15 +302,13 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
|
||||
!GetObjectsAndGroups().GetObjectGroups().Has(objectInParameter) &&
|
||||
!GetGlobalObjectsAndGroups().GetObjectGroups().Has(
|
||||
objectInParameter)) {
|
||||
condition.SetParameter(pNb, gd::Expression(""));
|
||||
condition.SetType("");
|
||||
return "/* Unknown object - skipped. */";
|
||||
} else if (!instrInfos.parameters[pNb].supplementaryInformation.empty() &&
|
||||
gd::GetTypeOfObject(GetGlobalObjectsAndGroups(),
|
||||
GetObjectsAndGroups(),
|
||||
objectInParameter) !=
|
||||
instrInfos.parameters[pNb].supplementaryInformation) {
|
||||
condition.SetParameter(pNb, gd::Expression(""));
|
||||
condition.SetType("");
|
||||
return "/* Mismatched object type - skipped. */";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -425,6 +426,11 @@ gd::String EventsCodeGenerator::GenerateConditionsListCode(
|
||||
outputCode += "{\n";
|
||||
outputCode += conditionCode;
|
||||
outputCode += "}";
|
||||
} else {
|
||||
// Deprecated way to cancel code generation - but still honor it.
|
||||
// Can be removed once condition is passed by const reference to
|
||||
// GenerateConditionCode.
|
||||
outputCode += "/* Skipped condition (empty type) */";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -440,8 +446,11 @@ gd::String EventsCodeGenerator::GenerateActionCode(
|
||||
gd::Instruction& action, EventsCodeGenerationContext& context) {
|
||||
gd::String actionCode;
|
||||
|
||||
gd::InstructionMetadata instrInfos =
|
||||
const gd::InstructionMetadata& instrInfos =
|
||||
MetadataProvider::GetActionMetadata(platform, action.GetType());
|
||||
if (MetadataProvider::IsBadInstructionMetadata(instrInfos)) {
|
||||
return "/* Unknown instruction - skipped. */";
|
||||
}
|
||||
|
||||
AddIncludeFiles(instrInfos.codeExtraInformation.GetIncludeFiles());
|
||||
|
||||
@@ -466,15 +475,13 @@ gd::String EventsCodeGenerator::GenerateActionCode(
|
||||
!GetObjectsAndGroups().GetObjectGroups().Has(objectInParameter) &&
|
||||
!GetGlobalObjectsAndGroups().GetObjectGroups().Has(
|
||||
objectInParameter)) {
|
||||
action.SetParameter(pNb, gd::Expression(""));
|
||||
action.SetType("");
|
||||
return "/* Unknown object - skipped. */";
|
||||
} else if (!instrInfos.parameters[pNb].supplementaryInformation.empty() &&
|
||||
gd::GetTypeOfObject(GetGlobalObjectsAndGroups(),
|
||||
GetObjectsAndGroups(),
|
||||
objectInParameter) !=
|
||||
instrInfos.parameters[pNb].supplementaryInformation) {
|
||||
action.SetParameter(pNb, gd::Expression(""));
|
||||
action.SetType("");
|
||||
return "/* Mismatched object type - skipped. */";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -556,7 +563,14 @@ gd::String EventsCodeGenerator::GenerateActionsListCode(
|
||||
gd::String actionCode = GenerateActionCode(actions[aId], context);
|
||||
|
||||
outputCode += "{";
|
||||
if (!actions[aId].GetType().empty()) outputCode += actionCode;
|
||||
if (actions[aId].GetType().empty()) {
|
||||
// Deprecated way to cancel code generation - but still honor it.
|
||||
// Can be removed once action is passed by const reference to
|
||||
// GenerateActionCode.
|
||||
outputCode += "/* Skipped action (empty type) */";
|
||||
} else {
|
||||
outputCode += actionCode;
|
||||
}
|
||||
outputCode += "}";
|
||||
}
|
||||
|
||||
|
@@ -462,24 +462,21 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
* Other standard parameters type that should be implemented by platforms:
|
||||
* - currentScene: Reference to the current runtime scene.
|
||||
* - objectList : a map containing lists of objects which are specified by the
|
||||
object name in another parameter. (C++: std::map <gd::String,
|
||||
std::vector<RuntimeObject*> *>). Example:
|
||||
object name in another parameter. Example:
|
||||
* \code
|
||||
AddExpression("Count", _("Object count"), _("Count the number of picked
|
||||
objects"), _("Objects"), "res/conditions/nbObjet.png")
|
||||
.AddParameter("objectList", _("Object"))
|
||||
.SetFunctionName("PickedObjectsCount").SetIncludeFile("GDCpp/Extensions/Builtin/ObjectTools.h");
|
||||
.SetFunctionName("getPickedObjectsCount");
|
||||
|
||||
* \endcode
|
||||
* - objectListWithoutPicking : Same as objectList but do not pick object if
|
||||
they are not already picked.
|
||||
* - objectPtr : Return a pointer to object specified by the object name in
|
||||
another parameter ( C++: RuntimeObject* ). Example:
|
||||
* - objectPtr : Return a reference to the object specified by the object name in
|
||||
another parameter. Example:
|
||||
* \code
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectPtr", _("Target object"))
|
||||
//The called function will be called with this signature on the C++ platform:
|
||||
Function(gd::String, RuntimeObject*)
|
||||
* \endcode
|
||||
*/
|
||||
virtual gd::String GenerateParameterCodes(
|
||||
|
@@ -16,7 +16,6 @@
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class EventsList;
|
||||
class MainFrameWrapper;
|
||||
class Project;
|
||||
class Layout;
|
||||
class EventsCodeGenerator;
|
||||
|
@@ -32,7 +32,6 @@ class GD_CORE_API BuiltinExtensionsImplementer {
|
||||
static void ImplementsExternalLayoutsExtension(
|
||||
gd::PlatformExtension& extension);
|
||||
static void ImplementsFileExtension(gd::PlatformExtension& extension);
|
||||
static void ImplementsJoystickExtension(gd::PlatformExtension& extension);
|
||||
static void ImplementsKeyboardExtension(gd::PlatformExtension& extension);
|
||||
static void ImplementsMathematicalToolsExtension(
|
||||
gd::PlatformExtension& extension);
|
||||
|
@@ -344,7 +344,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
obj.AddAction("SetObjectVariableAsBoolean",
|
||||
_("Boolean value of an object variable"),
|
||||
_("Change the boolean value of an object variable."),
|
||||
_("Set the boolean value of the variable _PARAM1_ of object "
|
||||
_("Set the boolean value of variable _PARAM1_ of "
|
||||
"_PARAM0_ to _PARAM2_"),
|
||||
_("Variables"),
|
||||
"res/actions/var24.png",
|
||||
@@ -360,7 +360,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Toggles the boolean value of an object variable.") + "\n" +
|
||||
_("If it was true, it will become false, and if it was false "
|
||||
"it will become true."),
|
||||
_("Toggle the boolean value of the variable _PARAM1_ of object "
|
||||
_("Toggle the boolean value of variable _PARAM1_ of "
|
||||
"_PARAM0_"),
|
||||
_("Variables"),
|
||||
"res/actions/var24.png",
|
||||
@@ -795,8 +795,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
|
||||
obj.AddCondition(
|
||||
"ObjectTimer",
|
||||
_("Value of a timer"),
|
||||
_("Test the elapsed time of a timer."),
|
||||
_("Value of an object timer"),
|
||||
_("Test the elapsed time of an object timer."),
|
||||
_("The timer _PARAM1_ of _PARAM0_ is greater than _PARAM2_ seconds"),
|
||||
_("Timers"),
|
||||
"res/conditions/timer24.png",
|
||||
@@ -806,8 +806,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("expression", _("Time in seconds"));
|
||||
|
||||
obj.AddCondition("ObjectTimerPaused",
|
||||
_("Timer paused"),
|
||||
_("Test if specified timer is paused."),
|
||||
_("Object timer paused"),
|
||||
_("Test if specified object timer is paused."),
|
||||
_("The timer _PARAM1_ of _PARAM0_ is paused"),
|
||||
_("Timers"),
|
||||
"res/conditions/timerPaused24.png",
|
||||
@@ -817,8 +817,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction("ResetObjectTimer",
|
||||
_("Start (or reset) a timer"),
|
||||
_("Reset the specified timer, if the timer doesn't exist "
|
||||
_("Start (or reset) an object timer"),
|
||||
_("Reset the specified object timer, if the timer doesn't exist "
|
||||
"it's created and started."),
|
||||
_("Reset the timer _PARAM1_ of _PARAM0_"),
|
||||
_("Timers"),
|
||||
@@ -828,8 +828,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("string", _("Timer's name"));
|
||||
|
||||
obj.AddAction("PauseObjectTimer",
|
||||
_("Pause a timer"),
|
||||
_("Pause a timer."),
|
||||
_("Pause an object timer"),
|
||||
_("Pause an object timer."),
|
||||
_("Pause timer _PARAM1_ of _PARAM0_"),
|
||||
_("Timers"),
|
||||
"res/actions/pauseTimer24.png",
|
||||
@@ -839,8 +839,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction("UnPauseObjectTimer",
|
||||
_("Unpause a timer"),
|
||||
_("Unpause a timer."),
|
||||
_("Unpause an object timer"),
|
||||
_("Unpause an object timer."),
|
||||
_("Unpause timer _PARAM1_ of _PARAM0_"),
|
||||
_("Timers"),
|
||||
"res/actions/unPauseTimer24.png",
|
||||
@@ -850,8 +850,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction("RemoveObjectTimer",
|
||||
_("Delete a timer"),
|
||||
_("Delete a timer from memory."),
|
||||
_("Delete an object timer"),
|
||||
_("Delete an object timer from memory."),
|
||||
_("Delete timer _PARAM1_ of _PARAM0_ from memory"),
|
||||
_("Timers"),
|
||||
"res/actions/timer24.png",
|
||||
@@ -1021,9 +1021,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("objectvar", _("Variable"));
|
||||
|
||||
obj.AddExpression("ObjectTimerElapsedTime",
|
||||
_("Timer value"),
|
||||
_("Value of a timer"),
|
||||
_("Timers"),
|
||||
_("Object timer value"),
|
||||
_("Value of an object timer"),
|
||||
_("Object timers"),
|
||||
"res/actions/time.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("string", _("Timer's name"));
|
||||
@@ -1072,6 +1072,74 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("expression", _("Target X position"))
|
||||
.AddParameter("expression", _("Target Y position"));
|
||||
|
||||
obj.AddAction("EnableEffect",
|
||||
_("Enable an object effect"),
|
||||
_("Enable an effect on the object"),
|
||||
_("Enable effect _PARAM1_ on _PARAM0_: _PARAM2_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("string", _("Effect Name"))
|
||||
.AddParameter("yesorno", _("Enable?"))
|
||||
.MarkAsSimple();
|
||||
|
||||
obj.AddAction("SetEffectDoubleParameter",
|
||||
_("Effect parameter (number)"),
|
||||
_("Change the value of a parameter of an effect.") + "\n" +
|
||||
_("You can find the parameter names (and change the effect "
|
||||
"names) in the effects window."),
|
||||
_("Set _PARAM2_ to _PARAM3_ for effect _PARAM1_ of _PARAM0_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("string", _("Effect Name"))
|
||||
.AddParameter("string", _("Parameter name"))
|
||||
.AddParameter("expression", _("New value"))
|
||||
.MarkAsSimple();
|
||||
|
||||
obj.AddAction("SetEffectStringParameter",
|
||||
_("Effect parameter (string)"),
|
||||
_("Change the value (string) of a parameter of an effect.") + "\n" +
|
||||
_("You can find the parameter names (and change the effect "
|
||||
"names) in the effects window."),
|
||||
_("Set _PARAM2_ to _PARAM3_ for effect _PARAM1_ of _PARAM0_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("string", _("Effect Name"))
|
||||
.AddParameter("string", _("Parameter name"))
|
||||
.AddParameter("string", _("New value"))
|
||||
.MarkAsSimple();
|
||||
|
||||
obj.AddAction("SetEffectBooleanParameter",
|
||||
_("Effect parameter (enable or disable)"),
|
||||
_("Enable or disable a parameter of an effect.") + "\n" +
|
||||
_("You can find the parameter names (and change the effect "
|
||||
"names) in the effects window."),
|
||||
_("Enable _PARAM2_ for effect _PARAM1_ of _PARAM0_: _PARAM3_"),
|
||||
_("Effects"),
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("string", _("Effect Name"))
|
||||
.AddParameter("string", _("Parameter Name"))
|
||||
.AddParameter("yesorno", _("Enable?"))
|
||||
.MarkAsSimple();
|
||||
|
||||
obj.AddCondition("IsEffectEnabled",
|
||||
_("Effect is enabled"),
|
||||
_("Check if the effect on an object is enabled."),
|
||||
_("Effect _PARAM1_ of _PARAM0_ is enabled"),
|
||||
_("Effects"),
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("string", _("Effect Name"))
|
||||
.MarkAsSimple();
|
||||
|
||||
extension
|
||||
.AddAction("Create",
|
||||
_("Create an object"),
|
||||
|
@@ -1,77 +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 "AllBuiltinExtensions.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
|
||||
using namespace std;
|
||||
namespace gd {
|
||||
|
||||
void GD_CORE_API BuiltinExtensionsImplementer::ImplementsJoystickExtension(
|
||||
gd::PlatformExtension& extension) {
|
||||
extension
|
||||
.SetExtensionInformation(
|
||||
"BuiltinJoystick",
|
||||
_("Joysticks features"),
|
||||
"Built-in extension that enables the use of joysticks.",
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("" /*TODO: Add a documentation page for this */);
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
extension
|
||||
.AddCondition("JoystickButtonDown",
|
||||
_("A button on a joystick is pressed"),
|
||||
_("Test if a button on a joystick is pressed."),
|
||||
_("The button _PARAM2_ of joystick _PARAM1_ is pressed"),
|
||||
_("Joystick"),
|
||||
"res/conditions/joystick24.png",
|
||||
"res/conditions/joystick.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Joystick number (first joystick: 0)"))
|
||||
.AddParameter("expression", _("Button"));
|
||||
|
||||
extension
|
||||
.AddCondition("JoystickAxis",
|
||||
_("Value of an axis of a joystick"),
|
||||
_("Test the value of an axis of a joystick."),
|
||||
_("the value of the axis _PARAM2_ of joystick _PARAM1_"),
|
||||
_("Joystick"),
|
||||
"res/conditions/joystick24.png",
|
||||
"res/conditions/joystick.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Joystick number (first joystick: 0)"))
|
||||
.AddParameter("joyaxis", _("Axis"))
|
||||
.UseStandardRelationalOperatorParameters("number");
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"GetJoystickAxis",
|
||||
_("Get the value of the axis of a joystick"),
|
||||
_("Save the value of the axis of the joystick (from -100 to 100)."),
|
||||
_("Save in _PARAM3_ the value of axis _PARAM2_ of joystick _PARAM1_"),
|
||||
_("Joystick"),
|
||||
"res/actions/joystick24.png",
|
||||
"res/actions/joystick.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Joystick number (first joystick: 0)"))
|
||||
.AddParameter("joyaxis", _("Axis"))
|
||||
.AddParameter("scenevar", _("Save the result to the scene variable"))
|
||||
.SetManipulatedType("number");
|
||||
|
||||
extension
|
||||
.AddExpression("GetJoystickAxis",
|
||||
_("Joystick axis"),
|
||||
_("Value of an axis of a joystick"),
|
||||
_("Joystick"),
|
||||
"res/conditions/joystick.png")
|
||||
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Joystick number (first joystick: 0)"))
|
||||
.AddParameter("joyaxis", _("Axis"));
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace gd
|
@@ -7,7 +7,6 @@
|
||||
#include <SFML/Graphics/Sprite.hpp>
|
||||
#include <iostream>
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/Polygon2d.h"
|
||||
#include "GDCore/Project/ImageManager.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -16,11 +15,7 @@ namespace gd {
|
||||
Point Sprite::badPoint("");
|
||||
|
||||
Sprite::Sprite()
|
||||
:
|
||||
#if !defined(EMSCRIPTEN)
|
||||
hasItsOwnImage(false),
|
||||
#endif
|
||||
automaticCollisionMask(true),
|
||||
: automaticCollisionMask(true),
|
||||
origine("origine"),
|
||||
centre("centre"),
|
||||
automaticCentre(true) {
|
||||
@@ -73,36 +68,10 @@ Point& Sprite::GetPoint(const gd::String& name) {
|
||||
|
||||
bool Sprite::SetDefaultCenterPoint(bool enabled) {
|
||||
automaticCentre = enabled;
|
||||
|
||||
#if !defined(EMSCRIPTEN)
|
||||
if (automaticCentre)
|
||||
centre.SetXY(sfmlSprite.getLocalBounds().width / 2,
|
||||
sfmlSprite.getLocalBounds().height / 2);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<Polygon2d> Sprite::GetCollisionMask() const {
|
||||
// TODO(perf): Cache to avoid re-creating a mask at every call
|
||||
#if !defined(EMSCRIPTEN)
|
||||
if (automaticCollisionMask) {
|
||||
std::vector<Polygon2d> mask;
|
||||
|
||||
Polygon2d rectangle;
|
||||
rectangle.vertices.push_back(sf::Vector2f(0, 0));
|
||||
rectangle.vertices.push_back(
|
||||
sf::Vector2f(sfmlSprite.getLocalBounds().width, 0));
|
||||
rectangle.vertices.push_back(sf::Vector2f(
|
||||
sfmlSprite.getLocalBounds().width, sfmlSprite.getLocalBounds().height));
|
||||
rectangle.vertices.push_back(
|
||||
sf::Vector2f(0, sfmlSprite.getLocalBounds().height));
|
||||
|
||||
mask.push_back(rectangle);
|
||||
return mask;
|
||||
}
|
||||
#endif
|
||||
|
||||
return customCollisionMask;
|
||||
}
|
||||
|
||||
@@ -111,25 +80,4 @@ void Sprite::SetCustomCollisionMask(
|
||||
customCollisionMask = collisionMask;
|
||||
}
|
||||
|
||||
#if !defined(EMSCRIPTEN)
|
||||
void Sprite::LoadImage(std::shared_ptr<SFMLTextureWrapper> image_) {
|
||||
sfmlImage = image_;
|
||||
sfmlSprite.setTexture(sfmlImage->texture, true);
|
||||
hasItsOwnImage = false;
|
||||
|
||||
if (automaticCentre)
|
||||
centre.SetXY(sfmlSprite.getLocalBounds().width / 2,
|
||||
sfmlSprite.getLocalBounds().height / 2);
|
||||
}
|
||||
|
||||
void Sprite::MakeSpriteOwnsItsImage() {
|
||||
if (!hasItsOwnImage || sfmlImage == std::shared_ptr<SFMLTextureWrapper>()) {
|
||||
sfmlImage = std::make_shared<SFMLTextureWrapper>(
|
||||
sfmlImage->texture); // Copy the texture.
|
||||
sfmlSprite.setTexture(sfmlImage->texture);
|
||||
hasItsOwnImage = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -11,7 +11,6 @@
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/Point.h"
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/Polygon2d.h"
|
||||
#include "GDCore/String.h"
|
||||
class SFMLTextureWrapper;
|
||||
#undef LoadImage // prevent windows.h to be polluting everything
|
||||
|
||||
namespace gd {
|
||||
@@ -19,9 +18,6 @@ namespace gd {
|
||||
/**
|
||||
* \brief Represents a sprite to be displayed on the screen.
|
||||
*
|
||||
* A sprite contains a SFML sprite to be displayed, some points,
|
||||
* and can also have its own texture (rather than a texture from ImageManager).
|
||||
*
|
||||
* \see Direction
|
||||
* \see SpriteObject
|
||||
* \ingroup SpriteObjectExtension
|
||||
@@ -163,53 +159,7 @@ class GD_CORE_API Sprite {
|
||||
*/
|
||||
bool SetDefaultCenterPoint(bool enabled);
|
||||
|
||||
#if !defined(EMSCRIPTEN)
|
||||
/** \name Sprite runtime management
|
||||
* Functions used by the C++ game engine.
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* \brief Get the SFML sprite associated with the sprite
|
||||
*/
|
||||
inline const sf::Sprite& GetSFMLSprite() const { return sfmlSprite; }
|
||||
|
||||
/**
|
||||
* \brief Get the SFML sprite associated with the sprite
|
||||
*/
|
||||
inline sf::Sprite& GetSFMLSprite() { return sfmlSprite; }
|
||||
|
||||
/**
|
||||
* \brief Set the SFML texture of the sprite
|
||||
*/
|
||||
void LoadImage(std::shared_ptr<SFMLTextureWrapper> image);
|
||||
|
||||
/**
|
||||
* \brief Get SFML texture used by the sprite
|
||||
*/
|
||||
std::shared_ptr<SFMLTextureWrapper> GetSFMLTexture() { return sfmlImage; };
|
||||
|
||||
/**
|
||||
* \brief Get SFML texture used by the sprite
|
||||
*/
|
||||
const std::shared_ptr<SFMLTextureWrapper> GetSFMLTexture() const {
|
||||
return sfmlImage;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Make the sprite, if it uses a texture from ImageManager,
|
||||
* copy this texture and take ownership of it.
|
||||
*/
|
||||
void MakeSpriteOwnsItsImage();
|
||||
///@}
|
||||
#endif
|
||||
|
||||
private:
|
||||
#if !defined(EMSCRIPTEN)
|
||||
sf::Sprite sfmlSprite; ///< Displayed SFML sprite
|
||||
std::shared_ptr<SFMLTextureWrapper>
|
||||
sfmlImage; ///< Pointer to the image displayed by the sprite.
|
||||
bool hasItsOwnImage; ///< True if sfmlImage is only owned by this Sprite.
|
||||
#endif
|
||||
gd::String image; ///< Name of the image to be loaded in Image Manager.
|
||||
|
||||
bool automaticCollisionMask; ///< True to use the custom collision mask.
|
||||
|
@@ -334,39 +334,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction("CopyImageOnImageOfSprite",
|
||||
_("Copy an image on the current one of an object"),
|
||||
_("Copy an image on the current image of an object.\nNote that "
|
||||
"the source image must be preferably kept loaded in memory."),
|
||||
_("Copy image _PARAM2_ on the current of _PARAM0_ at "
|
||||
"_PARAM3_;_PARAM4_"),
|
||||
_("Effects"),
|
||||
"res/copy24.png",
|
||||
"res/copyicon.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("string", _("Name of the source image"))
|
||||
.AddParameter("expression", _("X position"))
|
||||
.AddParameter("expression", _("Y position"))
|
||||
.AddParameter(
|
||||
"yesorno",
|
||||
_("Should the copy take in account the source transparency\?"));
|
||||
|
||||
obj.AddAction(
|
||||
"CreateMaskFromColorOnActualImage", // Actual is indeed a mistake :
|
||||
// Current should have been
|
||||
// chosen.
|
||||
_("Make a color of the image of an object transparent"),
|
||||
_("Make a color of the image of an object transparent."),
|
||||
_("Make color _PARAM1_ of the current image of _PARAM0_ transparent"),
|
||||
_("Effects"),
|
||||
"res/actions/opacity24.png",
|
||||
"res/actions/opacity.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("color", _("Color to make transparent"));
|
||||
|
||||
obj.AddAction("ChangeColor",
|
||||
_("Tint color"),
|
||||
_("Change the tint of an object. The default color is white."),
|
||||
|
@@ -10,7 +10,6 @@
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/Direction.h"
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/Sprite.h"
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h"
|
||||
#include "GDCore/Project/ImageManager.h"
|
||||
#include "GDCore/Project/InitialInstance.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
|
@@ -16,7 +16,6 @@ class Object;
|
||||
class Layout;
|
||||
class Sprite;
|
||||
class Animation;
|
||||
class MainFrameWrapper;
|
||||
class SerializerElement;
|
||||
class PropertyDescriptor;
|
||||
} // namespace gd
|
||||
|
@@ -393,4 +393,14 @@ const gd::String& BehaviorMetadata::GetName() const {
|
||||
return instance->GetTypeName();
|
||||
}
|
||||
|
||||
gd::Behavior& BehaviorMetadata::Get() const {
|
||||
if (!instance)
|
||||
gd::LogFatalError(
|
||||
"Trying to get a behavior from a BehaviorMetadata that has no "
|
||||
"behavior. This will crash - please double check that the "
|
||||
"BehaviorMetadata is valid.");
|
||||
|
||||
return *instance;
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -240,7 +240,7 @@ class GD_CORE_API BehaviorMetadata {
|
||||
/**
|
||||
* \brief Return the associated gd::Behavior, handling behavior contents.
|
||||
*/
|
||||
gd::Behavior& Get() const { return *instance; }
|
||||
gd::Behavior& Get() const;
|
||||
|
||||
/**
|
||||
* \brief Return the associated gd::BehaviorsSharedData, handling behavior
|
||||
|
@@ -7,7 +7,8 @@
|
||||
|
||||
namespace gd {
|
||||
|
||||
EffectMetadata::EffectMetadata(const gd::String& type_) : type(type_) {}
|
||||
EffectMetadata::EffectMetadata(const gd::String& type_)
|
||||
: type(type_), isMarkedAsNotWorkingForObjects(false) {}
|
||||
|
||||
EffectMetadata& EffectMetadata::SetIncludeFile(const gd::String& includeFile) {
|
||||
includeFiles.clear();
|
||||
@@ -22,4 +23,9 @@ EffectMetadata& EffectMetadata::AddIncludeFile(const gd::String& includeFile) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
EffectMetadata& EffectMetadata::MarkAsNotWorkingForObjects() {
|
||||
isMarkedAsNotWorkingForObjects = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
@@ -49,7 +50,8 @@ class GD_CORE_API EffectMetadata {
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the help path of the effect, relative to the GDevelop documentation root.
|
||||
* Set the help path of the effect, relative to the GDevelop documentation
|
||||
* root.
|
||||
*/
|
||||
EffectMetadata& SetHelpPath(const gd::String& path) {
|
||||
helpPath = path;
|
||||
@@ -66,6 +68,11 @@ class GD_CORE_API EffectMetadata {
|
||||
*/
|
||||
EffectMetadata& AddIncludeFile(const gd::String& includeFile);
|
||||
|
||||
/**
|
||||
* \brief Mark the effect as not working as an object effect.
|
||||
*/
|
||||
EffectMetadata& MarkAsNotWorkingForObjects();
|
||||
|
||||
/**
|
||||
* \brief Return a reference to the properties of this effect.
|
||||
*/
|
||||
@@ -81,12 +88,14 @@ class GD_CORE_API EffectMetadata {
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the help path of the effect, relative to the GDevelop documentation root.
|
||||
* \brief Get the help path of the effect, relative to the GDevelop
|
||||
* documentation root.
|
||||
*/
|
||||
const gd::String& GetHelpPath() const { return helpPath; }
|
||||
|
||||
/**
|
||||
* \brief Get the type of the effect (its internal name, like "BlackAndWhite").
|
||||
* \brief Get the type of the effect (its internal name, like
|
||||
* "BlackAndWhite").
|
||||
*/
|
||||
const gd::String& GetType() const { return type; }
|
||||
|
||||
@@ -107,6 +116,11 @@ class GD_CORE_API EffectMetadata {
|
||||
return includeFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check if the effect is marked as not working as an object effect.
|
||||
*/
|
||||
bool IsMarkedAsNotWorkingForObjects() const { return isMarkedAsNotWorkingForObjects; };
|
||||
|
||||
private:
|
||||
gd::String extensionNamespace;
|
||||
gd::String type;
|
||||
@@ -114,6 +128,7 @@ class GD_CORE_API EffectMetadata {
|
||||
gd::String fullname;
|
||||
gd::String description;
|
||||
std::vector<gd::String> includeFiles;
|
||||
bool isMarkedAsNotWorkingForObjects;
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties;
|
||||
};
|
||||
|
||||
|
@@ -234,14 +234,14 @@ class GD_CORE_API InstructionMetadata {
|
||||
/**
|
||||
* \brief Check if the instruction is an object instruction.
|
||||
*/
|
||||
bool IsObjectInstruction() {
|
||||
bool IsObjectInstruction() const {
|
||||
return isObjectInstruction;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check if the instruction is a behavior instruction.
|
||||
*/
|
||||
bool IsBehaviorInstruction() {
|
||||
bool IsBehaviorInstruction() const {
|
||||
return isBehaviorInstruction;
|
||||
}
|
||||
|
||||
|
@@ -245,6 +245,10 @@ class GD_CORE_API MetadataProvider {
|
||||
return &metadata == &badExpressionMetadata;
|
||||
}
|
||||
|
||||
static bool IsBadInstructionMetadata(const gd::InstructionMetadata& metadata) {
|
||||
return &metadata == &badInstructionMetadata;
|
||||
}
|
||||
|
||||
static bool IsBadBehaviorMetadata(const gd::BehaviorMetadata& metadata) {
|
||||
return &metadata == &badBehaviorMetadata;
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "ParameterMetadataTools.h"
|
||||
|
||||
#include "GDCore/Events/Expression.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/ObjectsContainer.h"
|
||||
@@ -60,6 +61,24 @@ void ParameterMetadataTools::IterateOverParameters(
|
||||
std::function<void(const gd::ParameterMetadata& parameterMetadata,
|
||||
const gd::String& parameterValue,
|
||||
const gd::String& lastObjectName)> fn) {
|
||||
IterateOverParametersWithIndex(
|
||||
parameters,
|
||||
parametersMetadata,
|
||||
[&fn](const gd::ParameterMetadata& parameterMetadata,
|
||||
const gd::String& parameterValue,
|
||||
size_t parameterIndex,
|
||||
const gd::String& lastObjectName) {
|
||||
fn(parameterMetadata, parameterValue, lastObjectName);
|
||||
});
|
||||
}
|
||||
|
||||
void ParameterMetadataTools::IterateOverParametersWithIndex(
|
||||
const std::vector<gd::Expression>& parameters,
|
||||
const std::vector<gd::ParameterMetadata>& parametersMetadata,
|
||||
std::function<void(const gd::ParameterMetadata& parameterMetadata,
|
||||
const gd::String& parameterValue,
|
||||
size_t parameterIndex,
|
||||
const gd::String& lastObjectName)> fn) {
|
||||
gd::String lastObjectName = "";
|
||||
for (std::size_t pNb = 0; pNb < parametersMetadata.size(); ++pNb) {
|
||||
const gd::ParameterMetadata& parameterMetadata = parametersMetadata[pNb];
|
||||
@@ -70,7 +89,7 @@ void ParameterMetadataTools::IterateOverParameters(
|
||||
? parameterMetadata.GetDefaultValue()
|
||||
: parameterValue;
|
||||
|
||||
fn(parameterMetadata, parameterValueOrDefault, lastObjectName);
|
||||
fn(parameterMetadata, parameterValueOrDefault, pNb, lastObjectName);
|
||||
|
||||
// Memorize the last object name. By convention, parameters that require
|
||||
// an object (mainly, "objectvar" and "behavior") should be placed after
|
||||
|
@@ -35,6 +35,19 @@ class GD_CORE_API ParameterMetadataTools {
|
||||
const gd::String& parameterValue,
|
||||
const gd::String& lastObjectName)> fn);
|
||||
|
||||
/**
|
||||
* Iterate over a list of parameters and their values.
|
||||
* Callback function is called with the parameter metadata, its value
|
||||
* and if applicable the name of the object it's linked to.
|
||||
*/
|
||||
static void IterateOverParametersWithIndex(
|
||||
const std::vector<gd::Expression>& parameters,
|
||||
const std::vector<gd::ParameterMetadata>& parametersMetadata,
|
||||
std::function<void(const gd::ParameterMetadata& parameterMetadata,
|
||||
const gd::String& parameterValue,
|
||||
size_t parameterIndex,
|
||||
const gd::String& lastObjectName)> fn);
|
||||
|
||||
/**
|
||||
* Given a parameter, return, if applicable, the index of the object parameter
|
||||
* it's linked to.
|
||||
|
164
Core/GDCore/IDE/Events/EventsBehaviorRenamer.cpp
Normal file
164
Core/GDCore/IDE/Events/EventsBehaviorRenamer.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/IDE/Events/EventsBehaviorRenamer.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
|
||||
#include "GDCore/IDE/Events/ExpressionValidator.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Go through the nodes and rename any reference to an object behavior.
|
||||
*
|
||||
* \see gd::ExpressionParser2
|
||||
*/
|
||||
class GD_CORE_API ExpressionBehaviorRenamer
|
||||
: public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
ExpressionBehaviorRenamer(const gd::ObjectsContainer& globalObjectsContainer_,
|
||||
const gd::ObjectsContainer& objectsContainer_,
|
||||
const gd::String& objectName_,
|
||||
const gd::String& oldBehaviorName_,
|
||||
const gd::String& newBehaviorName_)
|
||||
: hasDoneRenaming(false),
|
||||
globalObjectsContainer(globalObjectsContainer_),
|
||||
objectsContainer(objectsContainer_),
|
||||
objectName(objectName_),
|
||||
oldBehaviorName(oldBehaviorName_),
|
||||
newBehaviorName(newBehaviorName_){};
|
||||
virtual ~ExpressionBehaviorRenamer(){};
|
||||
|
||||
bool HasDoneRenaming() const { return hasDoneRenaming; }
|
||||
|
||||
protected:
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
|
||||
node.expression->Visit(*this);
|
||||
}
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {
|
||||
node.leftHandSide->Visit(*this);
|
||||
node.rightHandSide->Visit(*this);
|
||||
}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
|
||||
node.factor->Visit(*this);
|
||||
}
|
||||
void OnVisitNumberNode(NumberNode& node) override {}
|
||||
void OnVisitTextNode(TextNode& node) override {}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override {
|
||||
node.expression->Visit(*this);
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
|
||||
if (!node.behaviorFunctionName.empty()) {
|
||||
// Behavior function name
|
||||
if (node.objectName == objectName && node.objectFunctionOrBehaviorName == oldBehaviorName) {
|
||||
node.objectFunctionOrBehaviorName = newBehaviorName;
|
||||
hasDoneRenaming = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
|
||||
if (!node.behaviorName.empty()) {
|
||||
// Behavior function call
|
||||
if (node.objectName == objectName && node.behaviorName == oldBehaviorName) {
|
||||
node.behaviorName = newBehaviorName;
|
||||
hasDoneRenaming = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& parameter : node.parameters) {
|
||||
parameter->Visit(*this);
|
||||
}
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {}
|
||||
|
||||
private:
|
||||
bool hasDoneRenaming;
|
||||
const gd::ObjectsContainer& globalObjectsContainer;
|
||||
const gd::ObjectsContainer& objectsContainer;
|
||||
const gd::String& objectName; // The object name for which the behavior
|
||||
// must be replaced.
|
||||
const gd::String& oldBehaviorName;
|
||||
const gd::String& newBehaviorName;
|
||||
};
|
||||
|
||||
bool EventsBehaviorRenamer::DoVisitInstruction(gd::Instruction& instruction,
|
||||
bool isCondition) {
|
||||
const auto& metadata = isCondition
|
||||
? gd::MetadataProvider::GetConditionMetadata(
|
||||
platform, instruction.GetType())
|
||||
: gd::MetadataProvider::GetActionMetadata(
|
||||
platform, instruction.GetType());
|
||||
|
||||
gd::ParameterMetadataTools::IterateOverParametersWithIndex(
|
||||
instruction.GetParameters(),
|
||||
metadata.GetParameters(),
|
||||
[&](const gd::ParameterMetadata& parameterMetadata,
|
||||
const gd::String& parameterValue,
|
||||
size_t parameterIndex,
|
||||
const gd::String& lastObjectName) {
|
||||
const gd::String& type = parameterMetadata.type;
|
||||
|
||||
if (gd::ParameterMetadata::IsBehavior(type)) {
|
||||
if (lastObjectName == objectName) {
|
||||
if (parameterValue == oldBehaviorName) {
|
||||
instruction.SetParameter(parameterIndex,
|
||||
gd::Expression(newBehaviorName));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gd::ExpressionParser2 parser(
|
||||
platform, GetGlobalObjectsContainer(), GetObjectsContainer());
|
||||
auto node =
|
||||
gd::ParameterMetadata::IsExpression("number", type)
|
||||
? parser.ParseExpression("number", parameterValue)
|
||||
: (gd::ParameterMetadata::IsExpression("string", type)
|
||||
? parser.ParseExpression("string", parameterValue)
|
||||
: std::unique_ptr<gd::ExpressionNode>());
|
||||
if (node) {
|
||||
ExpressionBehaviorRenamer renamer(GetGlobalObjectsContainer(),
|
||||
GetObjectsContainer(),
|
||||
objectName,
|
||||
oldBehaviorName,
|
||||
newBehaviorName);
|
||||
node->Visit(renamer);
|
||||
|
||||
if (renamer.HasDoneRenaming()) {
|
||||
instruction.SetParameter(
|
||||
parameterIndex,
|
||||
ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
EventsBehaviorRenamer::~EventsBehaviorRenamer() {}
|
||||
|
||||
} // namespace gd
|
52
Core/GDCore/IDE/Events/EventsBehaviorRenamer.h
Normal file
52
Core/GDCore/IDE/Events/EventsBehaviorRenamer.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef EventsBehaviorRenamer_H
|
||||
#define EventsBehaviorRenamer_H
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class BaseEvent;
|
||||
class Platform;
|
||||
class EventsList;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Replace in expressions and in parameters of actions or conditions, references
|
||||
* to the name of a behavior of an object by another name.
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API EventsBehaviorRenamer : public ArbitraryEventsWorkerWithContext {
|
||||
public:
|
||||
EventsBehaviorRenamer(const gd::Platform &platform_,
|
||||
const gd::String& objectName_,
|
||||
const gd::String& oldBehaviorName_,
|
||||
const gd::String& newBehaviorName_) :
|
||||
platform(platform_),
|
||||
objectName(objectName_),
|
||||
oldBehaviorName(oldBehaviorName_),
|
||||
newBehaviorName(newBehaviorName_)
|
||||
{};
|
||||
virtual ~EventsBehaviorRenamer();
|
||||
|
||||
private:
|
||||
bool DoVisitInstruction(gd::Instruction &instruction,
|
||||
bool isCondition) override;
|
||||
|
||||
const gd::Platform &platform;
|
||||
gd::String objectName;
|
||||
gd::String oldBehaviorName;
|
||||
gd::String newBehaviorName;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // EventsBehaviorRenamer_H
|
@@ -5,17 +5,19 @@
|
||||
*/
|
||||
|
||||
#include "GDCore/IDE/Events/EventsRefactorer.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
|
||||
#include "GDCore/IDE/Events/ExpressionValidator.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/IDE/Events/ExpressionValidator.h"
|
||||
#include "GDCore/Project/ObjectsContainer.h"
|
||||
|
||||
using namespace std;
|
||||
@@ -31,10 +33,14 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
ExpressionObjectRenamer(const gd::String& objectName_,
|
||||
const gd::String& objectNewName_)
|
||||
: hasDoneRenaming(false), objectName(objectName_), objectNewName(objectNewName_){};
|
||||
: hasDoneRenaming(false),
|
||||
objectName(objectName_),
|
||||
objectNewName(objectNewName_){};
|
||||
virtual ~ExpressionObjectRenamer(){};
|
||||
|
||||
static bool Rename(gd::ExpressionNode & node, const gd::String& objectName, const gd::String& objectNewName) {
|
||||
static bool Rename(gd::ExpressionNode& node,
|
||||
const gd::String& objectName,
|
||||
const gd::String& objectNewName) {
|
||||
if (ExpressionValidator::HasNoErrors(node)) {
|
||||
ExpressionObjectRenamer renamer(objectName, objectNewName);
|
||||
node.Visit(renamer);
|
||||
@@ -72,7 +78,8 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
if (gd::ParameterMetadata::IsObject(node.type) && node.identifierName == objectName) {
|
||||
if (gd::ParameterMetadata::IsObject(node.type) &&
|
||||
node.identifierName == objectName) {
|
||||
hasDoneRenaming = true;
|
||||
node.identifierName = objectNewName;
|
||||
}
|
||||
@@ -109,10 +116,11 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
|
||||
class GD_CORE_API ExpressionObjectFinder : public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
ExpressionObjectFinder(const gd::String& objectName_)
|
||||
: hasObject(false), objectName(objectName_) {};
|
||||
: hasObject(false), objectName(objectName_){};
|
||||
virtual ~ExpressionObjectFinder(){};
|
||||
|
||||
static bool CheckIfHasObject(gd::ExpressionNode & node, const gd::String & objectName) {
|
||||
static bool CheckIfHasObject(gd::ExpressionNode& node,
|
||||
const gd::String& objectName) {
|
||||
if (ExpressionValidator::HasNoErrors(node)) {
|
||||
ExpressionObjectFinder finder(objectName);
|
||||
node.Visit(finder);
|
||||
@@ -150,7 +158,8 @@ class GD_CORE_API ExpressionObjectFinder : public ExpressionParser2NodeWorker {
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
if (gd::ParameterMetadata::IsObject(node.type) && node.identifierName == objectName) {
|
||||
if (gd::ParameterMetadata::IsObject(node.type) &&
|
||||
node.identifierName == objectName) {
|
||||
hasObject = true;
|
||||
}
|
||||
}
|
||||
@@ -183,7 +192,7 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
|
||||
bool somethingModified = false;
|
||||
|
||||
for (std::size_t aId = 0; aId < actions.size(); ++aId) {
|
||||
gd::InstructionMetadata instrInfos =
|
||||
const gd::InstructionMetadata& instrInfos =
|
||||
MetadataProvider::GetActionMetadata(platform, actions[aId].GetType());
|
||||
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
|
||||
// Replace object's name in parameters
|
||||
@@ -194,20 +203,24 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"number", instrInfos.parameters[pNb].type)) {
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression("number", actions[aId].GetParameter(pNb).GetPlainString());
|
||||
auto node = parser.ParseExpression(
|
||||
"number", actions[aId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
|
||||
actions[aId].SetParameter(pNb, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
actions[aId].SetParameter(
|
||||
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
}
|
||||
// Replace object's name in text expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"string", instrInfos.parameters[pNb].type)) {
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression("string", actions[aId].GetParameter(pNb).GetPlainString());
|
||||
auto node = parser.ParseExpression(
|
||||
"string", actions[aId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
|
||||
actions[aId].SetParameter(pNb, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
actions[aId].SetParameter(
|
||||
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -236,8 +249,9 @@ bool EventsRefactorer::RenameObjectInConditions(
|
||||
bool somethingModified = false;
|
||||
|
||||
for (std::size_t cId = 0; cId < conditions.size(); ++cId) {
|
||||
gd::InstructionMetadata instrInfos = MetadataProvider::GetConditionMetadata(
|
||||
platform, conditions[cId].GetType());
|
||||
const gd::InstructionMetadata& instrInfos =
|
||||
MetadataProvider::GetConditionMetadata(platform,
|
||||
conditions[cId].GetType());
|
||||
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
|
||||
// Replace object's name in parameters
|
||||
if (gd::ParameterMetadata::IsObject(instrInfos.parameters[pNb].type) &&
|
||||
@@ -247,20 +261,24 @@ bool EventsRefactorer::RenameObjectInConditions(
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"number", instrInfos.parameters[pNb].type)) {
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression("number", conditions[cId].GetParameter(pNb).GetPlainString());
|
||||
auto node = parser.ParseExpression(
|
||||
"number", conditions[cId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
|
||||
conditions[cId].SetParameter(pNb, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
conditions[cId].SetParameter(
|
||||
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
}
|
||||
// Replace object's name in text expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"string", instrInfos.parameters[pNb].type)) {
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression("string", conditions[cId].GetParameter(pNb).GetPlainString());
|
||||
auto node = parser.ParseExpression(
|
||||
"string", conditions[cId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
|
||||
conditions[cId].SetParameter(pNb, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
conditions[cId].SetParameter(
|
||||
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -293,8 +311,8 @@ bool EventsRefactorer::RenameObjectInEventParameters(
|
||||
expression.GetPlainString() == oldName)
|
||||
expression = gd::Expression(newName);
|
||||
// Replace object's name in expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"number", parameterMetadata.GetType())) {
|
||||
else if (ParameterMetadata::IsExpression("number",
|
||||
parameterMetadata.GetType())) {
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression("number", expression.GetPlainString());
|
||||
|
||||
@@ -303,8 +321,8 @@ bool EventsRefactorer::RenameObjectInEventParameters(
|
||||
}
|
||||
}
|
||||
// Replace object's name in text expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"string", parameterMetadata.GetType())) {
|
||||
else if (ParameterMetadata::IsExpression("string",
|
||||
parameterMetadata.GetType())) {
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression("string", expression.GetPlainString());
|
||||
|
||||
@@ -337,13 +355,19 @@ void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
|
||||
platform, project, layout, *actionsVectors[j], oldName, newName);
|
||||
}
|
||||
|
||||
vector<pair<gd::Expression*, gd::ParameterMetadata>> expressionsWithMetadata =
|
||||
events[i].GetAllExpressionsWithMetadata();
|
||||
vector<pair<gd::Expression*, gd::ParameterMetadata>>
|
||||
expressionsWithMetadata = events[i].GetAllExpressionsWithMetadata();
|
||||
for (std::size_t j = 0; j < expressionsWithMetadata.size(); ++j) {
|
||||
gd::Expression* expression = expressionsWithMetadata[j].first;
|
||||
gd::ParameterMetadata parameterMetadata = expressionsWithMetadata[j].second;
|
||||
bool somethingModified = RenameObjectInEventParameters(
|
||||
platform, project, layout, *expression, parameterMetadata, oldName, newName);
|
||||
gd::ParameterMetadata parameterMetadata =
|
||||
expressionsWithMetadata[j].second;
|
||||
bool somethingModified = RenameObjectInEventParameters(platform,
|
||||
project,
|
||||
layout,
|
||||
*expression,
|
||||
parameterMetadata,
|
||||
oldName,
|
||||
newName);
|
||||
}
|
||||
|
||||
if (events[i].CanHaveSubEvents())
|
||||
@@ -366,7 +390,7 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
|
||||
for (std::size_t aId = 0; aId < actions.size(); ++aId) {
|
||||
bool deleteMe = false;
|
||||
|
||||
gd::InstructionMetadata instrInfos =
|
||||
const gd::InstructionMetadata& instrInfos =
|
||||
MetadataProvider::GetActionMetadata(platform, actions[aId].GetType());
|
||||
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
|
||||
// Find object's name in parameters
|
||||
@@ -379,7 +403,8 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"number", instrInfos.parameters[pNb].type)) {
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression("number", actions[aId].GetParameter(pNb).GetPlainString());
|
||||
auto node = parser.ParseExpression(
|
||||
"number", actions[aId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
if (ExpressionObjectFinder::CheckIfHasObject(*node, name)) {
|
||||
deleteMe = true;
|
||||
@@ -390,7 +415,8 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"string", instrInfos.parameters[pNb].type)) {
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression("string", actions[aId].GetParameter(pNb).GetPlainString());
|
||||
auto node = parser.ParseExpression(
|
||||
"string", actions[aId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
if (ExpressionObjectFinder::CheckIfHasObject(*node, name)) {
|
||||
deleteMe = true;
|
||||
@@ -427,8 +453,9 @@ bool EventsRefactorer::RemoveObjectInConditions(
|
||||
for (std::size_t cId = 0; cId < conditions.size(); ++cId) {
|
||||
bool deleteMe = false;
|
||||
|
||||
gd::InstructionMetadata instrInfos = MetadataProvider::GetConditionMetadata(
|
||||
platform, conditions[cId].GetType());
|
||||
const gd::InstructionMetadata& instrInfos =
|
||||
MetadataProvider::GetConditionMetadata(platform,
|
||||
conditions[cId].GetType());
|
||||
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
|
||||
// Find object's name in parameters
|
||||
if (gd::ParameterMetadata::IsObject(instrInfos.parameters[pNb].type) &&
|
||||
@@ -440,7 +467,8 @@ bool EventsRefactorer::RemoveObjectInConditions(
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"number", instrInfos.parameters[pNb].type)) {
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression("number", conditions[cId].GetParameter(pNb).GetPlainString());
|
||||
auto node = parser.ParseExpression(
|
||||
"number", conditions[cId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
if (ExpressionObjectFinder::CheckIfHasObject(*node, name)) {
|
||||
deleteMe = true;
|
||||
@@ -451,7 +479,8 @@ bool EventsRefactorer::RemoveObjectInConditions(
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"string", instrInfos.parameters[pNb].type)) {
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression("string", conditions[cId].GetParameter(pNb).GetPlainString());
|
||||
auto node = parser.ParseExpression(
|
||||
"string", conditions[cId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
if (ExpressionObjectFinder::CheckIfHasObject(*node, name)) {
|
||||
deleteMe = true;
|
||||
@@ -781,10 +810,10 @@ bool EventsRefactorer::SearchStringInConditions(
|
||||
}
|
||||
|
||||
bool EventsRefactorer::SearchStringInEvent(gd::ObjectsContainer& project,
|
||||
gd::ObjectsContainer& layout,
|
||||
gd::BaseEvent& event,
|
||||
gd::String search,
|
||||
bool matchCase) {
|
||||
gd::ObjectsContainer& layout,
|
||||
gd::BaseEvent& event,
|
||||
gd::String search,
|
||||
bool matchCase) {
|
||||
for (gd::String str : event.GetAllSearchableStrings()) {
|
||||
if (matchCase) {
|
||||
if (str.find(search) != gd::String::npos) return true;
|
||||
|
@@ -151,7 +151,7 @@ std::set<gd::String> EventsVariablesFinder::FindArgumentsInInstructions(
|
||||
|
||||
for (std::size_t aId = 0; aId < instructions.size(); ++aId) {
|
||||
gd::String lastObjectParameter = "";
|
||||
gd::InstructionMetadata instrInfos =
|
||||
const gd::InstructionMetadata& instrInfos =
|
||||
instructionsAreConditions ? MetadataProvider::GetConditionMetadata(
|
||||
platform, instructions[aId].GetType())
|
||||
: MetadataProvider::GetActionMetadata(
|
||||
|
@@ -4,9 +4,11 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/IDE/Events/ExpressionsParameterMover.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
@@ -134,10 +136,11 @@ class GD_CORE_API ExpressionParameterMover
|
||||
|
||||
bool ExpressionsParameterMover::DoVisitInstruction(gd::Instruction& instruction,
|
||||
bool isCondition) {
|
||||
auto& metadata = isCondition ? gd::MetadataProvider::GetConditionMetadata(
|
||||
platform, instruction.GetType())
|
||||
: gd::MetadataProvider::GetActionMetadata(
|
||||
platform, instruction.GetType());
|
||||
const auto& metadata = isCondition
|
||||
? gd::MetadataProvider::GetConditionMetadata(
|
||||
platform, instruction.GetType())
|
||||
: gd::MetadataProvider::GetActionMetadata(
|
||||
platform, instruction.GetType());
|
||||
|
||||
for (std::size_t pNb = 0; pNb < metadata.parameters.size() &&
|
||||
pNb < instruction.GetParametersCount();
|
||||
|
@@ -4,9 +4,11 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/IDE/Events/ExpressionsRenamer.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
@@ -145,10 +147,11 @@ class GD_CORE_API ExpressionFunctionRenamer
|
||||
|
||||
bool ExpressionsRenamer::DoVisitInstruction(gd::Instruction& instruction,
|
||||
bool isCondition) {
|
||||
auto& metadata = isCondition ? gd::MetadataProvider::GetConditionMetadata(
|
||||
platform, instruction.GetType())
|
||||
: gd::MetadataProvider::GetActionMetadata(
|
||||
platform, instruction.GetType());
|
||||
const auto& metadata = isCondition
|
||||
? gd::MetadataProvider::GetConditionMetadata(
|
||||
platform, instruction.GetType())
|
||||
: gd::MetadataProvider::GetActionMetadata(
|
||||
platform, instruction.GetType());
|
||||
|
||||
for (std::size_t pNb = 0; pNb < metadata.parameters.size() &&
|
||||
pNb < instruction.GetParametersCount();
|
||||
|
@@ -4,16 +4,20 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "EventsFunctionTools.h"
|
||||
|
||||
#include "GDCore/Events/Expression.h"
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
|
||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||
#include "GDCore/Project/EventsFunction.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/ObjectsContainer.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
|
||||
namespace gd {
|
||||
void EventsFunctionTools::EventsFunctionToObjectsContainer(
|
||||
|
||||
void EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
|
||||
gd::Project& project,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
@@ -31,4 +35,41 @@ void EventsFunctionTools::EventsFunctionToObjectsContainer(
|
||||
outputObjectsContainer.GetObjectGroups() = eventsFunction.GetObjectGroups();
|
||||
}
|
||||
|
||||
void EventsFunctionTools::BehaviorEventsFunctionToObjectsContainer(
|
||||
gd::Project& project,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
gd::ObjectsContainer& outputObjectsContainer) {
|
||||
// The context is build the same way as free function...
|
||||
FreeEventsFunctionToObjectsContainer(project,
|
||||
eventsFunction,
|
||||
outputGlobalObjectsContainer,
|
||||
outputObjectsContainer);
|
||||
|
||||
// ...and has an "Object" by convention...
|
||||
if (!outputObjectsContainer.HasObjectNamed("Object")) {
|
||||
gd::LogWarning("No \"Object\" in a function of an events based behavior: " +
|
||||
eventsFunction.GetName() +
|
||||
". This means this function is likely misconfigured (check "
|
||||
"its parameters).");
|
||||
return;
|
||||
}
|
||||
|
||||
// ...with behaviors from properties.
|
||||
gd::Object& thisObject = outputObjectsContainer.GetObject("Object");
|
||||
for (size_t i = 0;
|
||||
i < eventsBasedBehavior.GetPropertyDescriptors().GetCount();
|
||||
i++) {
|
||||
const NamedPropertyDescriptor& propertyDescriptor =
|
||||
eventsBasedBehavior.GetPropertyDescriptors().Get(i);
|
||||
const std::vector<gd::String>& extraInfo =
|
||||
propertyDescriptor.GetExtraInfo();
|
||||
if (propertyDescriptor.GetType() == "Behavior" && extraInfo.size() > 0) {
|
||||
gd::String behaviorName = propertyDescriptor.GetName();
|
||||
thisObject.AddNewBehavior(project, extraInfo.at(0), behaviorName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -13,6 +13,7 @@ class Project;
|
||||
class ObjectsContainer;
|
||||
class ParameterMetadata;
|
||||
class EventsFunction;
|
||||
class EventsBasedBehavior;
|
||||
class Expression;
|
||||
} // namespace gd
|
||||
|
||||
@@ -23,18 +24,33 @@ namespace gd {
|
||||
class GD_CORE_API EventsFunctionTools {
|
||||
public:
|
||||
/**
|
||||
* \brief Given an events function, initialize the given objects container
|
||||
* \brief Given a free events function, initialize the given objects container
|
||||
* with objects described in the events function parameters and in
|
||||
* the events function groups.
|
||||
*
|
||||
* This is useful to create the "context" of a function, before code
|
||||
* generation for example.
|
||||
*/
|
||||
static void EventsFunctionToObjectsContainer(
|
||||
static void FreeEventsFunctionToObjectsContainer(
|
||||
gd::Project& project,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
gd::ObjectsContainer& outputObjectsContainer);
|
||||
/**
|
||||
* \brief Given a behavior events function, initialize the given objects container
|
||||
* with objects described in the events function parameters, in
|
||||
* the events function groups and in the behavior properties (for additional
|
||||
* required behaviors on the object).
|
||||
*
|
||||
* This is useful to create the "context" of a function, before code
|
||||
* generation for example.
|
||||
*/
|
||||
static void BehaviorEventsFunctionToObjectsContainer(
|
||||
gd::Project& project,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
gd::ObjectsContainer& outputObjectsContainer);
|
||||
};
|
||||
} // namespace gd
|
||||
|
||||
|
@@ -27,50 +27,6 @@ namespace gd {
|
||||
|
||||
PlatformLoader::PlatformLoader() {}
|
||||
|
||||
void PlatformLoader::LoadAllPlatformsInManager(gd::String dir) {
|
||||
{
|
||||
#if defined(WINDOWS)
|
||||
std::shared_ptr<gd::Platform> platform = LoadPlatformInManager("GDCpp.dll");
|
||||
#elif defined(LINUX)
|
||||
std::shared_ptr<gd::Platform> platform =
|
||||
LoadPlatformInManager("libGDCpp.so");
|
||||
#elif defined(MACOS)
|
||||
std::shared_ptr<gd::Platform> platform =
|
||||
LoadPlatformInManager("libGDCpp.dylib");
|
||||
#else
|
||||
#warning Add the appropriate filename here for the C++ Platform!
|
||||
std::shared_ptr<gd::Platform> platform;
|
||||
#endif
|
||||
if (platform)
|
||||
gd::ExtensionsLoader::LoadAllExtensions("./CppPlatform/Extensions/",
|
||||
*platform);
|
||||
}
|
||||
|
||||
{
|
||||
#if defined(WINDOWS)
|
||||
std::shared_ptr<gd::Platform> platform =
|
||||
LoadPlatformInManager("./JsPlatform/GDJS.dll");
|
||||
#elif defined(LINUX)
|
||||
std::shared_ptr<gd::Platform> platform =
|
||||
LoadPlatformInManager("./JsPlatform/libGDJS.so");
|
||||
#elif defined(MACOS)
|
||||
std::shared_ptr<gd::Platform> platform =
|
||||
LoadPlatformInManager("./JsPlatform/libGDJS.dylib");
|
||||
#else
|
||||
#warning Add the appropriate filename here for the Js Platform!
|
||||
std::shared_ptr<gd::Platform> platform;
|
||||
#endif
|
||||
if (platform)
|
||||
gd::ExtensionsLoader::LoadAllExtensions("./JsPlatform/Extensions/",
|
||||
*platform);
|
||||
if (platform)
|
||||
gd::ExtensionsLoader::LoadAllExtensions(
|
||||
"./CppPlatform/Extensions/", *platform, true);
|
||||
}
|
||||
|
||||
gd::ExtensionsLoader::ExtensionsLoadingDone("./CppPlatform/Extensions/");
|
||||
}
|
||||
|
||||
std::shared_ptr<gd::Platform> PlatformLoader::LoadPlatformInManager(
|
||||
gd::String fullpath) {
|
||||
std::cout << "Loading platform " << fullpath << "..." << std::endl;
|
||||
|
@@ -30,15 +30,6 @@ passing
|
||||
*/
|
||||
class GD_CORE_API PlatformLoader {
|
||||
public:
|
||||
/**
|
||||
* Load all the platforms available in a directory.
|
||||
*
|
||||
* \param dir The directory where platforms must be searched for.
|
||||
*
|
||||
* \todo For now, only GDCpp.dll and GDJS.dll are loaded.
|
||||
*/
|
||||
static void LoadAllPlatformsInManager(gd::String dir);
|
||||
|
||||
/**
|
||||
* Load a specific platform.
|
||||
*
|
||||
|
12
Core/GDCore/IDE/UnfilledRequiredBehaviorPropertyProblem.cpp
Normal file
12
Core/GDCore/IDE/UnfilledRequiredBehaviorPropertyProblem.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2021 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "UnfilledRequiredBehaviorPropertyProblem.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
UnfilledRequiredBehaviorPropertyProblem::~UnfilledRequiredBehaviorPropertyProblem(){};
|
||||
|
||||
} // namespace gd
|
80
Core/GDCore/IDE/UnfilledRequiredBehaviorPropertyProblem.h
Normal file
80
Core/GDCore/IDE/UnfilledRequiredBehaviorPropertyProblem.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2021 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef GDCORE_UNFILLEDREQUIREDBEHAVIORPROPERTYPROBLEM_H
|
||||
#define GDCORE_UNFILLEDREQUIREDBEHAVIORPROPERTYPROBLEM_H
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class Project;
|
||||
class Object;
|
||||
class BehaviorContent;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief A problem when a required behavior property is not fill correctly.
|
||||
*/
|
||||
class GD_CORE_API UnfilledRequiredBehaviorPropertyProblem {
|
||||
public:
|
||||
UnfilledRequiredBehaviorPropertyProblem(
|
||||
const gd::Project& sourceProject_,
|
||||
gd::Object& sourceObject_,
|
||||
gd::BehaviorContent& sourceBehaviorContent_,
|
||||
const gd::String& sourcePropertyName_,
|
||||
const gd::String& expectedBehaviorTypeName_)
|
||||
: sourceProject(sourceProject_),
|
||||
sourceObject(sourceObject_),
|
||||
sourceBehaviorContent(sourceBehaviorContent_),
|
||||
sourcePropertyName(sourcePropertyName_),
|
||||
expectedBehaviorTypeName(expectedBehaviorTypeName_){};
|
||||
virtual ~UnfilledRequiredBehaviorPropertyProblem();
|
||||
|
||||
/**
|
||||
* \brief Return the project where the problem appears
|
||||
*/
|
||||
virtual const gd::Project& GetSourceProject() const { return sourceProject; }
|
||||
|
||||
/**
|
||||
* \brief Return the object where the problem appears.
|
||||
*/
|
||||
virtual gd::Object& GetSourceObject() const { return sourceObject; }
|
||||
|
||||
/**
|
||||
* \brief Return the behavior where the problem appears.
|
||||
*/
|
||||
virtual gd::BehaviorContent& GetSourceBehaviorContent() const {
|
||||
return sourceBehaviorContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the property where the problem appears.
|
||||
*/
|
||||
virtual const gd::String& GetSourcePropertyName() const {
|
||||
return sourcePropertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the behavior type name that is expected for the required
|
||||
* behavior property.
|
||||
*/
|
||||
virtual const gd::String& GetExpectedBehaviorTypeName() const {
|
||||
return expectedBehaviorTypeName;
|
||||
}
|
||||
|
||||
private:
|
||||
const gd::Project& sourceProject;
|
||||
gd::Object& sourceObject;
|
||||
gd::BehaviorContent& sourceBehaviorContent;
|
||||
const gd::String sourcePropertyName;
|
||||
|
||||
const gd::String expectedBehaviorTypeName;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_UNFILLEDREQUIREDBEHAVIORPROPERTYPROBLEM_H
|
@@ -5,9 +5,12 @@
|
||||
*/
|
||||
#include "WholeProjectRefactorer.h"
|
||||
|
||||
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/IDE/DependenciesAnalyzer.h"
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/IDE/Events/EventsBehaviorRenamer.h"
|
||||
#include "GDCore/IDE/Events/EventsRefactorer.h"
|
||||
#include "GDCore/IDE/Events/ExpressionsParameterMover.h"
|
||||
#include "GDCore/IDE/Events/ExpressionsRenamer.h"
|
||||
@@ -15,6 +18,9 @@
|
||||
#include "GDCore/IDE/Events/InstructionsTypeRenamer.h"
|
||||
#include "GDCore/IDE/EventsFunctionTools.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
|
||||
#include "GDCore/IDE/UnfilledRequiredBehaviorPropertyProblem.h"
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/BehaviorContent.h"
|
||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDCore/Project/ExternalEvents.h"
|
||||
@@ -51,6 +57,10 @@ gd::String GetBehaviorFullType(const gd::String& extensionName,
|
||||
|
||||
namespace gd {
|
||||
|
||||
// By convention, the first parameter of an events based behavior method is
|
||||
// always called "Object".
|
||||
const gd::String WholeProjectRefactorer::behaviorObjectParameterName = "Object";
|
||||
|
||||
void WholeProjectRefactorer::ExposeProjectEvents(
|
||||
gd::Project& project, gd::ArbitraryEventsWorker& worker) {
|
||||
// See also gd::Project::ExposeResources for a method that traverse the whole
|
||||
@@ -115,7 +125,7 @@ void WholeProjectRefactorer::ExposeProjectEvents(
|
||||
for (auto&& eventsFunction : eventsFunctionsExtension.GetInternalVector()) {
|
||||
gd::ObjectsContainer globalObjectsAndGroups;
|
||||
gd::ObjectsContainer objectsAndGroups;
|
||||
gd::EventsFunctionTools::EventsFunctionToObjectsContainer(
|
||||
gd::EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
|
||||
project, *eventsFunction, globalObjectsAndGroups, objectsAndGroups);
|
||||
|
||||
worker.Launch(eventsFunction->GetEvents(),
|
||||
@@ -127,22 +137,31 @@ void WholeProjectRefactorer::ExposeProjectEvents(
|
||||
for (auto&& eventsBasedBehavior :
|
||||
eventsFunctionsExtension.GetEventsBasedBehaviors()
|
||||
.GetInternalVector()) {
|
||||
auto& behaviorEventsFunctions = eventsBasedBehavior->GetEventsFunctions();
|
||||
for (auto&& eventsFunction :
|
||||
behaviorEventsFunctions.GetInternalVector()) {
|
||||
gd::ObjectsContainer globalObjectsAndGroups;
|
||||
gd::ObjectsContainer objectsAndGroups;
|
||||
gd::EventsFunctionTools::EventsFunctionToObjectsContainer(
|
||||
project, *eventsFunction, globalObjectsAndGroups, objectsAndGroups);
|
||||
|
||||
worker.Launch(eventsFunction->GetEvents(),
|
||||
globalObjectsAndGroups,
|
||||
objectsAndGroups);
|
||||
}
|
||||
ExposeEventsBasedBehaviorEvents(project, *eventsBasedBehavior, worker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::ExposeEventsBasedBehaviorEvents(
|
||||
gd::Project& project,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
gd::ArbitraryEventsWorkerWithContext& worker) {
|
||||
auto& behaviorEventsFunctions = eventsBasedBehavior.GetEventsFunctions();
|
||||
for (auto&& eventsFunction : behaviorEventsFunctions.GetInternalVector()) {
|
||||
gd::ObjectsContainer globalObjectsAndGroups;
|
||||
gd::ObjectsContainer objectsAndGroups;
|
||||
gd::EventsFunctionTools::BehaviorEventsFunctionToObjectsContainer(
|
||||
project,
|
||||
eventsBasedBehavior,
|
||||
*eventsFunction,
|
||||
globalObjectsAndGroups,
|
||||
objectsAndGroups);
|
||||
|
||||
worker.Launch(
|
||||
eventsFunction->GetEvents(), globalObjectsAndGroups, objectsAndGroups);
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::ExposeProjectObjects(
|
||||
gd::Project& project, gd::ArbitraryObjectsWorker& worker) {
|
||||
worker.Launch(project);
|
||||
@@ -192,7 +211,7 @@ void WholeProjectRefactorer::EnsureBehaviorEventsFunctionsProperParameters(
|
||||
|
||||
parameters[0]
|
||||
.SetType("object")
|
||||
.SetName("Object")
|
||||
.SetName(behaviorObjectParameterName)
|
||||
.SetDescription("Object")
|
||||
.SetExtraInfo(eventsBasedBehavior.GetObjectType());
|
||||
parameters[1]
|
||||
@@ -470,7 +489,7 @@ void WholeProjectRefactorer::MoveBehaviorEventsFunctionParameter(
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameBehaviorProperty(
|
||||
void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
|
||||
gd::Project& project,
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
@@ -479,41 +498,294 @@ void WholeProjectRefactorer::RenameBehaviorProperty(
|
||||
auto& properties = eventsBasedBehavior.GetPropertyDescriptors();
|
||||
if (!properties.Has(oldPropertyName)) return;
|
||||
|
||||
// Order is important: we first rename the expressions then the instructions,
|
||||
// to avoid being unable to fetch the metadata (the types of parameters) of
|
||||
// instructions after they are renamed.
|
||||
gd::ExpressionsRenamer expressionRenamer =
|
||||
gd::ExpressionsRenamer(project.GetCurrentPlatform());
|
||||
expressionRenamer.SetReplacedBehaviorExpression(
|
||||
GetBehaviorFullType(eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName()),
|
||||
EventsBasedBehavior::GetPropertyExpressionName(oldPropertyName),
|
||||
EventsBasedBehavior::GetPropertyExpressionName(newPropertyName));
|
||||
ExposeProjectEvents(project, expressionRenamer);
|
||||
if (properties.Get(oldPropertyName).GetType() == "Behavior") {
|
||||
// This is a property representing another behavior that must exist on the
|
||||
// object.
|
||||
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName(),
|
||||
EventsBasedBehavior::GetPropertyActionName(oldPropertyName)),
|
||||
GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName(),
|
||||
EventsBasedBehavior::GetPropertyActionName(newPropertyName)));
|
||||
ExposeProjectEvents(project, actionRenamer);
|
||||
// This other "required behavior" uses the property name, that is about to
|
||||
// change, as its name.
|
||||
// So we must change all reference to this name in the events of the
|
||||
// behavior functions.
|
||||
gd::EventsBehaviorRenamer behaviorRenamer(project.GetCurrentPlatform(),
|
||||
behaviorObjectParameterName,
|
||||
oldPropertyName,
|
||||
newPropertyName);
|
||||
|
||||
gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName(),
|
||||
EventsBasedBehavior::GetPropertyConditionName(oldPropertyName)),
|
||||
GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName(),
|
||||
EventsBasedBehavior::GetPropertyConditionName(newPropertyName)));
|
||||
ExposeProjectEvents(project, conditionRenamer);
|
||||
ExposeEventsBasedBehaviorEvents(
|
||||
project, eventsBasedBehavior, behaviorRenamer);
|
||||
} else {
|
||||
// Properties that represent primitive values will be used through
|
||||
// their related actions/conditions/expressions. Rename these.
|
||||
|
||||
// Order is important: we first rename the expressions then the
|
||||
// instructions, to avoid being unable to fetch the metadata (the types of
|
||||
// parameters) of instructions after they are renamed.
|
||||
gd::ExpressionsRenamer expressionRenamer =
|
||||
gd::ExpressionsRenamer(project.GetCurrentPlatform());
|
||||
expressionRenamer.SetReplacedBehaviorExpression(
|
||||
GetBehaviorFullType(eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName()),
|
||||
EventsBasedBehavior::GetPropertyExpressionName(oldPropertyName),
|
||||
EventsBasedBehavior::GetPropertyExpressionName(newPropertyName));
|
||||
ExposeProjectEvents(project, expressionRenamer);
|
||||
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName(),
|
||||
EventsBasedBehavior::GetPropertyActionName(oldPropertyName)),
|
||||
GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName(),
|
||||
EventsBasedBehavior::GetPropertyActionName(newPropertyName)));
|
||||
ExposeProjectEvents(project, actionRenamer);
|
||||
|
||||
gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName(),
|
||||
EventsBasedBehavior::GetPropertyConditionName(oldPropertyName)),
|
||||
GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName(),
|
||||
EventsBasedBehavior::GetPropertyConditionName(newPropertyName)));
|
||||
ExposeProjectEvents(project, conditionRenamer);
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::AddBehaviorAndRequiredBehaviors(
|
||||
gd::Project& project,
|
||||
gd::Object& object,
|
||||
const gd::String& behaviorType,
|
||||
const gd::String& behaviorName) {
|
||||
if (object.AddNewBehavior(project, behaviorType, behaviorName) == nullptr) {
|
||||
// The behavior type/metadata can't be found.
|
||||
return;
|
||||
};
|
||||
|
||||
const gd::Platform& platform = project.GetCurrentPlatform();
|
||||
const gd::BehaviorMetadata& behaviorMetadata =
|
||||
MetadataProvider::GetBehaviorMetadata(platform, behaviorType);
|
||||
if (MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
|
||||
// Should not happen because the behavior was added successfully (so its
|
||||
// metadata are valid) - but double check anyway and bail out if the
|
||||
// behavior metadata are invalid.
|
||||
return;
|
||||
}
|
||||
|
||||
gd::Behavior& behavior = behaviorMetadata.Get();
|
||||
gd::BehaviorContent& behaviorContent = object.GetBehavior(behaviorName);
|
||||
for (auto const& keyValue :
|
||||
behavior.GetProperties(behaviorContent.GetContent())) {
|
||||
const gd::String& propertyName = keyValue.first;
|
||||
const gd::PropertyDescriptor& property = keyValue.second;
|
||||
if (property.GetType().LowerCase() == "behavior") {
|
||||
const std::vector<gd::String>& extraInfo = property.GetExtraInfo();
|
||||
if (extraInfo.size() == 0) {
|
||||
// very unlikely
|
||||
continue;
|
||||
}
|
||||
const gd::String& requiredBehaviorType = extraInfo.at(0);
|
||||
const auto behaviorContents =
|
||||
WholeProjectRefactorer::GetBehaviorsWithType(object,
|
||||
requiredBehaviorType);
|
||||
const gd::String* defaultBehaviorName = nullptr;
|
||||
if (behaviorContents.size() == 0) {
|
||||
const gd::BehaviorMetadata& requiredBehaviorMetadata =
|
||||
MetadataProvider::GetBehaviorMetadata(platform,
|
||||
requiredBehaviorType);
|
||||
const gd::String& requiredBehaviorName =
|
||||
requiredBehaviorMetadata.GetDefaultName();
|
||||
WholeProjectRefactorer::AddBehaviorAndRequiredBehaviors(
|
||||
project, object, requiredBehaviorType, requiredBehaviorName);
|
||||
defaultBehaviorName = &requiredBehaviorName;
|
||||
} else {
|
||||
defaultBehaviorName = &behaviorContents.at(0);
|
||||
}
|
||||
behavior.UpdateProperty(
|
||||
behaviorContent.GetContent(), propertyName, *defaultBehaviorName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<gd::String> WholeProjectRefactorer::GetBehaviorsWithType(
|
||||
const gd::Object& object, const gd::String& type) {
|
||||
std::vector<gd::String> behaviors;
|
||||
for (auto& behaviorName : object.GetAllBehaviorNames()) {
|
||||
const gd::BehaviorContent& behaviorContent =
|
||||
object.GetBehavior(behaviorName);
|
||||
if (behaviorContent.GetTypeName() == type) {
|
||||
behaviors.push_back(behaviorName);
|
||||
}
|
||||
}
|
||||
return behaviors;
|
||||
}
|
||||
|
||||
std::vector<gd::String> WholeProjectRefactorer::FindDependentBehaviorNames(
|
||||
const gd::Project& project,
|
||||
const gd::Object& object,
|
||||
const gd::String& behaviorName) {
|
||||
std::unordered_set<gd::String> dependentBehaviorNames;
|
||||
WholeProjectRefactorer::FindDependentBehaviorNames(
|
||||
project, object, behaviorName, dependentBehaviorNames);
|
||||
std::vector<gd::String> results;
|
||||
results.insert(results.end(),
|
||||
dependentBehaviorNames.begin(),
|
||||
dependentBehaviorNames.end());
|
||||
return results;
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::FindDependentBehaviorNames(
|
||||
const gd::Project& project,
|
||||
const gd::Object& object,
|
||||
const gd::String& behaviorName,
|
||||
std::unordered_set<gd::String>& dependentBehaviorNames) {
|
||||
const gd::Platform& platform = project.GetCurrentPlatform();
|
||||
for (auto const& objectBehaviorName : object.GetAllBehaviorNames()) {
|
||||
const gd::BehaviorContent& behaviorContent =
|
||||
object.GetBehavior(objectBehaviorName);
|
||||
const auto& behaviorMetadata = MetadataProvider::GetBehaviorMetadata(
|
||||
platform, behaviorContent.GetTypeName());
|
||||
if (MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
|
||||
// Ignore this behavior as it's unknown.
|
||||
continue;
|
||||
}
|
||||
|
||||
gd::Behavior& behavior = behaviorMetadata.Get();
|
||||
for (auto const& keyValue :
|
||||
behavior.GetProperties(behaviorContent.GetContent())) {
|
||||
const gd::String& propertyName = keyValue.first;
|
||||
const gd::PropertyDescriptor& property = keyValue.second;
|
||||
if (property.GetType().LowerCase() == "behavior" &&
|
||||
property.GetValue() == behaviorName &&
|
||||
dependentBehaviorNames.find(objectBehaviorName) ==
|
||||
dependentBehaviorNames.end()) {
|
||||
dependentBehaviorNames.insert(objectBehaviorName);
|
||||
WholeProjectRefactorer::FindDependentBehaviorNames(
|
||||
project, object, objectBehaviorName, dependentBehaviorNames);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<gd::UnfilledRequiredBehaviorPropertyProblem>
|
||||
WholeProjectRefactorer::FindInvalidRequiredBehaviorProperties(
|
||||
const gd::Project& project) {
|
||||
std::vector<gd::UnfilledRequiredBehaviorPropertyProblem>
|
||||
invalidRequiredBehaviorProperties;
|
||||
auto findInvalidRequiredBehaviorPropertiesInObjects =
|
||||
[&project, &invalidRequiredBehaviorProperties](
|
||||
const std::vector<std::unique_ptr<gd::Object> >& objectsList) {
|
||||
for (auto& object : objectsList) {
|
||||
for (auto& behaviorContentKeyValuePair :
|
||||
object->GetAllBehaviorContents()) {
|
||||
gd::BehaviorContent& behaviorContent =
|
||||
*behaviorContentKeyValuePair.second;
|
||||
|
||||
const auto& behaviorMetadata =
|
||||
gd::MetadataProvider::GetBehaviorMetadata(
|
||||
project.GetCurrentPlatform(),
|
||||
behaviorContent.GetTypeName());
|
||||
if (MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
|
||||
std::cout << "Could not find metadata for behavior with type \""
|
||||
<< behaviorContent.GetTypeName() << "\"" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& behavior = behaviorMetadata.Get();
|
||||
|
||||
for (auto const& keyValue :
|
||||
behavior.GetProperties(behaviorContent.GetContent())) {
|
||||
const gd::String& propertyName = keyValue.first;
|
||||
const gd::PropertyDescriptor& property = keyValue.second;
|
||||
if (property.GetType().LowerCase() != "behavior") {
|
||||
continue;
|
||||
}
|
||||
const gd::String& requiredBehaviorName = property.GetValue();
|
||||
const std::vector<gd::String>& extraInfo =
|
||||
property.GetExtraInfo();
|
||||
if (extraInfo.size() == 0) {
|
||||
// very unlikely
|
||||
continue;
|
||||
}
|
||||
const gd::String& requiredBehaviorType = extraInfo.at(0);
|
||||
|
||||
if (requiredBehaviorName == "" ||
|
||||
!object->HasBehaviorNamed(requiredBehaviorName) ||
|
||||
object->GetBehavior(requiredBehaviorName).GetTypeName() !=
|
||||
requiredBehaviorType) {
|
||||
auto problem = UnfilledRequiredBehaviorPropertyProblem(
|
||||
project,
|
||||
*object,
|
||||
behaviorContent,
|
||||
propertyName,
|
||||
requiredBehaviorType);
|
||||
invalidRequiredBehaviorProperties.push_back(problem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Find in global objects
|
||||
findInvalidRequiredBehaviorPropertiesInObjects(project.GetObjects());
|
||||
|
||||
// Find in layout objects.
|
||||
for (std::size_t i = 0; i < project.GetLayoutsCount(); ++i) {
|
||||
const gd::Layout& layout = project.GetLayout(i);
|
||||
findInvalidRequiredBehaviorPropertiesInObjects(layout.GetObjects());
|
||||
}
|
||||
return invalidRequiredBehaviorProperties;
|
||||
}
|
||||
|
||||
bool WholeProjectRefactorer::FixInvalidRequiredBehaviorProperties(
|
||||
gd::Project& project) {
|
||||
const auto& invalidRequiredBehaviorProblems =
|
||||
FindInvalidRequiredBehaviorProperties(project);
|
||||
for (const auto& problem : invalidRequiredBehaviorProblems) {
|
||||
auto& object = problem.GetSourceObject();
|
||||
auto suggestedBehaviorNames =
|
||||
GetBehaviorsWithType(object, problem.GetExpectedBehaviorTypeName());
|
||||
auto& behaviorContent = problem.GetSourceBehaviorContent();
|
||||
auto& behaviorMetadata = MetadataProvider::GetBehaviorMetadata(
|
||||
project.GetCurrentPlatform(), behaviorContent.GetTypeName());
|
||||
if (MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& behavior = behaviorMetadata.Get();
|
||||
if (suggestedBehaviorNames.empty()) {
|
||||
// No matching behavior on the object.
|
||||
// Add required behaviors on the object.
|
||||
|
||||
auto& expectedBehaviorMetadata = MetadataProvider::GetBehaviorMetadata(
|
||||
project.GetCurrentPlatform(), problem.GetExpectedBehaviorTypeName());
|
||||
if (MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const gd::String& newBehaviorName =
|
||||
expectedBehaviorMetadata.GetDefaultName();
|
||||
AddBehaviorAndRequiredBehaviors(project,
|
||||
object,
|
||||
problem.GetExpectedBehaviorTypeName(),
|
||||
newBehaviorName);
|
||||
behavior.UpdateProperty(behaviorContent.GetContent(),
|
||||
problem.GetSourcePropertyName(),
|
||||
newBehaviorName);
|
||||
} else {
|
||||
// There is a matching behavior on the object use it by default.
|
||||
behavior.UpdateProperty(
|
||||
behaviorContent.GetContent(),
|
||||
problem.GetSourcePropertyName(),
|
||||
// It's unlikely the object has 2 behaviors of the same type.
|
||||
suggestedBehaviorNames[0]);
|
||||
}
|
||||
}
|
||||
|
||||
return !invalidRequiredBehaviorProblems.empty();
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
@@ -678,6 +950,31 @@ void WholeProjectRefactorer::DoRenameBehavior(
|
||||
}
|
||||
};
|
||||
|
||||
// Rename behavior in required behavior properties
|
||||
for (std::size_t e = 0; e < project.GetEventsFunctionsExtensionsCount();
|
||||
e++) {
|
||||
auto& eventsFunctionsExtension = project.GetEventsFunctionsExtension(e);
|
||||
|
||||
for (auto&& eventsBasedBehavior :
|
||||
eventsFunctionsExtension.GetEventsBasedBehaviors()
|
||||
.GetInternalVector()) {
|
||||
for (size_t i = 0;
|
||||
i < eventsBasedBehavior->GetPropertyDescriptors().GetCount();
|
||||
i++) {
|
||||
NamedPropertyDescriptor& propertyDescriptor =
|
||||
eventsBasedBehavior->GetPropertyDescriptors().Get(i);
|
||||
std::vector<gd::String>& extraInfo = propertyDescriptor.GetExtraInfo();
|
||||
if (propertyDescriptor.GetType() == "Behavior" &&
|
||||
extraInfo.size() > 0) {
|
||||
const gd::String& requiredBehaviorType = extraInfo[0];
|
||||
if (requiredBehaviorType == oldBehaviorType) {
|
||||
extraInfo[0] = newBehaviorType;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Rename behavior in global objects
|
||||
renameBehaviorTypeInObjects(project.GetObjects());
|
||||
|
||||
|
@@ -6,10 +6,13 @@
|
||||
#ifndef GDCORE_WHOLEPROJECTREFACTORER_H
|
||||
#define GDCORE_WHOLEPROJECTREFACTORER_H
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
namespace gd {
|
||||
class Platform;
|
||||
class Project;
|
||||
class Layout;
|
||||
class Object;
|
||||
class String;
|
||||
class EventsFunctionsExtension;
|
||||
class EventsFunction;
|
||||
@@ -18,6 +21,10 @@ class EventsBasedBehavior;
|
||||
class ArbitraryEventsWorker;
|
||||
class ArbitraryObjectsWorker;
|
||||
class ArbitraryEventsWorkerWithContext;
|
||||
class Behavior;
|
||||
class BehaviorContent;
|
||||
class BehaviorMetadata;
|
||||
class UnfilledRequiredBehaviorPropertyProblem;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
@@ -51,13 +58,24 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
gd::ArbitraryEventsWorkerWithContext& worker);
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on all ObjectContainers of the project (global,
|
||||
* layouts...)
|
||||
* \brief Call the specified worker on all events of the events based behavior
|
||||
*
|
||||
* This should be the preferred way to traverse all the events of an events
|
||||
* based behavior
|
||||
*/
|
||||
static void ExposeEventsBasedBehaviorEvents(
|
||||
gd::Project& project,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
gd::ArbitraryEventsWorkerWithContext& worker);
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on all ObjectContainers of the project
|
||||
* (global, layouts...)
|
||||
*
|
||||
* This should be the preferred way to traverse all the objects of a project.
|
||||
*/
|
||||
static void ExposeProjectObjects(
|
||||
gd::Project& project, gd::ArbitraryObjectsWorker& worker);
|
||||
static void ExposeProjectObjects(gd::Project& project,
|
||||
gd::ArbitraryObjectsWorker& worker);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project **before** an events function extension is
|
||||
@@ -140,13 +158,52 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
* This is because the property is expected to have its old name for the
|
||||
* refactoring.
|
||||
*/
|
||||
static void RenameBehaviorProperty(
|
||||
static void RenameEventsBasedBehaviorProperty(
|
||||
gd::Project& project,
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::String& oldPropertyName,
|
||||
const gd::String& newPropertyName);
|
||||
|
||||
/**
|
||||
* \brief Add a behavior to an object and add required behaviors if necessary
|
||||
* to fill every behavior properties of the added behaviors.
|
||||
*/
|
||||
static void AddBehaviorAndRequiredBehaviors(gd::Project& project,
|
||||
gd::Object& object,
|
||||
const gd::String& behaviorType,
|
||||
const gd::String& behaviorName);
|
||||
|
||||
/**
|
||||
* \brief Find every behavior of the object that needs the given behaviors
|
||||
* directly or indirectly (because of "required behavior" properties).
|
||||
*/
|
||||
static std::vector<gd::String> FindDependentBehaviorNames(
|
||||
const gd::Project& project,
|
||||
const gd::Object& object,
|
||||
const gd::String& behaviorName);
|
||||
|
||||
/**
|
||||
* \brief Find the names of the behaviors with the specified type on the object.
|
||||
*/
|
||||
static std::vector<gd::String> GetBehaviorsWithType(const gd::Object& object,
|
||||
const gd::String& type);
|
||||
|
||||
/**
|
||||
* \brief Find in the project objects having behaviors with "behavior" properties that
|
||||
* don't have a valid value (i.e: pointing to a non existing behavior, or of a wrong type).
|
||||
*/
|
||||
static std::vector<gd::UnfilledRequiredBehaviorPropertyProblem>
|
||||
FindInvalidRequiredBehaviorProperties(const gd::Project& project);
|
||||
|
||||
/**
|
||||
* \brief Fix in the project objects having behaviors with "behavior" properties that
|
||||
* don't have a valid value (i.e: pointing to a non existing behavior, or of a wrong type),
|
||||
* by setting a proper behavior, or adding missing behaviors to these objects.
|
||||
*/
|
||||
static bool
|
||||
FixInvalidRequiredBehaviorProperties(gd::Project& project);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project **before** a behavior is renamed.
|
||||
*
|
||||
@@ -267,6 +324,14 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
const gd::String& oldBehaviorType,
|
||||
const gd::String& newBehaviorType);
|
||||
|
||||
static void FindDependentBehaviorNames(
|
||||
const gd::Project& project,
|
||||
const gd::Object& object,
|
||||
const gd::String& behaviorName,
|
||||
std::unordered_set<gd::String>& dependentBehaviorNames);
|
||||
|
||||
static const gd::String behaviorObjectParameterName;
|
||||
|
||||
WholeProjectRefactorer(){};
|
||||
};
|
||||
|
||||
|
@@ -1,213 +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 "GDCore/Project/ImageManager.h"
|
||||
#include <SFML/OpenGL.hpp>
|
||||
#include "GDCore/Project/ResourcesLoader.h"
|
||||
#include "GDCore/Project/ResourcesManager.h"
|
||||
#include "GDCore/Tools/InvalidImage.h"
|
||||
#if !defined(ANDROID) && !defined(MACOS)
|
||||
#include <GL/glu.h>
|
||||
#endif
|
||||
#undef LoadImage // thx windows.h
|
||||
|
||||
namespace gd {
|
||||
|
||||
ImageManager::ImageManager() : resourcesManager(NULL) {
|
||||
#if !defined(EMSCRIPTEN)
|
||||
badTexture = std::make_shared<SFMLTextureWrapper>();
|
||||
badTexture->texture.loadFromMemory(gd::InvalidImageData,
|
||||
sizeof(gd::InvalidImageData));
|
||||
badTexture->texture.setSmooth(false);
|
||||
badTexture->image = badTexture->texture.copyToImage();
|
||||
#endif
|
||||
}
|
||||
|
||||
std::shared_ptr<SFMLTextureWrapper> ImageManager::GetSFMLTexture(
|
||||
const gd::String& name) const {
|
||||
if (!resourcesManager) {
|
||||
std::cout << "ImageManager has no ResourcesManager associated with.";
|
||||
return badTexture;
|
||||
}
|
||||
|
||||
if (alreadyLoadedImages.find(name) != alreadyLoadedImages.end() &&
|
||||
!alreadyLoadedImages.find(name)->second.expired())
|
||||
return alreadyLoadedImages.find(name)->second.lock();
|
||||
|
||||
std::cout << "ImageManager: Loading " << name << ".";
|
||||
|
||||
// Load only an image when necessary
|
||||
try {
|
||||
ImageResource& image =
|
||||
dynamic_cast<ImageResource&>(resourcesManager->GetResource(name));
|
||||
|
||||
auto texture = std::make_shared<SFMLTextureWrapper>();
|
||||
ResourcesLoader::Get()->LoadSFMLImage(image.GetFile(), texture->image);
|
||||
texture->texture.loadFromImage(texture->image);
|
||||
texture->texture.setSmooth(image.smooth);
|
||||
|
||||
alreadyLoadedImages[name] = texture;
|
||||
#if defined(GD_IDE_ONLY)
|
||||
if (preventUnloading)
|
||||
unloadingPreventer.push_back(
|
||||
texture); // If unload prevention is activated, add the image to the
|
||||
// list dedicated to prevent images from being unloaded.
|
||||
#endif
|
||||
|
||||
return texture;
|
||||
} catch (...) {
|
||||
}
|
||||
|
||||
std::cout << " Resource not found." << std::endl;
|
||||
|
||||
return badTexture;
|
||||
}
|
||||
|
||||
bool ImageManager::HasLoadedSFMLTexture(const gd::String& name) const {
|
||||
if (alreadyLoadedImages.find(name) != alreadyLoadedImages.end() &&
|
||||
!alreadyLoadedImages.find(name)->second.expired())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ImageManager::SetSFMLTextureAsPermanentlyLoaded(
|
||||
const gd::String& name,
|
||||
std::shared_ptr<SFMLTextureWrapper>& texture) const {
|
||||
if (alreadyLoadedImages.find(name) == alreadyLoadedImages.end() ||
|
||||
alreadyLoadedImages.find(name)->second.expired())
|
||||
alreadyLoadedImages[name] = texture;
|
||||
|
||||
if (permanentlyLoadedImages.find(name) == permanentlyLoadedImages.end())
|
||||
permanentlyLoadedImages[name] = texture;
|
||||
}
|
||||
|
||||
void ImageManager::ReloadImage(const gd::String& name) const {
|
||||
if (!resourcesManager) {
|
||||
std::cout << "ImageManager has no ResourcesManager associated with.";
|
||||
return;
|
||||
}
|
||||
|
||||
// Verify if image is in memory. If not, it will be automatically reloaded
|
||||
// when necessary.
|
||||
if (alreadyLoadedImages.find(name) == alreadyLoadedImages.end() ||
|
||||
alreadyLoadedImages.find(name)->second.expired())
|
||||
return;
|
||||
|
||||
// Image still in memory, get it and update it.
|
||||
std::shared_ptr<SFMLTextureWrapper> oldTexture =
|
||||
alreadyLoadedImages.find(name)->second.lock();
|
||||
|
||||
try {
|
||||
ImageResource& image =
|
||||
dynamic_cast<ImageResource&>(resourcesManager->GetResource(name));
|
||||
|
||||
std::cout << "ImageManager: Reload " << name << std::endl;
|
||||
|
||||
ResourcesLoader::Get()->LoadSFMLImage(image.GetFile(), oldTexture->image);
|
||||
oldTexture->texture.loadFromImage(oldTexture->image);
|
||||
oldTexture->texture.setSmooth(image.smooth);
|
||||
|
||||
return;
|
||||
} catch (...) { /*The ressource is not an image*/
|
||||
}
|
||||
|
||||
// Image not present anymore in image list.
|
||||
std::cout << "ImageManager: " << name << " is not available anymore."
|
||||
<< std::endl;
|
||||
*oldTexture = *badTexture;
|
||||
}
|
||||
|
||||
std::shared_ptr<OpenGLTextureWrapper> ImageManager::GetOpenGLTexture(
|
||||
const gd::String& name) const {
|
||||
if (alreadyLoadedOpenGLTextures.find(name) !=
|
||||
alreadyLoadedOpenGLTextures.end() &&
|
||||
!alreadyLoadedOpenGLTextures.find(name)->second.expired())
|
||||
return alreadyLoadedOpenGLTextures.find(name)->second.lock();
|
||||
|
||||
std::cout << "Load OpenGL Texture" << name << std::endl;
|
||||
|
||||
std::shared_ptr<OpenGLTextureWrapper> texture =
|
||||
std::make_shared<OpenGLTextureWrapper>(GetSFMLTexture(name));
|
||||
alreadyLoadedOpenGLTextures[name] = texture;
|
||||
return texture;
|
||||
}
|
||||
|
||||
void ImageManager::LoadPermanentImages() {
|
||||
if (!resourcesManager) {
|
||||
std::cout << "ImageManager has no ResourcesManager associated with.";
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a new list of permanently loaded images but do not delete now the
|
||||
// old list so as not to unload images that could be still present.
|
||||
std::map<gd::String, std::shared_ptr<SFMLTextureWrapper> >
|
||||
newPermanentlyLoadedImages;
|
||||
|
||||
std::vector<gd::String> resources = resourcesManager->GetAllResourceNames();
|
||||
for (std::size_t i = 0; i < resources.size(); i++) {
|
||||
try {
|
||||
ImageResource& image = dynamic_cast<ImageResource&>(
|
||||
resourcesManager->GetResource(resources[i]));
|
||||
|
||||
if (image.alwaysLoaded)
|
||||
newPermanentlyLoadedImages[image.GetName()] =
|
||||
GetSFMLTexture(image.GetName());
|
||||
} catch (...) { /*The resource is not an image, we don't care about it.*/
|
||||
}
|
||||
}
|
||||
|
||||
permanentlyLoadedImages = newPermanentlyLoadedImages;
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
void ImageManager::PreventImagesUnloading() {
|
||||
preventUnloading = true;
|
||||
for (auto it = alreadyLoadedImages.begin(); it != alreadyLoadedImages.end();
|
||||
++it) {
|
||||
std::shared_ptr<SFMLTextureWrapper> image = (it->second).lock();
|
||||
if (image != std::shared_ptr<SFMLTextureWrapper>())
|
||||
unloadingPreventer.push_back(image);
|
||||
}
|
||||
}
|
||||
|
||||
void ImageManager::EnableImagesUnloading() {
|
||||
preventUnloading = false;
|
||||
unloadingPreventer
|
||||
.clear(); // Images which are not used anymore will thus be destroyed (As
|
||||
// no shared pointer will be pointing to them).
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace gd
|
||||
|
||||
SFMLTextureWrapper::SFMLTextureWrapper(const sf::Texture& texture_)
|
||||
: texture(texture_), image(texture.copyToImage()) {}
|
||||
|
||||
SFMLTextureWrapper::SFMLTextureWrapper() {}
|
||||
|
||||
SFMLTextureWrapper::~SFMLTextureWrapper() {}
|
||||
|
||||
OpenGLTextureWrapper::OpenGLTextureWrapper(
|
||||
std::shared_ptr<SFMLTextureWrapper> sfmlTexture_) {
|
||||
sfmlTexture = sfmlTexture_;
|
||||
|
||||
#if !defined(ANDROID) // TODO: OpenGL
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sfmlTexture->image.getSize().x,
|
||||
// sfmlTexture->image.getSize().y, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
// sfmlTexture->image.getPixelsPtr()); glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(
|
||||
GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
#endif
|
||||
}
|
||||
|
||||
OpenGLTextureWrapper::~OpenGLTextureWrapper() {
|
||||
#if !defined(ANDROID) // TODO: OpenGL
|
||||
glDeleteTextures(1, &texture);
|
||||
#endif
|
||||
};
|
@@ -1,185 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef ImageManager_H
|
||||
#define ImageManager_H
|
||||
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include <SFML/OpenGL.hpp>
|
||||
#include <SFML/System.hpp>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class ResourcesManager;
|
||||
}
|
||||
class OpenGLTextureWrapper;
|
||||
class SFMLTextureWrapper;
|
||||
#undef LoadImage // thx windows.h
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Manage images for the IDE as well as at runtime for GD C++ Platform,
|
||||
* providing an easy way to get SFML images or OpenGL textures.
|
||||
*
|
||||
* Image manager is used by objects to obtain their images from the image name.
|
||||
*
|
||||
* Images are loaded dynamically when necessary, and are unloaded if there is no
|
||||
* more shared_ptr pointing on an image.
|
||||
*
|
||||
* You should in particular be interested by gd::ImageManager::GetOpenGLTexture
|
||||
* and gd::ImageManager::GetSFMLTexture.
|
||||
*
|
||||
* \see SFMLTextureWrapper
|
||||
* \see OpenGLTextureWrapper
|
||||
*
|
||||
* \ingroup ResourcesManagement
|
||||
*/
|
||||
class GD_CORE_API ImageManager {
|
||||
public:
|
||||
ImageManager();
|
||||
virtual ~ImageManager(){};
|
||||
|
||||
/**
|
||||
* \brief Get a shared pointer to an OpenGL texture. The shared pointer must
|
||||
* be kept alive as long as the texture is used.
|
||||
*/
|
||||
std::shared_ptr<OpenGLTextureWrapper> GetOpenGLTexture(
|
||||
const gd::String& name) const;
|
||||
|
||||
/**
|
||||
* \brief Get a shared pointer to a SFML texture. The shared pointer must be
|
||||
* kept alive as long as the texture is used.
|
||||
*
|
||||
* For example, if the texture is used in an object, you should store the
|
||||
* shared pointer in a member to make sure the texture is available as long as
|
||||
* the object is alive.
|
||||
*/
|
||||
std::shared_ptr<SFMLTextureWrapper> GetSFMLTexture(
|
||||
const gd::String& name) const;
|
||||
|
||||
/**
|
||||
* \brief Set the gd::ResourcesManager used by the ImageManager.
|
||||
*/
|
||||
void SetResourcesManager(gd::ResourcesManager* resourcesManager_) {
|
||||
resourcesManager = resourcesManager_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Load all images of the project which are flagged as alwaysLoaded.
|
||||
* \see ImageResource
|
||||
*/
|
||||
void LoadPermanentImages();
|
||||
|
||||
/**
|
||||
* \brief Check if a SFML texture with the specified name is available and
|
||||
* loaded in memory. \return true if the texture called \a name if available
|
||||
* and loaded in memory.
|
||||
*/
|
||||
bool HasLoadedSFMLTexture(const gd::String& name) const;
|
||||
|
||||
/**
|
||||
* \brief Add the SFMLTextureWrapper to loaded images ( so that it can be
|
||||
* accessed thanks to ImageManager::GetSFMLTexture ) with the specified name
|
||||
* and mark it as permanently loaded ( so that is is unloaded only when the
|
||||
* layout is unloaded ).
|
||||
*/
|
||||
void SetSFMLTextureAsPermanentlyLoaded(
|
||||
const gd::String& name,
|
||||
std::shared_ptr<SFMLTextureWrapper>& texture) const;
|
||||
|
||||
/**
|
||||
* \brief Reload a single image from the game resources
|
||||
*/
|
||||
void ReloadImage(const gd::String& name) const;
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* \brief When called, images won't be unloaded from memory until
|
||||
* EnableImagesUnloading is called. Can be used when reloading a layout so as
|
||||
* to prevent images from being unloaded and then immediately reloaded.
|
||||
*/
|
||||
void PreventImagesUnloading();
|
||||
|
||||
/**
|
||||
* \brief Enable again unused images to be unloaded from memory.
|
||||
*/
|
||||
void EnableImagesUnloading();
|
||||
#endif
|
||||
|
||||
private:
|
||||
mutable std::map<gd::String, std::weak_ptr<SFMLTextureWrapper> >
|
||||
alreadyLoadedImages; ///< Reference all images loaded in memory.
|
||||
mutable std::map<gd::String, std::shared_ptr<SFMLTextureWrapper> >
|
||||
permanentlyLoadedImages; ///< Contains (smart) pointers to images which
|
||||
///< should stay loaded even if they are not
|
||||
///< (currently) used.
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
|
||||
/** This list is filled, when PreventImagesUnloading is called, with images
|
||||
* already loaded in memory ( and any image loaded after the call to
|
||||
* PreventImagesUnloading ). It will thus prevent these images from being
|
||||
* unloaded. This list is destroyed when EnableImagesUnloading is called.
|
||||
*
|
||||
* \see PreventImagesUnloading
|
||||
* \see EnableImagesUnloading
|
||||
*/
|
||||
mutable std::vector<std::shared_ptr<SFMLTextureWrapper> > unloadingPreventer;
|
||||
bool preventUnloading; ///< True if no images must be currently unloaded.
|
||||
#endif
|
||||
|
||||
mutable std::map<gd::String, std::weak_ptr<OpenGLTextureWrapper> >
|
||||
alreadyLoadedOpenGLTextures; ///< Reference all OpenGL textures loaded in
|
||||
///< memory.
|
||||
|
||||
mutable std::shared_ptr<SFMLTextureWrapper> badTexture;
|
||||
mutable std::shared_ptr<OpenGLTextureWrapper> badOpenGLTexture;
|
||||
|
||||
gd::ResourcesManager* resourcesManager;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
/**
|
||||
* \brief Class wrapping an SFML texture.
|
||||
*
|
||||
* \see gd::ImageManager
|
||||
* \ingroup ResourcesManagement
|
||||
*/
|
||||
class GD_CORE_API SFMLTextureWrapper {
|
||||
public:
|
||||
SFMLTextureWrapper(const sf::Texture& texture);
|
||||
SFMLTextureWrapper();
|
||||
~SFMLTextureWrapper();
|
||||
|
||||
sf::Texture texture;
|
||||
sf::Image image; ///< Associated sfml image, used for pixel perfect collision
|
||||
///< for example. If you update the image, call
|
||||
///< LoadFromImage on texture to update it also.
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Class wrapping an OpenGL texture.
|
||||
*
|
||||
* \see gd::ImageManager
|
||||
* \ingroup ResourcesManagement
|
||||
*/
|
||||
class GD_CORE_API OpenGLTextureWrapper {
|
||||
public:
|
||||
OpenGLTextureWrapper(std::shared_ptr<SFMLTextureWrapper> sfmlTexture_);
|
||||
OpenGLTextureWrapper() : texture(0){};
|
||||
~OpenGLTextureWrapper();
|
||||
inline GLuint GetOpenGLTexture() const { return texture; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<SFMLTextureWrapper> sfmlTexture;
|
||||
GLuint texture;
|
||||
};
|
||||
|
||||
#endif // ImageManager_H
|
@@ -70,12 +70,6 @@ class GD_CORE_API NamedPropertyDescriptor : public PropertyDescriptor {
|
||||
virtual void UnserializeValuesFrom(const SerializerElement& element);
|
||||
///@}
|
||||
|
||||
/**
|
||||
* Return a PropertyDescriptor from this NamedPropertyDescriptor,
|
||||
* slicing the name.
|
||||
*/
|
||||
PropertyDescriptor ToPropertyDescriptor() { return PropertyDescriptor(*this); }
|
||||
|
||||
private:
|
||||
gd::String name; ///< The name of the property.
|
||||
};
|
||||
|
@@ -26,7 +26,6 @@
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDCore/Project/ExternalEvents.h"
|
||||
#include "GDCore/Project/ExternalLayout.h"
|
||||
#include "GDCore/Project/ImageManager.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/ObjectGroupsContainer.h"
|
||||
@@ -64,26 +63,20 @@ Project::Project()
|
||||
minFPS(20),
|
||||
verticalSync(false),
|
||||
scaleMode("linear"),
|
||||
pixelsRounding(false),
|
||||
adaptGameResolutionAtRuntime(true),
|
||||
sizeOnStartupMode("adaptWidth"),
|
||||
projectUuid(""),
|
||||
useDeprecatedZeroAsDefaultZOrder(false),
|
||||
imageManager(std::make_shared<ImageManager>())
|
||||
useDeprecatedZeroAsDefaultZOrder(false)
|
||||
#if defined(GD_IDE_ONLY)
|
||||
,
|
||||
useExternalSourceFiles(false),
|
||||
currentPlatform(NULL),
|
||||
gdMajorVersion(gd::VersionWrapper::Major()),
|
||||
gdMinorVersion(gd::VersionWrapper::Minor()),
|
||||
gdBuildVersion(gd::VersionWrapper::Build()),
|
||||
dirty(false)
|
||||
gdBuildVersion(gd::VersionWrapper::Build())
|
||||
#endif
|
||||
{
|
||||
imageManager->SetResourcesManager(&resourcesManager);
|
||||
|
||||
#if !defined(GD_IDE_ONLY)
|
||||
platforms.push_back(&CppPlatform::Get());
|
||||
#endif
|
||||
}
|
||||
|
||||
Project::~Project() {}
|
||||
@@ -536,6 +529,7 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
SetVerticalSyncActivatedByDefault(
|
||||
propElement.GetChild("verticalSync").GetValue().GetBool());
|
||||
SetScaleMode(propElement.GetStringAttribute("scaleMode", "linear"));
|
||||
SetPixelsRounding(propElement.GetBoolAttribute("pixelsRounding", false));
|
||||
SetAdaptGameResolutionAtRuntime(
|
||||
propElement.GetBoolAttribute("adaptGameResolutionAtRuntime", false));
|
||||
SetSizeOnStartupMode(propElement.GetStringAttribute("sizeOnStartupMode", ""));
|
||||
@@ -748,6 +742,7 @@ void Project::SerializeTo(SerializerElement& element) const {
|
||||
propElement.AddChild("verticalSync")
|
||||
.SetValue(IsVerticalSynchronizationEnabledByDefault());
|
||||
propElement.SetAttribute("scaleMode", scaleMode);
|
||||
propElement.SetAttribute("pixelsRounding", pixelsRounding);
|
||||
propElement.SetAttribute("adaptGameResolutionAtRuntime",
|
||||
adaptGameResolutionAtRuntime);
|
||||
propElement.SetAttribute("sizeOnStartupMode", sizeOnStartupMode);
|
||||
@@ -823,10 +818,6 @@ void Project::SerializeTo(SerializerElement& element) const {
|
||||
for (std::size_t i = 0; i < externalSourceFiles.size(); ++i)
|
||||
externalSourceFiles[i]->SerializeTo(
|
||||
externalSourceFilesElement.AddChild("sourceFile"));
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
dirty = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Project::ValidateName(const gd::String& name) {
|
||||
@@ -943,6 +934,7 @@ void Project::Init(const gd::Project& game) {
|
||||
minFPS = game.minFPS;
|
||||
verticalSync = game.verticalSync;
|
||||
scaleMode = game.scaleMode;
|
||||
pixelsRounding = game.pixelsRounding;
|
||||
adaptGameResolutionAtRuntime = game.adaptGameResolutionAtRuntime;
|
||||
sizeOnStartupMode = game.sizeOnStartupMode;
|
||||
projectUuid = game.projectUuid;
|
||||
@@ -969,9 +961,7 @@ void Project::Init(const gd::Project& game) {
|
||||
platforms = game.platforms;
|
||||
|
||||
resourcesManager = game.resourcesManager;
|
||||
imageManager = std::make_shared<ImageManager>(*game.imageManager);
|
||||
imageManager->SetResourcesManager(&resourcesManager);
|
||||
|
||||
|
||||
initialObjects = gd::Clone(game.initialObjects);
|
||||
|
||||
scenes = gd::Clone(game.scenes);
|
||||
@@ -993,7 +983,6 @@ void Project::Init(const gd::Project& game) {
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
projectFile = game.GetProjectFile();
|
||||
imagesChanged = game.imagesChanged;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@@ -28,7 +28,6 @@ class Object;
|
||||
class VariablesContainer;
|
||||
class ArbitraryResourceWorker;
|
||||
class SourceFile;
|
||||
class ImageManager;
|
||||
class Behavior;
|
||||
class BehaviorsSharedData;
|
||||
class BaseEvent;
|
||||
@@ -277,6 +276,19 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
*/
|
||||
void SetScaleMode(const gd::String& scaleMode_) { scaleMode = scaleMode_; }
|
||||
|
||||
/**
|
||||
* Return true if pixels rounding option is enabled.
|
||||
*/
|
||||
bool GetPixelsRounding() const {
|
||||
return pixelsRounding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set pixels rounding option to true or false.
|
||||
*/
|
||||
void SetPixelsRounding(bool enable) { pixelsRounding = enable; }
|
||||
|
||||
|
||||
/**
|
||||
* \brief Return if the project should set 0 as Z-order for objects created
|
||||
* from events (which is deprecated) - instead of the highest Z order that was
|
||||
@@ -498,19 +510,6 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
*/
|
||||
void SerializeTo(SerializerElement& element) const;
|
||||
|
||||
/**
|
||||
* \brief Return true if the project is marked as being modified (The IDE or
|
||||
* application using the project should ask to save the project if the project
|
||||
* is closed).
|
||||
*/
|
||||
bool IsDirty() { return dirty; }
|
||||
|
||||
/**
|
||||
* \brief Mark the project as being modified (The IDE or application
|
||||
* using the project should ask to save the project if the project is closed).
|
||||
*/
|
||||
void SetDirty(bool enable = true) { dirty = enable; }
|
||||
|
||||
/**
|
||||
* Get the major version of GDevelop used to save the project.
|
||||
*/
|
||||
@@ -792,28 +791,6 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
*/
|
||||
ResourcesManager& GetResourcesManager() { return resourcesManager; }
|
||||
|
||||
/**
|
||||
* \brief Provide access to the ImageManager allowing to load SFML or OpenGL
|
||||
* textures for the IDE ( or at runtime for the GD C++ Platform ).
|
||||
*/
|
||||
const std::shared_ptr<gd::ImageManager>& GetImageManager() const {
|
||||
return imageManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Provide access to the ImageManager allowing to load SFML or OpenGL
|
||||
* textures for the IDE ( or at runtime for the GD C++ Platform ).
|
||||
*/
|
||||
std::shared_ptr<gd::ImageManager>& GetImageManager() { return imageManager; }
|
||||
|
||||
/**
|
||||
* \brief Provide access to the ImageManager allowing to load SFML or OpenGL
|
||||
* textures for the IDE ( or at runtime for the GD C++ Platform ).
|
||||
*/
|
||||
void SetImageManager(std::shared_ptr<gd::ImageManager> imageManager_) {
|
||||
imageManager = imageManager_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Called ( e.g. during compilation ) so as to inventory internal
|
||||
* resources, sometimes update their filename or any other work or resources.
|
||||
@@ -910,12 +887,6 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
#endif
|
||||
///@}
|
||||
|
||||
// TODO: Put this in private part
|
||||
#if defined(GD_IDE_ONLY)
|
||||
std::vector<gd::String> imagesChanged; ///< Images that have been changed and
|
||||
///< which have to be reloaded
|
||||
#endif
|
||||
|
||||
private:
|
||||
/**
|
||||
* Initialize from another game. Used by copy-ctor and assign-op.
|
||||
@@ -932,6 +903,8 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
///< are below this number )
|
||||
bool verticalSync; ///< If true, must activate vertical synchronization.
|
||||
gd::String scaleMode;
|
||||
bool pixelsRounding; ///< If true, the rendering should stop pixel interpolation
|
||||
///< of rendered objects.
|
||||
bool adaptGameResolutionAtRuntime; ///< Should the game resolution be adapted
|
||||
///< to the window size at runtime
|
||||
gd::String
|
||||
@@ -954,9 +927,6 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
#endif
|
||||
gd::ResourcesManager
|
||||
resourcesManager; ///< Contains all resources used by the project
|
||||
std::shared_ptr<gd::ImageManager>
|
||||
imageManager; ///< Image manager is accessed thanks to a (smart) ptr as
|
||||
///< it can be shared with GD C++ Platform projects.
|
||||
std::vector<gd::Platform*>
|
||||
platforms; ///< Pointers to the platforms this project supports.
|
||||
gd::String firstLayout;
|
||||
@@ -987,7 +957,6 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
///< time the project was saved.
|
||||
mutable unsigned int gdBuildVersion; ///< The GD build version used the last
|
||||
///< time the project was saved.
|
||||
mutable bool dirty; ///< True to flag the project as being modified.
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@@ -76,6 +76,14 @@ class GD_CORE_API PropertyDescriptor {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set and replace the additional information for the property.
|
||||
*/
|
||||
PropertyDescriptor& SetExtraInfo(const std::vector<gd::String>& info) {
|
||||
extraInformation = info;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Add an information about the property.
|
||||
* \note The information are arbitrary and are interpreted by the class
|
||||
@@ -92,9 +100,14 @@ class GD_CORE_API PropertyDescriptor {
|
||||
const gd::String& GetType() const { return type; }
|
||||
const gd::String& GetLabel() const { return label; }
|
||||
const gd::String& GetDescription() const { return description; }
|
||||
|
||||
const std::vector<gd::String>& GetExtraInfo() const {
|
||||
return extraInformation;
|
||||
}
|
||||
|
||||
std::vector<gd::String>& GetExtraInfo() {
|
||||
return extraInformation;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set if the property should be shown or hidden in the editor.
|
||||
|
@@ -1,108 +0,0 @@
|
||||
#include "GDCore/Project/ResourcesLoader.h"
|
||||
#include <SFML/Audio.hpp>
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/FileStream.h"
|
||||
#undef LoadImage // Undef a macro from windows.h
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace gd {
|
||||
|
||||
ResourcesLoader *ResourcesLoader::_singleton = NULL;
|
||||
|
||||
void ResourcesLoader::LoadSFMLImage(const gd::String &filename,
|
||||
sf::Image &image) {
|
||||
gd::SFMLFileStream stream;
|
||||
if (!stream.open(filename) || !image.loadFromStream(stream))
|
||||
cout << "Failed to load a SFML image: " << filename << endl;
|
||||
}
|
||||
|
||||
sf::Texture ResourcesLoader::LoadSFMLTexture(const gd::String &filename) {
|
||||
sf::Texture texture;
|
||||
LoadSFMLTexture(filename, texture);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
void ResourcesLoader::LoadSFMLTexture(const gd::String &filename,
|
||||
sf::Texture &texture) {
|
||||
gd::SFMLFileStream stream;
|
||||
if (!stream.open(filename) || !texture.loadFromStream(stream))
|
||||
cout << "Failed to load a SFML texture: " << filename << endl;
|
||||
}
|
||||
|
||||
std::pair<sf::Font *, StreamHolder *> ResourcesLoader::LoadFont(
|
||||
const gd::String &filename) {
|
||||
sf::Font *font = new sf::Font();
|
||||
StreamHolder *streamHolder = new StreamHolder();
|
||||
|
||||
if (!streamHolder->stream.open(filename) ||
|
||||
!font->loadFromStream(streamHolder->stream)) {
|
||||
cout << "Failed to load a font from a file: " << filename << endl;
|
||||
delete font;
|
||||
delete streamHolder;
|
||||
return std::make_pair((sf::Font *)nullptr, (StreamHolder *)nullptr);
|
||||
}
|
||||
|
||||
return std::make_pair(font, streamHolder);
|
||||
}
|
||||
|
||||
sf::SoundBuffer ResourcesLoader::LoadSoundBuffer(const gd::String &filename) {
|
||||
sf::SoundBuffer sbuffer;
|
||||
gd::SFMLFileStream stream;
|
||||
if (!stream.open(filename) || !sbuffer.loadFromStream(stream))
|
||||
cout << "Failed to load a sound buffer: " << filename << endl;
|
||||
|
||||
return sbuffer;
|
||||
}
|
||||
|
||||
gd::String ResourcesLoader::LoadPlainText(const gd::String &filename) {
|
||||
gd::String text;
|
||||
gd::FileStream file(filename, ios::in);
|
||||
|
||||
if (!file.fail()) {
|
||||
std::string ligne;
|
||||
while (getline(file, ligne)) text += gd::String::FromUTF8(ligne) + "\n";
|
||||
|
||||
file.close();
|
||||
} else
|
||||
cout << "Failed to read a file: " << filename << endl;
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a binary text file
|
||||
*/
|
||||
char *ResourcesLoader::LoadBinaryFile(const gd::String &filename) {
|
||||
gd::FileStream file(filename, ios::in | ios::binary | ios::ate);
|
||||
if (file.is_open()) {
|
||||
iostream::pos_type size = file.tellg();
|
||||
char *memblock = new char[size];
|
||||
file.seekg(0, ios::beg);
|
||||
file.read(memblock, size);
|
||||
file.close();
|
||||
|
||||
return memblock;
|
||||
}
|
||||
|
||||
cout << "Binary file " << filename << " can't be loaded into memory " << endl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
long int ResourcesLoader::GetBinaryFileSize(const gd::String &filename) {
|
||||
gd::FileStream file(filename, ios::in | ios::binary | ios::ate);
|
||||
if (file.is_open()) {
|
||||
return file.tellg();
|
||||
}
|
||||
|
||||
std::cout << "Binary file " << filename << " cannot be read. " << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace gd
|
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef RESSOURCESLOADER_H
|
||||
#define RESSOURCESLOADER_H
|
||||
#include <SFML/Audio.hpp>
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/FileStream.h"
|
||||
#undef LoadImage // Undef macro from windows.h
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief A class holding a buffer and/or a file stream (useful for SFML classes
|
||||
* that needs their buffer/stream continuously opened)
|
||||
*/
|
||||
struct StreamHolder {
|
||||
StreamHolder() : buffer(nullptr), stream() {}
|
||||
~StreamHolder() {
|
||||
if (buffer) delete buffer;
|
||||
}
|
||||
|
||||
char *buffer;
|
||||
gd::SFMLFileStream stream;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Class used by games to load resources from files: this is purely an
|
||||
* abstraction to most SFML loadFrom* functions.
|
||||
*
|
||||
* This class is replaced in GDCpp by an equivalent that can load also from
|
||||
* memory.
|
||||
*
|
||||
* \ingroup ResourcesManagement
|
||||
*/
|
||||
class GD_CORE_API ResourcesLoader {
|
||||
public:
|
||||
void LoadSFMLImage(const gd::String &filename, sf::Image &image);
|
||||
|
||||
/**
|
||||
* Load a SFML texture.
|
||||
*/
|
||||
sf::Texture LoadSFMLTexture(const gd::String &filename);
|
||||
void LoadSFMLTexture(const gd::String &filename, sf::Texture &texture);
|
||||
|
||||
/**
|
||||
* Load a SFML Font.
|
||||
* \warning The function calling LoadFont is the owner of the returned font
|
||||
* and buffer (if any): Don't forget to delete them after use.
|
||||
*
|
||||
* \return A pair containing the loaded font, or NULL if loading failed, and
|
||||
* the buffer that need to be kept alive while the font is used (can be NULL
|
||||
* if the font was loaded from a file).
|
||||
*/
|
||||
std::pair<sf::Font *, StreamHolder *> LoadFont(const gd::String &filename);
|
||||
|
||||
/**
|
||||
* Load a SFML Sound Buffer
|
||||
*/
|
||||
sf::SoundBuffer LoadSoundBuffer(const gd::String &filename);
|
||||
|
||||
/**
|
||||
* Load a plain text file
|
||||
*/
|
||||
gd::String LoadPlainText(const gd::String &filename);
|
||||
|
||||
/**
|
||||
* Get a buffer for file.
|
||||
* Be careful, the buffer will be invalided by any subsequent call to
|
||||
* Load[Something]. Make a copy of the buffer if you want it to stay alive
|
||||
* longer.
|
||||
*/
|
||||
char *LoadBinaryFile(const gd::String &filename);
|
||||
|
||||
/**
|
||||
* Get the size of a file
|
||||
*/
|
||||
long int GetBinaryFileSize(const gd::String &filename);
|
||||
|
||||
static ResourcesLoader *Get() {
|
||||
if (NULL == _singleton) {
|
||||
_singleton = new ResourcesLoader;
|
||||
}
|
||||
|
||||
return (static_cast<ResourcesLoader *>(_singleton));
|
||||
}
|
||||
|
||||
static void DestroySingleton() {
|
||||
if (NULL != _singleton) {
|
||||
delete _singleton;
|
||||
_singleton = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ResourcesLoader(){};
|
||||
virtual ~ResourcesLoader(){};
|
||||
|
||||
static ResourcesLoader *_singleton;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
#endif // RESSOURCESLOADER_H
|
@@ -7,7 +7,6 @@
|
||||
#include "GDCore/Project/Variable.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <cmath>
|
||||
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/String.h"
|
||||
@@ -92,7 +91,7 @@ double Variable::GetValue() const {
|
||||
if (type == Type::Number) {
|
||||
return value;
|
||||
} else if (type == Type::String) {
|
||||
double retVal = str.To<double>();
|
||||
double retVal = str.empty() ? 0.0 : str.To<double>();
|
||||
if(std::isnan(retVal)) retVal = 0.0;
|
||||
return retVal;
|
||||
} else if (type == Type::Boolean) {
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
@@ -96,6 +97,8 @@ class GD_CORE_API Variable {
|
||||
*/
|
||||
void SetValue(double val) {
|
||||
value = val;
|
||||
// NaN values are not supported by GDevelop nor the serializer.
|
||||
if(std::isnan(value)) value = 0.0;
|
||||
type = Type::Number;
|
||||
}
|
||||
|
||||
|
@@ -9,12 +9,11 @@
|
||||
/** @file
|
||||
* Provide a way to mark strings to be translated.
|
||||
*
|
||||
* Strings to be translated in GDevelop Core codebase (and GDCpp),
|
||||
* Strings to be translated in GDevelop Core codebase
|
||||
* are marked with the underscore macro, for example: _("Hello World").
|
||||
*
|
||||
* The macro is then defined to be using the translation function
|
||||
* of the underlying platform (Emscripten for GDevelop 5,
|
||||
* no translation for GDCpp Runtime).
|
||||
* of the underlying platform (Emscripten for GDevelop 5).
|
||||
*/
|
||||
|
||||
#if defined(EMSCRIPTEN)
|
||||
@@ -33,7 +32,7 @@ gd::String GetTranslation(const char* str);
|
||||
#define _(s) gd::GetTranslation(u8##s)
|
||||
|
||||
#else
|
||||
// When compiling without Emscripten (typically for GDC++ Runtime),
|
||||
// When compiling without Emscripten,
|
||||
// just return an untranslated gd::String.
|
||||
|
||||
// Create a new macro to return UTF8 gd::String from a translation
|
||||
|
@@ -9,19 +9,23 @@
|
||||
namespace gd {
|
||||
|
||||
void GD_CORE_API LogWarning(const gd::String& msg) {
|
||||
std::cout << "WARNING: " << msg;
|
||||
std::cout << "WARNING: " << msg << std::endl;
|
||||
}
|
||||
|
||||
void GD_CORE_API LogError(const gd::String& msg) {
|
||||
std::cout << "ERROR: " << msg;
|
||||
std::cout << "ERROR: " << msg << std::endl;
|
||||
}
|
||||
|
||||
void GD_CORE_API LogFatalError(const gd::String& msg) {
|
||||
std::cout << "FATAL ERROR: " << msg << std::endl;
|
||||
}
|
||||
|
||||
void GD_CORE_API LogMessage(const gd::String& msg) {
|
||||
std::cout << "MESSAGE: " << msg;
|
||||
std::cout << "MESSAGE: " << msg << std::endl;
|
||||
}
|
||||
|
||||
void GD_CORE_API LogStatus(const gd::String& msg) {
|
||||
std::cout << "STATUS: " << msg;
|
||||
std::cout << "STATUS: " << msg << std::endl;
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -22,11 +22,18 @@ void GD_CORE_API LogWarning(const gd::String& msg);
|
||||
*/
|
||||
void GD_CORE_API LogError(const gd::String& msg);
|
||||
|
||||
/**
|
||||
* \brief Standard function that should be used when emitting an error to be
|
||||
* displayed to the user before a crash/undefined behavior.
|
||||
*/
|
||||
void GD_CORE_API LogFatalError(const gd::String& msg);
|
||||
|
||||
/**
|
||||
* \brief Standard function that should be used when emitting a message to be
|
||||
* displayed to the user.
|
||||
*/
|
||||
void GD_CORE_API LogMessage(const gd::String& msg);
|
||||
|
||||
/**
|
||||
* \brief Standard function that should be used when emitting a status message
|
||||
* to be displayed to the user.
|
||||
|
8
Core/GDCore/Tools/VersionPriv.h
Normal file
8
Core/GDCore/Tools/VersionPriv.h
Normal file
@@ -0,0 +1,8 @@
|
||||
// Deprecated version number that was used for GDevelop 4, but still
|
||||
// used to version the project files.
|
||||
// Might be a good idea to refactor this at some point to make it
|
||||
// clearer this is used for the versioning of the project files.
|
||||
#define GD_VERSION_STRING "4.0.99-0-release"
|
||||
#define GD_VERSION_RC 4,0,99,0-0-release
|
||||
#define GD_VERSION_RC_STRING "4, 0, 99, 0-0-release\0"
|
||||
#define GD_DATE_STRING __DATE__
|
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "GDCore/Tools/VersionWrapper.h"
|
||||
#include "GDCore/Tools/VersionPriv.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
@@ -35,13 +36,6 @@ gd::String VersionWrapper::Year() {
|
||||
gd::String VersionWrapper::Status() {
|
||||
return Revision() == 0 ? "Release" : "Dev";
|
||||
}
|
||||
bool VersionWrapper::CompiledForEdittime() {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool VersionWrapper::IsOlder(int major,
|
||||
int minor,
|
||||
|
@@ -7,8 +7,6 @@
|
||||
#define GDCORE_VERSIONWRAPPER_H
|
||||
#include "GDCore/String.h"
|
||||
|
||||
#include "GDCore/Tools/VersionPriv.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
@@ -48,11 +46,6 @@ class GD_CORE_API VersionWrapper {
|
||||
*/
|
||||
static gd::String Status();
|
||||
|
||||
/**
|
||||
* \brief Return true if GDCpp is compiled with edittime support.
|
||||
*/
|
||||
static bool CompiledForEdittime();
|
||||
|
||||
/**
|
||||
* \brief Get Year of the release
|
||||
*/
|
||||
|
@@ -1,13 +1,12 @@
|
||||
# GDevelop Architecture Overview
|
||||
|
||||
GDevelop is architectured around a `Core` library, platforms (`GDJS`, `GDCpp`) and extensions (`Extensions` folder). The editor (`newIDE` folder) is using all of these libraries. This is a recap table of the main folders:
|
||||
GDevelop is architectured around a `Core` library, the game engine (`GDJS`) and extensions (`Extensions` folder). The editor (`newIDE` folder) is using all of these libraries. This is a recap table of the main folders:
|
||||
|
||||
| Directory | ℹ️ Description |
|
||||
| ------------- | ----------------------------------------------------------------------------------------------------- |
|
||||
| `Core` | GDevelop core library, containing common tools to implement the IDE and work with GDevelop games. |
|
||||
| `GDCpp` | The C++ game engine, used to build native games (_not used in GDevelop 5_). |
|
||||
| `GDJS` | The game engine, written in TypeScript, using PixiJS (WebGL), powering all GDevelop games. |
|
||||
| `GDevelop.js` | Bindings of `Core`/`GDCpp`/`GDJS` and `Extensions` to JavaScript (with WebAssembly), used by the IDE. |
|
||||
| `GDevelop.js` | Bindings of `Core`, `GDJS` and `Extensions` to JavaScript (with WebAssembly), used by the IDE. |
|
||||
| `newIDE` | The game editor, written in JavaScript with React, Electron and PixiJS. |
|
||||
| `Extensions` | Extensions for the game engine, providing objects, behaviors, events and new features. |
|
||||
|
||||
@@ -17,11 +16,11 @@ The rest of this page is an introduction to the main concepts of GDevelop archit
|
||||
|
||||
**IDE** stands for "Integrated Development Environment". A synonym for it is also simply "editor". In GDevelop, the software itself, that is used to create games and running as an app or a web-app, is called the "GDevelop Editor" or the "GDevelop IDE"
|
||||
|
||||
> The term "IDE" is also used in some folders. When you browse `Core`, `GDCpp` or `GDJS` subfolders, some folders are called `IDE`. They contain classes and tools that are **only useful for the editor** (they are not per se mandatory to describe the structure of a game).
|
||||
> The term "IDE" is also used in some folders. When you browse `Core` or `GDJS` subfolders, some folders are called `IDE`. They contain classes and tools that are **only useful for the editor** (they are not per se mandatory to describe the structure of a game).
|
||||
|
||||
**Runtime** is a word used to describe classes, tools and source files being used during a game. This could also be called "in-game" or a "game engine".
|
||||
|
||||
> When you browse `GDCpp` or `GDJS` subfolders, you can find folders called `Runtime`. They contain the **game engine** of GDevelop.
|
||||
> When you browse `GDJS` subfolder, you can find a folder called `Runtime`. It's the **game engine** of GDevelop.
|
||||
|
||||
Extensions do have the same distinction between the "**IDE**" part and the "**Runtime**" part. For example, most extensions have:
|
||||
|
||||
@@ -79,7 +78,7 @@ You're welcome to do so! Please get in touch :)
|
||||
The idea of the GDevelop editor and game engine is to have a lean game engine, supporting almost nothing. Then, one can add "mods", "plugins", "modules" for GDevelop. We chose to call them "**Extensions**" in GDevelop.
|
||||
|
||||
- `GDevelop/Core/GDCore/Extensions` is the **declaration** of default (we say "builtin") extensions, that are available for any game and are "mandatory". They are called Extensions but they could be named "Extensions that will always be in your game". In programming languages, this is called a "[Standard Library](https://en.wikipedia.org/wiki/Standard_library)" (but don't get too distracted by this naming).
|
||||
- `GDevelop/GDJS/GDJS/Extensions/` and `GDevelop/GDCpp/GDCpp/Extensions/` are reusing these **declarations** and **adding** their own declarations. Mainly, they are setting the name of the functions to be called (either in TypeScript or in C++) for each action, condition or expression.
|
||||
- `GDevelop/GDJS/GDJS/Extensions/` is reusing these **declarations** and **adding** their own declarations. Mainly, they are setting the name of the functions to be called (either in TypeScript or in C++) for each action, condition or expression.
|
||||
- `GDevelop/Extensions/` is the folder for the "mods"/"plugins" for GDevelop - the ones that are not mandatory. They are not part of GDCore - they work on their own.
|
||||
|
||||
> In theory, all extensions could be moved to `GDevelop/Extensions/`. In practice, it's more pragmatic to have a set of "built-in" extensions with basic features.
|
||||
|
@@ -12,8 +12,76 @@
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
#include "catch.hpp"
|
||||
|
||||
void SetupProjectWithDummyPlatform(gd::Project &project,
|
||||
gd::Platform &platform) {
|
||||
class BehaviorWithRequiredBehaviorProperty : public gd::Behavior {
|
||||
public:
|
||||
BehaviorWithRequiredBehaviorProperty() {};
|
||||
virtual ~BehaviorWithRequiredBehaviorProperty(){};
|
||||
virtual Behavior* Clone() const override {
|
||||
return new BehaviorWithRequiredBehaviorProperty(*this);
|
||||
}
|
||||
|
||||
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties(
|
||||
const gd::SerializerElement& behaviorContent) const override {
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties;
|
||||
properties["requiredBehaviorProperty"]
|
||||
.SetLabel("A required behavior")
|
||||
.SetValue(behaviorContent.GetStringAttribute("requiredBehaviorProperty"))
|
||||
.SetType("Behavior")
|
||||
.AddExtraInfo("MyExtension::MyBehavior");
|
||||
return properties;
|
||||
}
|
||||
virtual bool UpdateProperty(gd::SerializerElement& behaviorContent,
|
||||
const gd::String& name,
|
||||
const gd::String& value) override {
|
||||
if (name == _("requiredBehaviorProperty")) {
|
||||
behaviorContent.SetAttribute("requiredBehaviorProperty", value);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
virtual void InitializeContent(
|
||||
gd::SerializerElement& behaviorContent) override {
|
||||
behaviorContent.SetAttribute("requiredBehaviorProperty", "");
|
||||
}
|
||||
};
|
||||
|
||||
class BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior
|
||||
: public gd::Behavior {
|
||||
public:
|
||||
BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior() {};
|
||||
virtual ~BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior(){};
|
||||
virtual Behavior* Clone() const override {
|
||||
return new BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior(
|
||||
*this);
|
||||
}
|
||||
|
||||
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties(
|
||||
const gd::SerializerElement& behaviorContent) const override {
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties;
|
||||
properties["requiredBehaviorProperty"]
|
||||
.SetLabel("A required behavior")
|
||||
.SetValue(behaviorContent.GetStringAttribute("requiredBehaviorProperty"))
|
||||
.SetType("Behavior")
|
||||
.AddExtraInfo("MyExtension::BehaviorWithRequiredBehaviorProperty");
|
||||
return properties;
|
||||
}
|
||||
virtual bool UpdateProperty(gd::SerializerElement& behaviorContent,
|
||||
const gd::String& name,
|
||||
const gd::String& value) override {
|
||||
if (name == _("requiredBehaviorProperty")) {
|
||||
behaviorContent.SetAttribute("requiredBehaviorProperty", value);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
virtual void InitializeContent(
|
||||
gd::SerializerElement& behaviorContent) override {
|
||||
behaviorContent.SetAttribute("requiredBehaviorProperty", "");
|
||||
}
|
||||
};
|
||||
|
||||
void SetupProjectWithDummyPlatform(gd::Project& project,
|
||||
gd::Platform& platform) {
|
||||
// Don't show extension loading logs for tests (too verbose).
|
||||
platform.EnableExtensionLoadingLogs(false);
|
||||
|
||||
@@ -85,18 +153,19 @@ void SetupProjectWithDummyPlatform(gd::Project &project,
|
||||
.AddParameter("expression", "", "", true)
|
||||
.SetFunctionName("getNumberWith3Params");
|
||||
extension
|
||||
->AddStrExpression("GetStringWith2ObjectParamAnd2ObjectVarParam",
|
||||
"Get string with twice an object param and an objectvar param",
|
||||
"",
|
||||
"",
|
||||
"")
|
||||
->AddStrExpression(
|
||||
"GetStringWith2ObjectParamAnd2ObjectVarParam",
|
||||
"Get string with twice an object param and an objectvar param",
|
||||
"",
|
||||
"",
|
||||
"")
|
||||
.AddParameter("object", _("Object 1 parameter"))
|
||||
.AddParameter("objectvar", _("Variable for object 1"))
|
||||
.AddParameter("object", _("Object 2 parameter"))
|
||||
.AddParameter("objectvar", _("Variable for object 2"))
|
||||
.SetFunctionName("getStringWith2ObjectParamAnd2ObjectVarParam");
|
||||
|
||||
auto &object = extension->AddObject<gd::Object>(
|
||||
auto& object = extension->AddObject<gd::Object>(
|
||||
"Sprite", "Dummy Sprite", "Dummy sprite object", "");
|
||||
object
|
||||
.AddExpression("GetObjectVariableAsNumber",
|
||||
@@ -140,36 +209,91 @@ void SetupProjectWithDummyPlatform(gd::Project &project,
|
||||
.AddParameter("object", _("Object parameter"))
|
||||
.AddParameter("objectPtr", _("Object parameter"))
|
||||
.SetFunctionName("getObjectStringWith2ObjectParam");
|
||||
auto behavior =
|
||||
extension->AddBehavior("MyBehavior",
|
||||
"Dummy behavior",
|
||||
"MyBehavior",
|
||||
"A dummy behavior for tests",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
gd::make_unique<gd::Behavior>(),
|
||||
gd::make_unique<gd::BehaviorsSharedData>());
|
||||
behavior
|
||||
.AddAction("BehaviorDoSomething",
|
||||
"Do something on behavior",
|
||||
"This does something with the behavior",
|
||||
"Do something with the behavior please",
|
||||
"",
|
||||
"",
|
||||
"")
|
||||
.AddParameter("expression", "Parameter 1 (a number)")
|
||||
.SetFunctionName("behaviorDoSomething");
|
||||
behavior
|
||||
.AddStrExpression("GetBehaviorStringWith1Param",
|
||||
"Get string from behavior with 1 param",
|
||||
"",
|
||||
"",
|
||||
"")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "MyExtension::MyBehavior")
|
||||
.AddParameter("expression", _("Number parameter"))
|
||||
.SetFunctionName("getBehaviorStringWith1Param");
|
||||
|
||||
{
|
||||
auto& behavior =
|
||||
extension->AddBehavior("MyBehavior",
|
||||
"Dummy behavior",
|
||||
"MyBehavior",
|
||||
"A dummy behavior for tests",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
gd::make_unique<gd::Behavior>(),
|
||||
gd::make_unique<gd::BehaviorsSharedData>());
|
||||
behavior
|
||||
.AddAction("BehaviorDoSomething",
|
||||
"Do something on behavior",
|
||||
"This does something with the behavior",
|
||||
"Do something with the behavior please",
|
||||
"",
|
||||
"",
|
||||
"")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "MyExtension::MyBehavior")
|
||||
.AddParameter("expression", "Parameter 1 (a number)")
|
||||
.SetFunctionName("behaviorDoSomething");
|
||||
behavior
|
||||
.AddStrExpression("GetBehaviorStringWith1Param",
|
||||
"Get string from behavior with 1 param",
|
||||
"",
|
||||
"",
|
||||
"")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "MyExtension::MyBehavior")
|
||||
.AddParameter("expression", _("Number parameter"))
|
||||
.SetFunctionName("getBehaviorStringWith1Param");
|
||||
behavior
|
||||
.AddExpression("GetBehaviorNumberWith1Param",
|
||||
"Get number from behavior with 1 param",
|
||||
"",
|
||||
"",
|
||||
"")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "MyExtension::MyBehavior")
|
||||
.AddParameter("expression", _("Number parameter"))
|
||||
.SetFunctionName("getBehaviorNumberWith1Param");
|
||||
}
|
||||
{
|
||||
auto& behavior =
|
||||
extension->AddBehavior("MyOtherBehavior",
|
||||
"Another Dummy behavior",
|
||||
"MyOtherBehavior",
|
||||
"Another dummy behavior for tests",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
gd::make_unique<gd::Behavior>(),
|
||||
gd::make_unique<gd::BehaviorsSharedData>());
|
||||
}
|
||||
|
||||
{
|
||||
auto& behavior = extension->AddBehavior(
|
||||
"BehaviorWithRequiredBehaviorProperty",
|
||||
"BehaviorWithRequiredBehaviorProperty",
|
||||
"BehaviorWithRequiredBehaviorProperty",
|
||||
"A dummy behavior requiring another behavior (MyBehavior)",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
gd::make_unique<BehaviorWithRequiredBehaviorProperty>(),
|
||||
gd::make_unique<gd::BehaviorsSharedData>());
|
||||
}
|
||||
{
|
||||
auto& behavior = extension->AddBehavior(
|
||||
"BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior",
|
||||
"BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior",
|
||||
"BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior",
|
||||
"A dummy behavior requiring another behavior "
|
||||
"(BehaviorWithRequiredBehaviorProperty) that itself requires another "
|
||||
"behavior (MyBehavior)",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
gd::make_unique<
|
||||
BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior>(),
|
||||
gd::make_unique<gd::BehaviorsSharedData>());
|
||||
}
|
||||
|
||||
platform.AddExtension(baseObjectExtension);
|
||||
platform.AddExtension(extension);
|
||||
|
137
Core/tests/EventsBehaviorRenamer.cpp
Normal file
137
Core/tests/EventsBehaviorRenamer.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/IDE/Events/EventsBehaviorRenamer.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "DummyPlatform.h"
|
||||
#include "GDCore/Events/Builtin/StandardEvent.h"
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "catch.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
gd::StandardEvent &EnsureStandardEvent(gd::BaseEvent &baseEvent) {
|
||||
gd::StandardEvent *standardEvent =
|
||||
dynamic_cast<gd::StandardEvent *>(&baseEvent);
|
||||
INFO("The inspected event is "
|
||||
<< (standardEvent ? "a standard event" : "not a standard event"));
|
||||
REQUIRE(standardEvent != nullptr);
|
||||
|
||||
return *standardEvent;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("EventsBehaviorRenamer (expressions)", "[common]") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &layout1 = project.InsertNewLayout("Layout1", 0);
|
||||
|
||||
auto &object1 =
|
||||
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object1", 0);
|
||||
object1.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
|
||||
object1.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior2");
|
||||
|
||||
// Add an event with an expression using the behaviors.
|
||||
gd::StandardEvent event;
|
||||
gd::Instruction instruction;
|
||||
instruction.SetType("MyExtension::DoSomething");
|
||||
instruction.SetParametersCount(1);
|
||||
instruction.SetParameter(
|
||||
0,
|
||||
gd::Expression("4 + "
|
||||
"Object1.MyBehavior::GetBehaviorNumberWith1Param(1) + "
|
||||
"Object1.MyBehavior2::GetBehaviorNumberWith1Param(1)"));
|
||||
event.GetActions().Insert(instruction);
|
||||
layout1.GetEvents().InsertEvent(event);
|
||||
|
||||
// Rename the first behavior.
|
||||
gd::EventsBehaviorRenamer behaviorRenamer(
|
||||
platform, "Object1", "MyBehavior", "MyRenamedBehavior");
|
||||
behaviorRenamer.Launch(layout1.GetEvents(), project, layout1);
|
||||
|
||||
// Verify the expression were updated.
|
||||
REQUIRE(EnsureStandardEvent(layout1.GetEvents().GetEvent(0))
|
||||
.GetActions()
|
||||
.Get(0)
|
||||
.GetParameter(0)
|
||||
.GetPlainString() ==
|
||||
"4 + Object1.MyRenamedBehavior::GetBehaviorNumberWith1Param(1) + "
|
||||
"Object1.MyBehavior2::GetBehaviorNumberWith1Param(1)");
|
||||
}
|
||||
|
||||
TEST_CASE("EventsBehaviorRenamer (instructions)", "[common]") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &layout1 = project.InsertNewLayout("Layout1", 0);
|
||||
|
||||
auto &object1 =
|
||||
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object1", 0);
|
||||
object1.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
|
||||
object1.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior2");
|
||||
|
||||
// Add an action using MyBehavior.
|
||||
{
|
||||
gd::StandardEvent event;
|
||||
gd::Instruction instruction;
|
||||
instruction.SetType("MyExtension::BehaviorDoSomething");
|
||||
instruction.SetParametersCount(3);
|
||||
instruction.SetParameter(0, gd::Expression("Object1"));
|
||||
instruction.SetParameter(1, gd::Expression("MyBehavior"));
|
||||
instruction.SetParameter(2, gd::Expression("123"));
|
||||
event.GetActions().Insert(instruction);
|
||||
layout1.GetEvents().InsertEvent(event);
|
||||
}
|
||||
|
||||
// Add an action using MyBehavior2.
|
||||
{
|
||||
gd::StandardEvent event;
|
||||
gd::Instruction instruction;
|
||||
instruction.SetType("MyExtension::BehaviorDoSomething");
|
||||
instruction.SetParametersCount(3);
|
||||
instruction.SetParameter(0, gd::Expression("Object1"));
|
||||
instruction.SetParameter(1, gd::Expression("MyBehavior2"));
|
||||
instruction.SetParameter(2, gd::Expression("123"));
|
||||
event.GetActions().Insert(instruction);
|
||||
layout1.GetEvents().InsertEvent(event);
|
||||
}
|
||||
|
||||
// Rename MyBehavior.
|
||||
gd::EventsBehaviorRenamer behaviorRenamer(
|
||||
platform, "Object1", "MyBehavior", "MyRenamedBehavior");
|
||||
behaviorRenamer.Launch(layout1.GetEvents(), project, layout1);
|
||||
|
||||
// Ensure the action using MyBehavior has its parameter renamed.
|
||||
REQUIRE(EnsureStandardEvent(layout1.GetEvents().GetEvent(0))
|
||||
.GetActions()
|
||||
.Get(0)
|
||||
.GetParameter(0)
|
||||
.GetPlainString() == "Object1");
|
||||
REQUIRE(EnsureStandardEvent(layout1.GetEvents().GetEvent(0))
|
||||
.GetActions()
|
||||
.Get(0)
|
||||
.GetParameter(1)
|
||||
.GetPlainString() == "MyRenamedBehavior");
|
||||
|
||||
// Ensure MyBehavior2 is left untouched
|
||||
REQUIRE(EnsureStandardEvent(layout1.GetEvents().GetEvent(1))
|
||||
.GetActions()
|
||||
.Get(0)
|
||||
.GetParameter(0)
|
||||
.GetPlainString() == "Object1");
|
||||
REQUIRE(EnsureStandardEvent(layout1.GetEvents().GetEvent(1))
|
||||
.GetActions()
|
||||
.Get(0)
|
||||
.GetParameter(1)
|
||||
.GetPlainString() == "MyBehavior2");
|
||||
}
|
@@ -7,13 +7,19 @@
|
||||
* @file Tests covering project refactoring
|
||||
*/
|
||||
#include "GDCore/IDE/WholeProjectRefactorer.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "DummyPlatform.h"
|
||||
#include "GDCore/Events/Builtin/LinkEvent.h"
|
||||
#include "GDCore/Events/Builtin/StandardEvent.h"
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/IDE/UnfilledRequiredBehaviorPropertyProblem.h"
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDCore/Project/ExternalEvents.h"
|
||||
#include "GDCore/Project/ExternalLayout.h"
|
||||
@@ -113,13 +119,29 @@ gd::EventsFunctionsExtension &SetupProjectWithEventsFunctionExtension(
|
||||
eventsBasedBehavior.SetFullName("My events based behavior");
|
||||
eventsBasedBehavior.SetDescription("An events based behavior for test");
|
||||
|
||||
// Add functions
|
||||
// Add functions, and parameters that should be there by convention.
|
||||
auto &behaviorEventsFunctions = eventsBasedBehavior.GetEventsFunctions();
|
||||
behaviorEventsFunctions.InsertNewEventsFunction("MyBehaviorEventsFunction",
|
||||
0);
|
||||
behaviorEventsFunctions
|
||||
.InsertNewEventsFunction("MyBehaviorEventsFunctionExpression", 1)
|
||||
.SetFunctionType(gd::EventsFunction::Expression);
|
||||
auto &behaviorAction = behaviorEventsFunctions.InsertNewEventsFunction(
|
||||
"MyBehaviorEventsFunction", 0);
|
||||
behaviorAction.GetParameters().push_back(
|
||||
gd::ParameterMetadata().SetName("Object").SetType("object"));
|
||||
behaviorAction.GetParameters().push_back(
|
||||
gd::ParameterMetadata()
|
||||
.SetName("Behavior")
|
||||
.SetType("behavior")
|
||||
.SetExtraInfo("MyExtension::MyEventsBasedBehavior"));
|
||||
|
||||
auto &behaviorExpression =
|
||||
behaviorEventsFunctions
|
||||
.InsertNewEventsFunction("MyBehaviorEventsFunctionExpression", 1)
|
||||
.SetFunctionType(gd::EventsFunction::Expression);
|
||||
behaviorExpression.GetParameters().push_back(
|
||||
gd::ParameterMetadata().SetName("Object").SetType("object"));
|
||||
behaviorExpression.GetParameters().push_back(
|
||||
gd::ParameterMetadata()
|
||||
.SetName("Behavior")
|
||||
.SetType("behavior")
|
||||
.SetExtraInfo("MyExtension::MyEventsBasedBehavior"));
|
||||
|
||||
// Add property
|
||||
eventsBasedBehavior.GetPropertyDescriptors()
|
||||
@@ -703,7 +725,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
.GetEvent(0)) ==
|
||||
"1 + MyEventsExtension::MyEventsFunctionExpression(456, 123)");
|
||||
}
|
||||
SECTION("Events based Behavior type renamed") {
|
||||
SECTION("Events based Behavior renamed (instructions update)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
@@ -757,6 +779,52 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
"ObjectWithMyBehavior.MyBehavior::"
|
||||
"MyBehaviorEventsFunctionExpression(123, 456, 789)");
|
||||
}
|
||||
SECTION("Events based Behavior renamed (other behaviors properties update)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
auto &eventsBasedBehavior =
|
||||
eventsExtension.GetEventsBasedBehaviors().Get("MyEventsBasedBehavior");
|
||||
|
||||
// Set up another events based behavior having a "required behavior"
|
||||
// property refering to the behavior.
|
||||
auto &otherEventsExtension =
|
||||
project.InsertNewEventsFunctionsExtension("MyOtherEventsExtension", 0);
|
||||
auto &otherEventsBasedBehavior =
|
||||
eventsExtension.GetEventsBasedBehaviors().InsertNew(
|
||||
"MyOtherEventsBasedBehavior");
|
||||
auto &otherEventsBasedBehaviorFirstProperty =
|
||||
otherEventsBasedBehavior.GetPropertyDescriptors()
|
||||
.InsertNew("SomeRequiredBehavior")
|
||||
.SetType("Behavior")
|
||||
.AddExtraInfo("MyEventsExtension::MyEventsBasedBehavior");
|
||||
|
||||
// Also add another "required behavior" property referring to another
|
||||
// unrelated behavior.
|
||||
auto &otherEventsBasedBehaviorSecondProperty =
|
||||
otherEventsBasedBehavior.GetPropertyDescriptors()
|
||||
.InsertNew("SomeRequiredBehavior")
|
||||
.SetType("Behavior")
|
||||
.AddExtraInfo("SomeOtherExtension::SomeOtherBehavior");
|
||||
|
||||
gd::WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
project,
|
||||
eventsExtension,
|
||||
"MyEventsBasedBehavior",
|
||||
"MyRenamedEventsBasedBehavior");
|
||||
|
||||
// Check the other events-based behavior has its property updated.
|
||||
REQUIRE(otherEventsBasedBehaviorFirstProperty.GetExtraInfo().size() == 1);
|
||||
REQUIRE(otherEventsBasedBehaviorFirstProperty.GetExtraInfo().at(0) ==
|
||||
"MyEventsExtension::MyRenamedEventsBasedBehavior");
|
||||
|
||||
// Check the other events-based behavior has its other property left
|
||||
// untouched.
|
||||
REQUIRE(otherEventsBasedBehaviorSecondProperty.GetExtraInfo().size() == 1);
|
||||
REQUIRE(otherEventsBasedBehaviorSecondProperty.GetExtraInfo().at(0) ==
|
||||
"SomeOtherExtension::SomeOtherBehavior");
|
||||
}
|
||||
SECTION("(Events based Behavior) events function renamed") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
@@ -882,7 +950,8 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
"ObjectWithMyBehavior::MyBehavior."
|
||||
"MyBehaviorEventsFunctionExpression(123, 456, 789)");
|
||||
}
|
||||
SECTION("(Events based Behavior) property renamed") {
|
||||
SECTION(
|
||||
"(Events based Behavior) property (not a required behavior) renamed") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
@@ -890,11 +959,12 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
auto &eventsBasedBehavior =
|
||||
eventsExtension.GetEventsBasedBehaviors().Get("MyEventsBasedBehavior");
|
||||
|
||||
gd::WholeProjectRefactorer::RenameBehaviorProperty(project,
|
||||
eventsExtension,
|
||||
eventsBasedBehavior,
|
||||
"MyProperty",
|
||||
"MyRenamedProperty");
|
||||
gd::WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
|
||||
project,
|
||||
eventsExtension,
|
||||
eventsBasedBehavior,
|
||||
"MyProperty",
|
||||
"MyRenamedProperty");
|
||||
|
||||
// Check if events-based behaviors property has been renamed in
|
||||
// instructions
|
||||
@@ -919,3 +989,459 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
"ObjectWithMyBehavior.MyBehavior::PropertyMyRenamedProperty()");
|
||||
}
|
||||
}
|
||||
TEST_CASE("WholeProjectRefactorer (FindInvalidRequiredBehaviorProperties)",
|
||||
"[common]") {
|
||||
SECTION("Find nothing if there are no missing required behavior") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
std::vector<gd::UnfilledRequiredBehaviorPropertyProblem> problems =
|
||||
gd::WholeProjectRefactorer::FindInvalidRequiredBehaviorProperties(
|
||||
project);
|
||||
REQUIRE(problems.size() == 0);
|
||||
}
|
||||
SECTION("Find unfilled required behavior properties") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
// Insert an object using a behavior requiring another behavior.
|
||||
// But don't fill the property, which is a problem.
|
||||
auto &object =
|
||||
project.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
|
||||
object.AddNewBehavior(project,
|
||||
"MyExtension::BehaviorWithRequiredBehaviorProperty",
|
||||
"MyBehaviorWithRequiredBehaviorProperty");
|
||||
|
||||
std::vector<gd::UnfilledRequiredBehaviorPropertyProblem> problems =
|
||||
gd::WholeProjectRefactorer::FindInvalidRequiredBehaviorProperties(
|
||||
project);
|
||||
REQUIRE(problems.size() == 1);
|
||||
REQUIRE(problems[0].GetSourceObject().GetName() == "MyObject");
|
||||
REQUIRE(problems[0].GetSourceBehaviorContent().GetName() ==
|
||||
"MyBehaviorWithRequiredBehaviorProperty");
|
||||
REQUIRE(problems[0].GetSourcePropertyName() == "requiredBehaviorProperty");
|
||||
REQUIRE(problems[0].GetExpectedBehaviorTypeName() ==
|
||||
"MyExtension::MyBehavior");
|
||||
}
|
||||
SECTION("Find nothing if the required behavior properties are filled") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
// Insert an object using a behavior requiring another behavior.
|
||||
auto &object =
|
||||
project.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
|
||||
object.AddNewBehavior(project,
|
||||
"MyExtension::BehaviorWithRequiredBehaviorProperty",
|
||||
"MyBehaviorWithRequiredBehaviorProperty");
|
||||
object.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
|
||||
|
||||
// Fill the required behavior property on the object.
|
||||
gd::Behavior &behavior =
|
||||
gd::MetadataProvider::GetBehaviorMetadata(
|
||||
platform, "MyExtension::BehaviorWithRequiredBehaviorProperty")
|
||||
.Get();
|
||||
gd::BehaviorContent &behaviorContent =
|
||||
object.GetBehavior("MyBehaviorWithRequiredBehaviorProperty");
|
||||
REQUIRE(behavior.UpdateProperty(behaviorContent.GetContent(),
|
||||
"requiredBehaviorProperty",
|
||||
"MyBehavior") == true);
|
||||
|
||||
std::vector<gd::UnfilledRequiredBehaviorPropertyProblem> problems =
|
||||
gd::WholeProjectRefactorer::FindInvalidRequiredBehaviorProperties(
|
||||
project);
|
||||
REQUIRE(problems.size() == 0);
|
||||
}
|
||||
SECTION("Find wrongly filled (wrong type) required behavior properties") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
// Insert an object using a behavior requiring another behavior.
|
||||
auto &object =
|
||||
project.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
|
||||
object.AddNewBehavior(project,
|
||||
"MyExtension::BehaviorWithRequiredBehaviorProperty",
|
||||
"MyBehaviorWithRequiredBehaviorProperty");
|
||||
object.AddNewBehavior(
|
||||
project, "MyExtension::MyOtherBehavior", "MyOtherBehavior");
|
||||
|
||||
// Fill the required behavior property on the object with the wrong behavior
|
||||
// name
|
||||
gd::Behavior &behavior =
|
||||
gd::MetadataProvider::GetBehaviorMetadata(
|
||||
platform, "MyExtension::BehaviorWithRequiredBehaviorProperty")
|
||||
.Get();
|
||||
gd::BehaviorContent &behaviorContent =
|
||||
object.GetBehavior("MyBehaviorWithRequiredBehaviorProperty");
|
||||
REQUIRE(behavior.UpdateProperty(behaviorContent.GetContent(),
|
||||
"requiredBehaviorProperty",
|
||||
"MyOtherBehavior") == true);
|
||||
|
||||
std::vector<gd::UnfilledRequiredBehaviorPropertyProblem> problems =
|
||||
gd::WholeProjectRefactorer::FindInvalidRequiredBehaviorProperties(
|
||||
project);
|
||||
REQUIRE(problems.size() == 1);
|
||||
REQUIRE(problems[0].GetSourceObject().GetName() == "MyObject");
|
||||
REQUIRE(problems[0].GetSourceBehaviorContent().GetName() ==
|
||||
"MyBehaviorWithRequiredBehaviorProperty");
|
||||
REQUIRE(problems[0].GetSourcePropertyName() == "requiredBehaviorProperty");
|
||||
REQUIRE(problems[0].GetExpectedBehaviorTypeName() ==
|
||||
"MyExtension::MyBehavior");
|
||||
}
|
||||
SECTION("Find wrongly filled (not existing) required behavior properties") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
// Insert an object using a behavior requiring another behavior.
|
||||
auto &object =
|
||||
project.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
|
||||
object.AddNewBehavior(project,
|
||||
"MyExtension::BehaviorWithRequiredBehaviorProperty",
|
||||
"MyBehaviorWithRequiredBehaviorProperty");
|
||||
|
||||
// Fill the required behavior property on the object with the wrong behavior
|
||||
// name
|
||||
gd::Behavior &behavior =
|
||||
gd::MetadataProvider::GetBehaviorMetadata(
|
||||
platform, "MyExtension::BehaviorWithRequiredBehaviorProperty")
|
||||
.Get();
|
||||
gd::BehaviorContent &behaviorContent =
|
||||
object.GetBehavior("MyBehaviorWithRequiredBehaviorProperty");
|
||||
REQUIRE(behavior.UpdateProperty(behaviorContent.GetContent(),
|
||||
"requiredBehaviorProperty",
|
||||
"MyNotExistingBehavior") == true);
|
||||
|
||||
std::vector<gd::UnfilledRequiredBehaviorPropertyProblem> problems =
|
||||
gd::WholeProjectRefactorer::FindInvalidRequiredBehaviorProperties(
|
||||
project);
|
||||
REQUIRE(problems.size() == 1);
|
||||
REQUIRE(problems[0].GetSourceObject().GetName() == "MyObject");
|
||||
REQUIRE(problems[0].GetSourceBehaviorContent().GetName() ==
|
||||
"MyBehaviorWithRequiredBehaviorProperty");
|
||||
REQUIRE(problems[0].GetSourcePropertyName() == "requiredBehaviorProperty");
|
||||
REQUIRE(problems[0].GetExpectedBehaviorTypeName() ==
|
||||
"MyExtension::MyBehavior");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("WholeProjectRefactorer (FixInvalidRequiredBehaviorProperties)",
|
||||
"[common]") {
|
||||
SECTION("Fix nothing if there are no missing required behavior") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
REQUIRE(gd::WholeProjectRefactorer::FixInvalidRequiredBehaviorProperties(
|
||||
project) == false);
|
||||
}
|
||||
SECTION(
|
||||
"Fix unfilled required behavior properties by adding a behavior if "
|
||||
"necessary") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
// Insert an object using a behavior requiring another behavior.
|
||||
// But don't fill the property, which is a problem.
|
||||
auto &object =
|
||||
project.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
|
||||
object.AddNewBehavior(project,
|
||||
"MyExtension::BehaviorWithRequiredBehaviorProperty",
|
||||
"MyBehaviorWithRequiredBehaviorProperty");
|
||||
|
||||
REQUIRE(gd::WholeProjectRefactorer::FixInvalidRequiredBehaviorProperties(
|
||||
project) == true);
|
||||
|
||||
// Check the behavior is still there.
|
||||
REQUIRE(object.HasBehaviorNamed("MyBehaviorWithRequiredBehaviorProperty"));
|
||||
|
||||
// Check that the property was filled with the newly added behavior.
|
||||
REQUIRE(object.GetBehavior("MyBehaviorWithRequiredBehaviorProperty")
|
||||
.GetContent()
|
||||
.HasAttribute("requiredBehaviorProperty"));
|
||||
REQUIRE(object.GetBehavior("MyBehaviorWithRequiredBehaviorProperty")
|
||||
.GetContent()
|
||||
.GetStringAttribute("requiredBehaviorProperty") ==
|
||||
"MyBehavior");
|
||||
|
||||
// And also the new behavior that was missing (inserted using its default
|
||||
// name).
|
||||
REQUIRE(object.GetAllBehaviorNames().size() == 2);
|
||||
REQUIRE(object.HasBehaviorNamed("MyBehavior"));
|
||||
REQUIRE(object.GetBehavior("MyBehavior").GetTypeName() ==
|
||||
"MyExtension::MyBehavior");
|
||||
|
||||
// Check there is no other fix to do.
|
||||
REQUIRE(gd::WholeProjectRefactorer::FixInvalidRequiredBehaviorProperties(
|
||||
project) == false);
|
||||
}
|
||||
|
||||
SECTION(
|
||||
"Fix wrongly filled required behavior properties without adding a "
|
||||
"behavior, if not necessary") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
// Insert an object using a behavior requiring another behavior.
|
||||
auto &object =
|
||||
project.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
|
||||
object.AddNewBehavior(project,
|
||||
"MyExtension::BehaviorWithRequiredBehaviorProperty",
|
||||
"MyBehaviorWithRequiredBehaviorProperty");
|
||||
object.AddNewBehavior(project, "MyExtension::MyBehavior", "MyBehavior");
|
||||
|
||||
// Wrongly fill the required behavior property on the object.
|
||||
gd::Behavior &behavior =
|
||||
gd::MetadataProvider::GetBehaviorMetadata(
|
||||
platform, "MyExtension::BehaviorWithRequiredBehaviorProperty")
|
||||
.Get();
|
||||
gd::BehaviorContent &behaviorContent =
|
||||
object.GetBehavior("MyBehaviorWithRequiredBehaviorProperty");
|
||||
REQUIRE(behavior.UpdateProperty(behaviorContent.GetContent(),
|
||||
"requiredBehaviorProperty",
|
||||
"ThisIsInvalid") == true);
|
||||
|
||||
// Check a fix is done
|
||||
REQUIRE(gd::WholeProjectRefactorer::FixInvalidRequiredBehaviorProperties(
|
||||
project) == true);
|
||||
|
||||
REQUIRE(object.HasBehaviorNamed("MyBehaviorWithRequiredBehaviorProperty"));
|
||||
|
||||
// Check that the property was filled with the existing behavior.
|
||||
REQUIRE(behavior.GetProperties(behaviorContent.GetContent())
|
||||
.at("requiredBehaviorProperty")
|
||||
.GetValue() == "MyBehavior");
|
||||
|
||||
// Check that the existing behavior is unchanged.
|
||||
REQUIRE(object.GetAllBehaviorNames().size() == 2);
|
||||
REQUIRE(object.HasBehaviorNamed("MyBehavior"));
|
||||
REQUIRE(object.GetBehavior("MyBehavior").GetTypeName() ==
|
||||
"MyExtension::MyBehavior");
|
||||
|
||||
// Check there is no other fix to do.
|
||||
REQUIRE(gd::WholeProjectRefactorer::FixInvalidRequiredBehaviorProperties(
|
||||
project) == false);
|
||||
}
|
||||
}
|
||||
TEST_CASE("WholeProjectRefactorer (AddBehaviorAndRequiredBehaviors)",
|
||||
"[common]") {
|
||||
SECTION(
|
||||
"Does not add anything else if the newly added behavior has no required "
|
||||
"behavior properties") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &object =
|
||||
project.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
|
||||
|
||||
// Add a simple behavior.
|
||||
gd::WholeProjectRefactorer::AddBehaviorAndRequiredBehaviors(
|
||||
project, object, "MyExtension::MyBehavior", "MyBehavior");
|
||||
|
||||
REQUIRE(object.HasBehaviorNamed("MyBehavior"));
|
||||
REQUIRE(object.GetAllBehaviorNames().size() == 1);
|
||||
}
|
||||
|
||||
SECTION("Does not add anything else if the newly added behavior is unknown") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &object =
|
||||
project.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
|
||||
|
||||
// Add a simple behavior.
|
||||
gd::WholeProjectRefactorer::AddBehaviorAndRequiredBehaviors(
|
||||
project,
|
||||
object,
|
||||
"MyExtension::MyNotExistingBehavior",
|
||||
"MyNotExistingBehavior");
|
||||
|
||||
REQUIRE(object.GetAllBehaviorNames().size() == 0);
|
||||
}
|
||||
|
||||
SECTION("Add a behavior and its required behaviors on an object") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &object =
|
||||
project.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
|
||||
|
||||
// Add the behavior that requires a behavior.
|
||||
gd::WholeProjectRefactorer::AddBehaviorAndRequiredBehaviors(
|
||||
project,
|
||||
object,
|
||||
"MyExtension::"
|
||||
"BehaviorWithRequiredBehaviorProperty",
|
||||
"BehaviorWithRequiredBehaviorProperty");
|
||||
|
||||
// Required behavior are added.
|
||||
REQUIRE(object.HasBehaviorNamed("MyBehavior"));
|
||||
REQUIRE(object.HasBehaviorNamed("BehaviorWithRequiredBehaviorProperty"));
|
||||
|
||||
// Check that required behavior properties were filled properly too.
|
||||
const auto &metadata1 = gd::MetadataProvider::GetBehaviorMetadata(
|
||||
platform,
|
||||
"MyExtension::"
|
||||
"BehaviorWithRequiredBehaviorProperty");
|
||||
REQUIRE(!gd::MetadataProvider::IsBadBehaviorMetadata(metadata1));
|
||||
const auto &behaviorWithRequiredBehaviorPropertyProperties =
|
||||
metadata1.Get().GetProperties(
|
||||
object.GetBehavior("BehaviorWithRequiredBehaviorProperty")
|
||||
.GetContent());
|
||||
|
||||
REQUIRE(behaviorWithRequiredBehaviorPropertyProperties
|
||||
.at("requiredBehaviorProperty")
|
||||
.GetValue() == "MyBehavior");
|
||||
}
|
||||
|
||||
SECTION(
|
||||
"Add a behavior and its required behaviors on an object (transitively)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &object =
|
||||
project.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
|
||||
|
||||
// Add the behavior that requires a behavior that requires another.
|
||||
gd::WholeProjectRefactorer::AddBehaviorAndRequiredBehaviors(
|
||||
project,
|
||||
object,
|
||||
"MyExtension::"
|
||||
"BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior",
|
||||
"BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior");
|
||||
|
||||
// Required behavior are added transitively.
|
||||
REQUIRE(object.HasBehaviorNamed("MyBehavior"));
|
||||
REQUIRE(object.HasBehaviorNamed("BehaviorWithRequiredBehaviorProperty"));
|
||||
REQUIRE(object.HasBehaviorNamed(
|
||||
"BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior"));
|
||||
|
||||
// Check that required behavior properties were filled properly too.
|
||||
const auto &metadata1 = gd::MetadataProvider::GetBehaviorMetadata(
|
||||
platform,
|
||||
"MyExtension::"
|
||||
"BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior");
|
||||
const auto &metadata2 = gd::MetadataProvider::GetBehaviorMetadata(
|
||||
platform, "MyExtension::BehaviorWithRequiredBehaviorProperty");
|
||||
REQUIRE(!gd::MetadataProvider::IsBadBehaviorMetadata(metadata1));
|
||||
REQUIRE(!gd::MetadataProvider::IsBadBehaviorMetadata(metadata2));
|
||||
const auto &
|
||||
behaviorWithRequiredBehaviorPropertyRequiringAnotherBehaviorProperties =
|
||||
metadata1.Get().GetProperties(
|
||||
object
|
||||
.GetBehavior("BehaviorWithRequiredBehaviorPropertyRequiring"
|
||||
"AnotherBehavior")
|
||||
.GetContent());
|
||||
const auto &behaviorWithRequiredBehaviorPropertyProperties =
|
||||
metadata2.Get().GetProperties(
|
||||
object.GetBehavior("BehaviorWithRequiredBehaviorProperty")
|
||||
.GetContent());
|
||||
|
||||
REQUIRE(
|
||||
behaviorWithRequiredBehaviorPropertyRequiringAnotherBehaviorProperties
|
||||
.at("requiredBehaviorProperty")
|
||||
.GetValue() == "BehaviorWithRequiredBehaviorProperty");
|
||||
REQUIRE(behaviorWithRequiredBehaviorPropertyProperties
|
||||
.at("requiredBehaviorProperty")
|
||||
.GetValue() == "MyBehavior");
|
||||
}
|
||||
}
|
||||
TEST_CASE("WholeProjectRefactorer (FindDependentBehaviorNames)", "[common]") {
|
||||
SECTION("Find behaviors that are dependent on another") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &object =
|
||||
project.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
|
||||
|
||||
// Add the behavior that requires a behavior that requires another.
|
||||
gd::WholeProjectRefactorer::AddBehaviorAndRequiredBehaviors(
|
||||
project,
|
||||
object,
|
||||
"MyExtension::"
|
||||
"BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior",
|
||||
"BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior");
|
||||
|
||||
// Required behavior are added transitively.
|
||||
REQUIRE(object.HasBehaviorNamed("MyBehavior"));
|
||||
REQUIRE(object.HasBehaviorNamed("BehaviorWithRequiredBehaviorProperty"));
|
||||
REQUIRE(object.HasBehaviorNamed(
|
||||
"BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior"));
|
||||
|
||||
// Find dependent behaviors
|
||||
{
|
||||
const auto &behaviorNames =
|
||||
gd::WholeProjectRefactorer::FindDependentBehaviorNames(
|
||||
project, object, "MyBehavior");
|
||||
|
||||
REQUIRE(behaviorNames.size() == 2);
|
||||
REQUIRE(std::find(behaviorNames.begin(),
|
||||
behaviorNames.end(),
|
||||
"BehaviorWithRequiredBehaviorProperty") !=
|
||||
behaviorNames.end());
|
||||
REQUIRE(
|
||||
std::find(
|
||||
behaviorNames.begin(),
|
||||
behaviorNames.end(),
|
||||
"BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior") !=
|
||||
behaviorNames.end());
|
||||
}
|
||||
{
|
||||
const auto &behaviorNames =
|
||||
gd::WholeProjectRefactorer::FindDependentBehaviorNames(
|
||||
project, object, "BehaviorWithRequiredBehaviorProperty");
|
||||
|
||||
REQUIRE(behaviorNames.size() == 1);
|
||||
REQUIRE(
|
||||
std::find(
|
||||
behaviorNames.begin(),
|
||||
behaviorNames.end(),
|
||||
"BehaviorWithRequiredBehaviorPropertyRequiringAnotherBehavior") !=
|
||||
behaviorNames.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
TEST_CASE("WholeProjectRefactorer (FindDependentBehaviorNames failing cases)",
|
||||
"[common]") {
|
||||
SECTION("Handle non existing behaviors") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &object =
|
||||
project.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
|
||||
|
||||
// Add the behavior that requires a behavior that requires another.
|
||||
gd::WholeProjectRefactorer::AddBehaviorAndRequiredBehaviors(
|
||||
project,
|
||||
object,
|
||||
"MyExtension::"
|
||||
"BehaviorWithRequiredBehaviorProperty",
|
||||
"BehaviorWithRequiredBehaviorProperty");
|
||||
|
||||
// Required behavior are added transitively.
|
||||
REQUIRE(object.HasBehaviorNamed("MyBehavior"));
|
||||
REQUIRE(object.HasBehaviorNamed("BehaviorWithRequiredBehaviorProperty"));
|
||||
|
||||
gd::BehaviorContent unknownBehaviorContent(
|
||||
"MyUnknownBehavior", "MyUnknownExtension::MyUnknownBehavior");
|
||||
object.AddBehavior(unknownBehaviorContent);
|
||||
|
||||
// Find dependent behaviors, and ignore the unknown one.
|
||||
{
|
||||
const auto &behaviorNames =
|
||||
gd::WholeProjectRefactorer::FindDependentBehaviorNames(
|
||||
project, object, "MyBehavior");
|
||||
|
||||
REQUIRE(behaviorNames.size() == 1);
|
||||
REQUIRE(std::find(behaviorNames.begin(),
|
||||
behaviorNames.end(),
|
||||
"BehaviorWithRequiredBehaviorProperty") !=
|
||||
behaviorNames.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -6,8 +6,8 @@ This project is released under the MIT License.
|
||||
#ifndef ANCHORBEHAVIOR_H
|
||||
#define ANCHORBEHAVIOR_H
|
||||
#include <vector>
|
||||
#include "GDCpp/Runtime/Project/Behavior.h"
|
||||
#include "GDCpp/Runtime/Project/Object.h"
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
namespace gd {
|
||||
class SerializerElement;
|
||||
class Project;
|
||||
@@ -16,7 +16,7 @@ class Project;
|
||||
/**
|
||||
* \brief Allow to anchor objects to the window's bounds.
|
||||
*/
|
||||
class GD_EXTENSION_API AnchorBehavior : public Behavior {
|
||||
class GD_EXTENSION_API AnchorBehavior : public gd::Behavior {
|
||||
public:
|
||||
enum HorizontalAnchor {
|
||||
ANCHOR_HORIZONTAL_NONE = 0,
|
||||
|
@@ -1,212 +0,0 @@
|
||||
/**
|
||||
|
||||
GDevelop - Anchor Behavior Extension
|
||||
Copyright (c) 2016 Victor Levasseur (victorlevasseur52@gmail.com)
|
||||
This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#include "AnchorRuntimeBehavior.h"
|
||||
#include <SFML/Window.hpp>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
#include "GDCpp/Extensions/Builtin/MathematicalTools.h"
|
||||
#include "GDCpp/Runtime/CommonTools.h"
|
||||
#include "GDCpp/Runtime/Project/Layout.h"
|
||||
#include "GDCpp/Runtime/RuntimeGame.h"
|
||||
#include "GDCpp/Runtime/RuntimeObject.h"
|
||||
#include "GDCpp/Runtime/RuntimeScene.h"
|
||||
#include "GDCpp/Runtime/Serialization/SerializerElement.h"
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#include <map>
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#endif
|
||||
|
||||
AnchorRuntimeBehavior::AnchorRuntimeBehavior(
|
||||
const gd::SerializerElement& behaviorContent)
|
||||
: RuntimeBehavior(behaviorContent),
|
||||
m_relativeToOriginalWindowSize(true),
|
||||
m_leftEdgeAnchor(ANCHOR_HORIZONTAL_NONE),
|
||||
m_rightEdgeAnchor(ANCHOR_HORIZONTAL_NONE),
|
||||
m_topEdgeAnchor(ANCHOR_VERTICAL_NONE),
|
||||
m_bottomEdgeAnchor(ANCHOR_VERTICAL_NONE),
|
||||
m_invalidDistances(true),
|
||||
m_leftEdgeDistance(0.f),
|
||||
m_rightEdgeDistance(0.f),
|
||||
m_topEdgeDistance(0.f),
|
||||
m_bottomEdgeDistance(0.f) {
|
||||
m_relativeToOriginalWindowSize =
|
||||
behaviorContent.GetBoolAttribute("relativeToOriginalWindowSize");
|
||||
m_leftEdgeAnchor = static_cast<HorizontalAnchor>(
|
||||
behaviorContent.GetIntAttribute("leftEdgeAnchor"));
|
||||
m_rightEdgeAnchor = static_cast<HorizontalAnchor>(
|
||||
behaviorContent.GetIntAttribute("rightEdgeAnchor"));
|
||||
m_topEdgeAnchor = static_cast<VerticalAnchor>(
|
||||
behaviorContent.GetIntAttribute("topEdgeAnchor"));
|
||||
m_bottomEdgeAnchor = static_cast<VerticalAnchor>(
|
||||
behaviorContent.GetIntAttribute("bottomEdgeAnchor"));
|
||||
}
|
||||
|
||||
void AnchorRuntimeBehavior::OnActivate() { m_invalidDistances = true; }
|
||||
|
||||
namespace {
|
||||
sf::Vector2f mapFloatPixelToCoords(const sf::Vector2f& point,
|
||||
const sf::RenderTarget& target,
|
||||
const sf::View& view) {
|
||||
// First, convert from viewport coordinates to homogeneous coordinates
|
||||
sf::Vector2f normalized;
|
||||
sf::IntRect viewport = target.getViewport(view);
|
||||
normalized.x = -1.f + 2.f * (point.x - static_cast<float>(viewport.left)) /
|
||||
static_cast<float>(viewport.width);
|
||||
normalized.y = 1.f - 2.f * (point.y - static_cast<float>(viewport.top)) /
|
||||
static_cast<float>(viewport.height);
|
||||
|
||||
// Then transform by the inverse of the view matrix
|
||||
return view.getInverseTransform().transformPoint(normalized);
|
||||
}
|
||||
|
||||
sf::Vector2f mapCoordsToFloatPixel(const sf::Vector2f& point,
|
||||
const sf::RenderTarget& target,
|
||||
const sf::View& view) {
|
||||
// Note: almost the same as RenderTarget::mapCoordsToPixel except that the
|
||||
// result is sf::Vector2f
|
||||
|
||||
// First, transform the point by the view matrix
|
||||
sf::Vector2f normalized = view.getTransform().transformPoint(point);
|
||||
|
||||
// Then convert to viewport coordinates
|
||||
sf::Vector2f pixel;
|
||||
sf::IntRect viewport = target.getViewport(view);
|
||||
pixel.x = (normalized.x + 1.f) / 2.f * static_cast<float>(viewport.width) +
|
||||
static_cast<float>(viewport.left);
|
||||
pixel.y = (-normalized.y + 1.f) / 2.f * static_cast<float>(viewport.height) +
|
||||
static_cast<float>(viewport.top);
|
||||
|
||||
return pixel;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void AnchorRuntimeBehavior::DoStepPreEvents(RuntimeScene& scene) {}
|
||||
|
||||
void AnchorRuntimeBehavior::DoStepPostEvents(RuntimeScene& scene) {
|
||||
const RuntimeLayer& layer = scene.GetRuntimeLayer(object->GetLayer());
|
||||
const RuntimeCamera& firstCamera = layer.GetCamera(0);
|
||||
|
||||
if (m_invalidDistances) {
|
||||
sf::Vector2u windowSize =
|
||||
m_relativeToOriginalWindowSize
|
||||
? sf::Vector2u(scene.game->getWindowOriginalWidth(),
|
||||
scene.game->getWindowOriginalHeight())
|
||||
: scene.renderWindow->getSize();
|
||||
|
||||
// Calculate the distances from the window's bounds.
|
||||
sf::Vector2f topLeftPixel = mapCoordsToFloatPixel(
|
||||
sf::Vector2f(object->GetDrawableX(), object->GetDrawableY()),
|
||||
*(scene.renderWindow),
|
||||
firstCamera.GetSFMLView());
|
||||
|
||||
sf::Vector2f bottomRightPixel = mapCoordsToFloatPixel(
|
||||
sf::Vector2f(object->GetDrawableX() + object->GetWidth(),
|
||||
object->GetDrawableY() + object->GetHeight()),
|
||||
*(scene.renderWindow),
|
||||
firstCamera.GetSFMLView());
|
||||
|
||||
// Left edge
|
||||
if (m_leftEdgeAnchor == ANCHOR_HORIZONTAL_WINDOW_LEFT)
|
||||
m_leftEdgeDistance = topLeftPixel.x;
|
||||
else if (m_leftEdgeAnchor == ANCHOR_HORIZONTAL_WINDOW_RIGHT)
|
||||
m_leftEdgeDistance = static_cast<float>(windowSize.x) - topLeftPixel.x;
|
||||
else if (m_leftEdgeAnchor == ANCHOR_HORIZONTAL_PROPORTIONAL)
|
||||
m_leftEdgeDistance = topLeftPixel.x / windowSize.x;
|
||||
|
||||
// Right edge
|
||||
if (m_rightEdgeAnchor == ANCHOR_HORIZONTAL_WINDOW_LEFT)
|
||||
m_rightEdgeDistance = bottomRightPixel.x;
|
||||
else if (m_rightEdgeAnchor == ANCHOR_HORIZONTAL_WINDOW_RIGHT)
|
||||
m_rightEdgeDistance =
|
||||
static_cast<float>(windowSize.x) - bottomRightPixel.x;
|
||||
else if (m_rightEdgeAnchor == ANCHOR_HORIZONTAL_PROPORTIONAL)
|
||||
m_rightEdgeDistance = bottomRightPixel.x / windowSize.x;
|
||||
|
||||
// Top edge
|
||||
if (m_topEdgeAnchor == ANCHOR_VERTICAL_WINDOW_TOP)
|
||||
m_topEdgeDistance = topLeftPixel.y;
|
||||
else if (m_topEdgeAnchor == ANCHOR_VERTICAL_WINDOW_BOTTOM)
|
||||
m_topEdgeDistance = static_cast<float>(windowSize.y) - topLeftPixel.y;
|
||||
else if (m_topEdgeAnchor == ANCHOR_VERTICAL_PROPORTIONAL)
|
||||
m_topEdgeDistance = topLeftPixel.y / static_cast<float>(windowSize.y);
|
||||
|
||||
// Bottom edge
|
||||
if (m_bottomEdgeAnchor == ANCHOR_VERTICAL_WINDOW_TOP)
|
||||
m_bottomEdgeDistance = bottomRightPixel.y;
|
||||
else if (m_bottomEdgeAnchor == ANCHOR_VERTICAL_WINDOW_BOTTOM)
|
||||
m_bottomEdgeDistance =
|
||||
static_cast<float>(windowSize.y) - bottomRightPixel.y;
|
||||
else if (m_bottomEdgeAnchor == ANCHOR_VERTICAL_PROPORTIONAL)
|
||||
m_bottomEdgeDistance =
|
||||
bottomRightPixel.y / static_cast<float>(windowSize.y);
|
||||
|
||||
m_invalidDistances = false;
|
||||
} else {
|
||||
sf::Vector2u windowSize = scene.renderWindow->getSize();
|
||||
|
||||
// Move and resize the object if needed
|
||||
sf::Vector2f topLeftPixel;
|
||||
sf::Vector2f bottomRightPixel;
|
||||
|
||||
// Left edge
|
||||
if (m_leftEdgeAnchor == ANCHOR_HORIZONTAL_WINDOW_LEFT)
|
||||
topLeftPixel.x = m_leftEdgeDistance;
|
||||
else if (m_leftEdgeAnchor == ANCHOR_HORIZONTAL_WINDOW_RIGHT)
|
||||
topLeftPixel.x = static_cast<float>(windowSize.x) - m_leftEdgeDistance;
|
||||
else if (m_leftEdgeAnchor == ANCHOR_HORIZONTAL_PROPORTIONAL)
|
||||
topLeftPixel.x = m_leftEdgeDistance * static_cast<float>(windowSize.x);
|
||||
|
||||
// Top edge
|
||||
if (m_topEdgeAnchor == ANCHOR_VERTICAL_WINDOW_TOP)
|
||||
topLeftPixel.y = m_topEdgeDistance;
|
||||
else if (m_topEdgeAnchor == ANCHOR_VERTICAL_WINDOW_BOTTOM)
|
||||
topLeftPixel.y = static_cast<float>(windowSize.y) - m_topEdgeDistance;
|
||||
else if (m_topEdgeAnchor == ANCHOR_VERTICAL_PROPORTIONAL)
|
||||
topLeftPixel.y = m_topEdgeDistance * static_cast<float>(windowSize.y);
|
||||
|
||||
// Right edge
|
||||
if (m_rightEdgeAnchor == ANCHOR_HORIZONTAL_WINDOW_LEFT)
|
||||
bottomRightPixel.x = m_rightEdgeDistance;
|
||||
else if (m_rightEdgeAnchor == ANCHOR_HORIZONTAL_WINDOW_RIGHT)
|
||||
bottomRightPixel.x =
|
||||
static_cast<float>(windowSize.x) - m_rightEdgeDistance;
|
||||
else if (m_rightEdgeAnchor == ANCHOR_HORIZONTAL_PROPORTIONAL)
|
||||
bottomRightPixel.x =
|
||||
m_rightEdgeDistance * static_cast<float>(windowSize.x);
|
||||
|
||||
// Bottom edge
|
||||
if (m_bottomEdgeAnchor == ANCHOR_VERTICAL_WINDOW_TOP)
|
||||
bottomRightPixel.y = m_bottomEdgeDistance;
|
||||
else if (m_bottomEdgeAnchor == ANCHOR_VERTICAL_WINDOW_BOTTOM)
|
||||
bottomRightPixel.y =
|
||||
static_cast<float>(windowSize.y) - m_bottomEdgeDistance;
|
||||
else if (m_bottomEdgeAnchor == ANCHOR_VERTICAL_PROPORTIONAL)
|
||||
bottomRightPixel.y =
|
||||
m_bottomEdgeDistance * static_cast<float>(windowSize.y);
|
||||
|
||||
sf::Vector2f topLeftCoord = mapFloatPixelToCoords(
|
||||
topLeftPixel, (*scene.renderWindow), firstCamera.GetSFMLView());
|
||||
sf::Vector2f bottomRightCoord = mapFloatPixelToCoords(
|
||||
bottomRightPixel, (*scene.renderWindow), firstCamera.GetSFMLView());
|
||||
|
||||
// Move and resize the object according to the anchors
|
||||
if (m_rightEdgeAnchor != ANCHOR_HORIZONTAL_NONE)
|
||||
object->SetWidth(bottomRightCoord.x - topLeftCoord.x);
|
||||
if (m_bottomEdgeAnchor != ANCHOR_VERTICAL_NONE)
|
||||
object->SetHeight(bottomRightCoord.y - topLeftCoord.y);
|
||||
if (m_leftEdgeAnchor != ANCHOR_HORIZONTAL_NONE)
|
||||
object->SetX(topLeftCoord.x + object->GetX() - object->GetDrawableX());
|
||||
if (m_topEdgeAnchor != ANCHOR_VERTICAL_NONE)
|
||||
object->SetY(topLeftCoord.y + object->GetY() - object->GetDrawableY());
|
||||
}
|
||||
}
|
@@ -1,72 +0,0 @@
|
||||
/**
|
||||
GDevelop - Anchor Behavior Extension
|
||||
Copyright (c) 2016 Victor Levasseur (victorlevasseur52@gmail.com)
|
||||
This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef ANCHORRuntimeBEHAVIOR_H
|
||||
#define ANCHORRuntimeBEHAVIOR_H
|
||||
|
||||
#include <SFML/Graphics/RenderTarget.hpp>
|
||||
#include <SFML/Graphics/View.hpp>
|
||||
#include <SFML/System/Vector2.hpp>
|
||||
#include <vector>
|
||||
#include "GDCpp/Runtime/RuntimeBehavior.h"
|
||||
#include "GDCpp/Runtime/Project/Object.h"
|
||||
namespace gd {
|
||||
class Layout;
|
||||
}
|
||||
class RuntimeScene;
|
||||
namespace gd {
|
||||
class SerializerElement;
|
||||
}
|
||||
class RuntimeScenePlatformData;
|
||||
|
||||
/**
|
||||
* \brief Allow to anchor objects to the window's bounds.
|
||||
*/
|
||||
class GD_EXTENSION_API AnchorRuntimeBehavior : public RuntimeBehavior {
|
||||
public:
|
||||
enum HorizontalAnchor {
|
||||
ANCHOR_HORIZONTAL_NONE = 0,
|
||||
ANCHOR_HORIZONTAL_WINDOW_LEFT = 1,
|
||||
ANCHOR_HORIZONTAL_WINDOW_RIGHT = 2,
|
||||
ANCHOR_HORIZONTAL_PROPORTIONAL = 3
|
||||
};
|
||||
|
||||
enum VerticalAnchor {
|
||||
ANCHOR_VERTICAL_NONE = 0,
|
||||
ANCHOR_VERTICAL_WINDOW_TOP = 1,
|
||||
ANCHOR_VERTICAL_WINDOW_BOTTOM = 2,
|
||||
ANCHOR_VERTICAL_PROPORTIONAL = 3
|
||||
};
|
||||
|
||||
AnchorRuntimeBehavior(const gd::SerializerElement& behaviorContent);
|
||||
virtual ~AnchorRuntimeBehavior(){};
|
||||
virtual AnchorRuntimeBehavior* Clone() const override { return new AnchorRuntimeBehavior(*this); }
|
||||
|
||||
virtual void OnActivate() override;
|
||||
|
||||
private:
|
||||
virtual void DoStepPreEvents(RuntimeScene& scene) override;
|
||||
virtual void DoStepPostEvents(RuntimeScene& scene) override;
|
||||
|
||||
bool m_relativeToOriginalWindowSize; ///< True if the original size of the
|
||||
///< game window must be used.
|
||||
HorizontalAnchor m_leftEdgeAnchor;
|
||||
HorizontalAnchor m_rightEdgeAnchor;
|
||||
VerticalAnchor m_topEdgeAnchor;
|
||||
VerticalAnchor m_bottomEdgeAnchor;
|
||||
|
||||
bool m_invalidDistances;
|
||||
// Distances (in window's units) from the XXX edge of the object to side of
|
||||
// the window the edge is anchored on. Note: If the edge anchor is set to
|
||||
// PROPORTIONAL, then it contains the ratio of the distance to the window
|
||||
// size.
|
||||
float m_leftEdgeDistance;
|
||||
float m_rightEdgeDistance;
|
||||
float m_topEdgeDistance;
|
||||
float m_bottomEdgeDistance;
|
||||
};
|
||||
|
||||
#endif // ANCHORRuntimeBEHAVIOR_H
|
@@ -13,14 +13,8 @@ gd_add_extension_definitions(AnchorBehavior)
|
||||
include_directories(.)
|
||||
file(GLOB source_files *.cpp *.h)
|
||||
gd_add_clang_utils(AnchorBehavior "${source_files}")
|
||||
|
||||
gd_add_extension_target(AnchorBehavior "${source_files}")
|
||||
gdcpp_add_runtime_extension_target(AnchorBehavior_Runtime "${source_files}")
|
||||
|
||||
#Linker files for the IDE extension
|
||||
###
|
||||
gd_extension_link_libraries(AnchorBehavior)
|
||||
|
||||
#Linker files for the GD C++ Runtime extension
|
||||
###
|
||||
gdcpp_runtime_extension_link_libraries(AnchorBehavior_Runtime)
|
||||
|
@@ -6,9 +6,9 @@ This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#include "AnchorBehavior.h"
|
||||
#include "AnchorRuntimeBehavior.h"
|
||||
#include "GDCpp/Extensions/ExtensionBase.h"
|
||||
#include "GDCpp/Runtime/Project/BehaviorsSharedData.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/Project/BehaviorsSharedData.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
|
||||
void DeclareAnchorBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
extension
|
||||
@@ -30,38 +30,3 @@ void DeclareAnchorBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
std::make_shared<AnchorBehavior>(),
|
||||
std::make_shared<gd::BehaviorsSharedData>());
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief This class declares information about the extension.
|
||||
*/
|
||||
class AnchorBehaviorCppExtension : public ExtensionBase {
|
||||
public:
|
||||
/**
|
||||
* Constructor of an extension declares everything the extension contains:
|
||||
* objects, actions, conditions and expressions.
|
||||
*/
|
||||
AnchorBehaviorCppExtension() {
|
||||
DeclareAnchorBehaviorExtension(*this);
|
||||
AddRuntimeBehavior<AnchorRuntimeBehavior>(
|
||||
GetBehaviorMetadata("AnchorBehavior::AnchorBehavior"),
|
||||
"AnchorRuntimeBehavior");
|
||||
GetBehaviorMetadata("AnchorBehavior::AnchorBehavior")
|
||||
.SetIncludeFile("AnchorBehavior/AnchorRuntimeBehavior.h");
|
||||
|
||||
GD_COMPLETE_EXTENSION_COMPILATION_INFORMATION();
|
||||
};
|
||||
};
|
||||
|
||||
#if defined(ANDROID)
|
||||
extern "C" ExtensionBase* CreateGDCppAnchorBehaviorExtension() {
|
||||
return new AnchorBehaviorCppExtension;
|
||||
}
|
||||
#elif !defined(EMSCRIPTEN)
|
||||
/**
|
||||
* Used by GDevelop to create the extension class
|
||||
* -- Do not need to be modified. --
|
||||
*/
|
||||
extern "C" ExtensionBase* GD_EXTENSION_API CreateGDExtension() {
|
||||
return new AnchorBehaviorCppExtension;
|
||||
}
|
||||
#endif
|
||||
|
@@ -118,7 +118,7 @@ module.exports = {
|
||||
opacity: 255,
|
||||
fontSize: 20,
|
||||
visible: true,
|
||||
color: '#000000',
|
||||
color: '0;0;0',
|
||||
fontFamily: 'Arial',
|
||||
align: 'left',
|
||||
wordWrap: true,
|
||||
@@ -511,7 +511,7 @@ module.exports = {
|
||||
this._pixiObject.alpha = opacity / 255;
|
||||
|
||||
const color = properties.get('color').getValue();
|
||||
this._pixiObject.textStyles.default.fill = color;
|
||||
this._pixiObject.textStyles.default.fill = objectsRenderingService.rgbOrHexToHexNumber(color);
|
||||
|
||||
const fontSize = properties.get('fontSize').getValue();
|
||||
this._pixiObject.textStyles.default.fontSize = `${fontSize}px`;
|
||||
|
@@ -56,7 +56,7 @@ namespace gdjs {
|
||||
// @ts-ignore - parseFloat should not be required, but GDevelop 5.0 beta 92 and below were storing it as a string.
|
||||
this._opacity = parseFloat(objectData.content.opacity);
|
||||
this._text = objectData.content.text;
|
||||
this._color = gdjs.hexToRGBColor(objectData.content.color);
|
||||
this._color = gdjs.rgbOrHexToRGBColor(objectData.content.color);
|
||||
this._fontFamily = objectData.content.fontFamily;
|
||||
// @ts-ignore - parseFloat should not be required, but GDevelop 5.0 beta 92 and below were storing it as a string.
|
||||
this._fontSize = parseFloat(objectData.content.fontSize);
|
||||
@@ -88,7 +88,7 @@ namespace gdjs {
|
||||
this.setBBText(newObjectData.content.text);
|
||||
}
|
||||
if (oldObjectData.content.color !== newObjectData.content.color) {
|
||||
this._color = gdjs.hexToRGBColor(newObjectData.content.color);
|
||||
this._color = gdjs.rgbOrHexToRGBColor(newObjectData.content.color);
|
||||
this._renderer.updateColor();
|
||||
}
|
||||
if (
|
||||
@@ -142,13 +142,7 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
setColor(rgbColorString): void {
|
||||
const splitValue = rgbColorString.split(';');
|
||||
if (splitValue.length !== 3) {
|
||||
return;
|
||||
}
|
||||
this._color[0] = parseInt(splitValue[0], 10);
|
||||
this._color[1] = parseInt(splitValue[1], 10);
|
||||
this._color[2] = parseInt(splitValue[2], 10);
|
||||
this._color = gdjs.rgbOrHexToRGBColor(rgbColorString);
|
||||
this._renderer.updateColor();
|
||||
}
|
||||
|
||||
|
@@ -119,7 +119,7 @@ module.exports = {
|
||||
opacity: 255,
|
||||
scale: 1,
|
||||
fontSize: 20,
|
||||
tint: '#ffffff',
|
||||
tint: '255;255;255',
|
||||
bitmapFontResourceName: '',
|
||||
textureAtlasResourceName: '',
|
||||
align: 'left',
|
||||
@@ -638,7 +638,7 @@ module.exports = {
|
||||
this._pixiObject.align = align;
|
||||
|
||||
const color = properties.get('tint').getValue();
|
||||
this._pixiObject.tint = parseInt(color.replace('#', '0x'), 16);
|
||||
this._pixiObject.tint = objectsRenderingService.rgbOrHexToHexNumber(color);
|
||||
|
||||
const scale = properties.get('scale').getValue() || 1;
|
||||
this._pixiObject.scale.set(scale);
|
||||
|
@@ -1,33 +0,0 @@
|
||||
namespace gdjs {
|
||||
/**
|
||||
* The Cocos2D-JS renderer for the BitmapTextRuntimeObject.
|
||||
*
|
||||
* The implementation is empty as the object is not supported in Cocos2D-JS for now.
|
||||
*/
|
||||
export class BitmapTextRuntimeObjectCocosRenderer {
|
||||
getRendererObject() {}
|
||||
onDestroy() {}
|
||||
getFontSize() {}
|
||||
updateFont() {}
|
||||
updateTint() {}
|
||||
getTint() {}
|
||||
updateScale() {}
|
||||
getScale() {}
|
||||
updateWrappingWidth() {}
|
||||
updateTextContent() {}
|
||||
updateAlignment() {}
|
||||
updatePosition() {}
|
||||
updateAngle() {}
|
||||
updateOpacity() {}
|
||||
|
||||
getWidth() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
getHeight() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
export const BitmapTextRuntimeObjectRenderer = BitmapTextRuntimeObjectCocosRenderer;
|
||||
}
|
@@ -61,7 +61,7 @@ namespace gdjs {
|
||||
|
||||
this._opacity = objectData.content.opacity;
|
||||
this._text = objectData.content.text;
|
||||
this._tint = gdjs.hexToRGBColor(objectData.content.tint);
|
||||
this._tint = gdjs.rgbOrHexToRGBColor(objectData.content.tint);
|
||||
|
||||
this._bitmapFontResourceName = objectData.content.bitmapFontResourceName; // fnt/xml files
|
||||
this._textureAtlasResourceName =
|
||||
@@ -96,7 +96,7 @@ namespace gdjs {
|
||||
this.setText(newObjectData.content.text);
|
||||
}
|
||||
if (oldObjectData.content.tint !== newObjectData.content.tint) {
|
||||
this._tint = gdjs.hexToRGBColor(newObjectData.content.tint);
|
||||
this._tint = gdjs.rgbOrHexToRGBColor(newObjectData.content.tint);
|
||||
this._renderer.updateTint();
|
||||
}
|
||||
if (
|
||||
@@ -159,12 +159,7 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
setTint(rgbColorString: string): void {
|
||||
const splitValue = rgbColorString.split(';');
|
||||
if (splitValue.length !== 3) return;
|
||||
|
||||
this._tint[0] = parseInt(splitValue[0], 10);
|
||||
this._tint[1] = parseInt(splitValue[1], 10);
|
||||
this._tint[2] = parseInt(splitValue[2], 10);
|
||||
this._tint = gdjs.rgbOrHexToRGBColor(rgbColorString);
|
||||
this._renderer.updateTint();
|
||||
}
|
||||
|
||||
|
@@ -6,7 +6,6 @@
|
||||
macro(gd_add_extension_includes)
|
||||
include_directories(${sfml_include_dir})
|
||||
include_directories(${GDCORE_include_dir})
|
||||
include_directories(${GDCpp_include_dir})
|
||||
endmacro()
|
||||
|
||||
#Add common defines for a target that will be a GD extension
|
||||
@@ -76,69 +75,13 @@ function(gd_add_extension_target target_name source_files)
|
||||
ENDIF()
|
||||
endfunction()
|
||||
|
||||
#Add a GDC++ runtime extension target, that will produce the final library file for runtime.
|
||||
function(gdcpp_add_runtime_extension_target gdcpp_runtime_target_name source_files)
|
||||
IF(NOT gdcpp_runtime_target_name MATCHES "_Runtime$")
|
||||
MESSAGE(ERROR "You called gdcpp_add_runtime_extension_target with a target name not finishing with '_Runtime'")
|
||||
ENDIF()
|
||||
string(REGEX REPLACE "_Runtime" "" target_name ${gdcpp_runtime_target_name})
|
||||
|
||||
IF(NOT EMSCRIPTEN) #Also add a GDC++ extension target
|
||||
add_library(${gdcpp_runtime_target_name} SHARED ${source_files})
|
||||
set_target_properties(${gdcpp_runtime_target_name} PROPERTIES COMPILE_DEFINITIONS "${${gdcpp_runtime_target_name}_extra_definitions}")
|
||||
set_target_properties(${gdcpp_runtime_target_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME}/CppPlatform/Extensions/Runtime")
|
||||
set_target_properties(${gdcpp_runtime_target_name} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME}/CppPlatform/Extensions/Runtime")
|
||||
set_target_properties(${gdcpp_runtime_target_name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME}/CppPlatform/Extensions/Runtime")
|
||||
set_target_properties(${gdcpp_runtime_target_name} PROPERTIES RUNTIME_OUTPUT_NAME "${target_name}")
|
||||
set_target_properties(${gdcpp_runtime_target_name} PROPERTIES LIBRARY_OUTPUT_NAME "${target_name}")
|
||||
set_target_properties(${gdcpp_runtime_target_name} PROPERTIES ARCHIVE_OUTPUT_NAME "${target_name}")
|
||||
set_target_properties(${gdcpp_runtime_target_name} PROPERTIES PREFIX "")
|
||||
IF(WIN32) #GD extensions have special suffix in their filenames.
|
||||
set_target_properties(${gdcpp_runtime_target_name} PROPERTIES SUFFIX ".xgdw")
|
||||
ELSE()
|
||||
set_target_properties(${gdcpp_runtime_target_name} PROPERTIES SUFFIX ".xgd")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
endfunction()
|
||||
|
||||
#Link default libraries with a target that is a GD extension
|
||||
function(gd_extension_link_libraries target_name)
|
||||
IF(EMSCRIPTEN)
|
||||
#Nothing.
|
||||
ELSE()
|
||||
target_link_libraries(${target_name} GDCore)
|
||||
target_link_libraries(${target_name} GDCpp)
|
||||
target_link_libraries(${target_name} ${sfml_LIBRARIES})
|
||||
ENDIF()
|
||||
endfunction()
|
||||
|
||||
#Link default libraries with a target that is a GDC++ Runtime extension
|
||||
function(gdcpp_runtime_extension_link_libraries target_name)
|
||||
IF(EMSCRIPTEN)
|
||||
#Nothing.
|
||||
ELSE()
|
||||
target_link_libraries(${target_name} GDCpp_Runtime)
|
||||
target_link_libraries(${target_name} ${sfml_LIBRARIES})
|
||||
IF(WIN32)
|
||||
target_link_libraries(${target_name} ws2_32 user32 opengl32 glu32)
|
||||
ENDIF(WIN32)
|
||||
ENDIF()
|
||||
endfunction()
|
||||
|
||||
|
||||
#Create a target for a test executable of a GDC++ Runtime extension
|
||||
function(gdcpp_add_tests_extension_target gdcpp_tests_target_name test_source_files)
|
||||
IF(NOT gdcpp_tests_target_name MATCHES "_tests$")
|
||||
MESSAGE(ERROR "You called gdcpp_add_tests_extension_target with a target name not finishing with '_tests'")
|
||||
ENDIF()
|
||||
string(REGEX REPLACE "_tests" "" target_name ${gdcpp_tests_target_name})
|
||||
|
||||
if(BUILD_TESTS)
|
||||
add_executable(${gdcpp_tests_target_name} ${test_source_files})
|
||||
target_link_libraries(${gdcpp_tests_target_name} GDCpp_Runtime)
|
||||
target_link_libraries(${gdcpp_tests_target_name} ${target_name})
|
||||
target_link_libraries(${gdcpp_tests_target_name} ${sfml_LIBRARIES})
|
||||
|
||||
set_target_properties(${gdcpp_tests_target_name} PROPERTIES BUILD_WITH_INSTALL_RPATH FALSE) #Allow finding dependencies directly from build path on Mac OS X.
|
||||
endif()
|
||||
endfunction()
|
||||
|
@@ -13,14 +13,8 @@ gd_add_extension_definitions(DestroyOutsideBehavior)
|
||||
include_directories(.)
|
||||
file(GLOB source_files *.cpp *.h)
|
||||
gd_add_clang_utils(DestroyOutsideBehavior "${source_files}")
|
||||
|
||||
gd_add_extension_target(DestroyOutsideBehavior "${source_files}")
|
||||
gdcpp_add_runtime_extension_target(DestroyOutsideBehavior_Runtime "${source_files}")
|
||||
|
||||
#Linker files for the IDE extension
|
||||
###
|
||||
gd_extension_link_libraries(DestroyOutsideBehavior GDCore)
|
||||
|
||||
#Linker files for the GD C++ Runtime extension
|
||||
###
|
||||
gdcpp_runtime_extension_link_libraries(DestroyOutsideBehavior_Runtime)
|
||||
|
@@ -1,55 +0,0 @@
|
||||
/**
|
||||
|
||||
GDevelop - DestroyOutside Behavior Extension
|
||||
Copyright (c) 2014-2016 Florian Rival (Florian.Rival@gmail.com)
|
||||
This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#include "DestroyOutsideRuntimeBehavior.h"
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include "GDCpp/Runtime/CommonTools.h"
|
||||
#include "GDCpp/Runtime/Project/Layout.h"
|
||||
#include "GDCpp/Runtime/RuntimeLayer.h"
|
||||
#include "GDCpp/Runtime/RuntimeObject.h"
|
||||
#include "GDCpp/Runtime/RuntimeScene.h"
|
||||
#include "GDCpp/Runtime/Serialization/SerializerElement.h"
|
||||
|
||||
DestroyOutsideRuntimeBehavior::DestroyOutsideRuntimeBehavior(
|
||||
const gd::SerializerElement& behaviorContent)
|
||||
: RuntimeBehavior(behaviorContent), extraBorder(0) {
|
||||
extraBorder = behaviorContent.GetDoubleAttribute("extraBorder", 0);
|
||||
}
|
||||
|
||||
void DestroyOutsideRuntimeBehavior::DoStepPostEvents(RuntimeScene& scene) {
|
||||
bool erase = true;
|
||||
const RuntimeLayer& theLayer = scene.GetRuntimeLayer(object->GetLayer());
|
||||
float objCenterX = object->GetDrawableX() + object->GetCenterX();
|
||||
float objCenterY = object->GetDrawableY() + object->GetCenterY();
|
||||
for (std::size_t cameraIndex = 0; cameraIndex < theLayer.GetCameraCount();
|
||||
++cameraIndex) {
|
||||
const RuntimeCamera& theCamera = theLayer.GetCamera(cameraIndex);
|
||||
|
||||
float boundingCircleRadius =
|
||||
sqrt(object->GetWidth() * object->GetWidth() +
|
||||
object->GetHeight() * object->GetHeight()) /
|
||||
2.0;
|
||||
if (objCenterX + boundingCircleRadius + extraBorder <
|
||||
theCamera.GetViewCenter().x - theCamera.GetWidth() / 2.0 ||
|
||||
objCenterX - boundingCircleRadius - extraBorder >
|
||||
theCamera.GetViewCenter().x + theCamera.GetWidth() / 2.0 ||
|
||||
objCenterY + boundingCircleRadius + extraBorder <
|
||||
theCamera.GetViewCenter().y - theCamera.GetHeight() / 2.0 ||
|
||||
objCenterY - boundingCircleRadius - extraBorder >
|
||||
theCamera.GetViewCenter().y + theCamera.GetHeight() / 2.0) {
|
||||
// Ok we are outside the camera area.
|
||||
} else {
|
||||
// The object can be viewed by the camera.
|
||||
erase = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (erase) object->DeleteFromScene(scene);
|
||||
}
|
@@ -1,47 +0,0 @@
|
||||
/**
|
||||
|
||||
GDevelop - DestroyOutside Behavior Extension
|
||||
Copyright (c) 2013-2016 Florian Rival (Florian.Rival@gmail.com)
|
||||
This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef DESTROYOUTSIDERUNTIMEBEHAVIOR_H
|
||||
#define DESTROYOUTSIDERUNTIMEBEHAVIOR_H
|
||||
#include <map>
|
||||
#include "GDCpp/Runtime/Project/Object.h"
|
||||
#include "GDCpp/Runtime/RuntimeBehavior.h"
|
||||
class RuntimeScene;
|
||||
namespace gd {
|
||||
class SerializerElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Behavior that allows objects to be dragged with the mouse
|
||||
*/
|
||||
class GD_EXTENSION_API DestroyOutsideRuntimeBehavior : public RuntimeBehavior {
|
||||
public:
|
||||
DestroyOutsideRuntimeBehavior(const gd::SerializerElement& behaviorContent);
|
||||
virtual ~DestroyOutsideRuntimeBehavior(){};
|
||||
virtual DestroyOutsideRuntimeBehavior* Clone() const {
|
||||
return new DestroyOutsideRuntimeBehavior(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the value of the extra border.
|
||||
*/
|
||||
bool GetExtraBorder() const { return extraBorder; };
|
||||
|
||||
/**
|
||||
* \brief Set the value of the extra border, i.e the supplementary margin that
|
||||
* the object must cross before being deleted.
|
||||
*/
|
||||
void SetExtraBorder(float extraBorder_) { extraBorder = extraBorder_; };
|
||||
|
||||
private:
|
||||
virtual void DoStepPostEvents(RuntimeScene& scene);
|
||||
|
||||
float extraBorder; ///< The supplementary margin outside the screen that the
|
||||
///< object must cross before being deleted.
|
||||
};
|
||||
|
||||
#endif // DESTROYOUTSIDERUNTIMEBEHAVIOR_H
|
@@ -6,8 +6,9 @@ This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#include "DestroyOutsideBehavior.h"
|
||||
#include "DestroyOutsideRuntimeBehavior.h"
|
||||
#include "GDCpp/Extensions/ExtensionBase.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/Project/BehaviorsSharedData.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
|
||||
void DeclareDestroyOutsideBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
extension
|
||||
@@ -66,39 +67,3 @@ void DeclareDestroyOutsideBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
.SetIncludeFile("DestroyOutsideBehavior/DestroyOutsideRuntimeBehavior.h");
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief This class declares information about the extension.
|
||||
*/
|
||||
class DestroyOutsideBehaviorCppExtension : public ExtensionBase {
|
||||
public:
|
||||
/**
|
||||
* Constructor of an extension declares everything the extension contains:
|
||||
* objects, actions, conditions and expressions.
|
||||
*/
|
||||
DestroyOutsideBehaviorCppExtension() {
|
||||
DeclareDestroyOutsideBehaviorExtension(*this);
|
||||
AddRuntimeBehavior<DestroyOutsideRuntimeBehavior>(
|
||||
GetBehaviorMetadata("DestroyOutsideBehavior::DestroyOutside"),
|
||||
"DestroyOutsideRuntimeBehavior");
|
||||
GetBehaviorMetadata("DestroyOutsideBehavior::DestroyOutside")
|
||||
.SetIncludeFile(
|
||||
"DestroyOutsideBehavior/DestroyOutsideRuntimeBehavior.h");
|
||||
|
||||
GD_COMPLETE_EXTENSION_COMPILATION_INFORMATION();
|
||||
};
|
||||
};
|
||||
|
||||
#if defined(ANDROID)
|
||||
extern "C" ExtensionBase* CreateGDCppDestroyOutsideBehaviorExtension() {
|
||||
return new DestroyOutsideBehaviorCppExtension;
|
||||
}
|
||||
#elif !defined(EMSCRIPTEN)
|
||||
/**
|
||||
* Used by GDevelop to create the extension class
|
||||
* -- Do not need to be modified. --
|
||||
*/
|
||||
extern "C" ExtensionBase* GD_EXTENSION_API CreateGDExtension() {
|
||||
return new DestroyOutsideBehaviorCppExtension;
|
||||
}
|
||||
#endif
|
||||
|
@@ -13,14 +13,8 @@ gd_add_extension_definitions(DraggableBehavior)
|
||||
include_directories(.)
|
||||
file(GLOB source_files *.cpp *.h)
|
||||
gd_add_clang_utils(DraggableBehavior "${source_files}")
|
||||
|
||||
gd_add_extension_target(DraggableBehavior "${source_files}")
|
||||
gdcpp_add_runtime_extension_target(DraggableBehavior_Runtime "${source_files}")
|
||||
|
||||
#Linker files for the IDE extension
|
||||
###
|
||||
gd_extension_link_libraries(DraggableBehavior)
|
||||
|
||||
#Linker files for the GD C++ Runtime extension
|
||||
###
|
||||
gdcpp_runtime_extension_link_libraries(DraggableBehavior_Runtime)
|
||||
|
@@ -6,6 +6,6 @@ This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#include "DraggableBehavior.h"
|
||||
#include "GDCpp/Runtime/Serialization/SerializerElement.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
|
||||
DraggableBehavior::DraggableBehavior() {}
|
||||
|
@@ -9,8 +9,8 @@ This project is released under the MIT License.
|
||||
#define DRAGGABLEBEHAVIOR_H
|
||||
#include <SFML/System/Vector2.hpp>
|
||||
#include <map>
|
||||
#include "GDCpp/Runtime/Project/Behavior.h"
|
||||
#include "GDCpp/Runtime/Project/Object.h"
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
class RuntimeScene;
|
||||
namespace gd {
|
||||
class SerializerElement;
|
||||
@@ -20,7 +20,7 @@ class Layout;
|
||||
/**
|
||||
* \brief Behavior that allows objects to be dragged with the mouse
|
||||
*/
|
||||
class GD_EXTENSION_API DraggableBehavior : public Behavior {
|
||||
class GD_EXTENSION_API DraggableBehavior : public gd::Behavior {
|
||||
public:
|
||||
DraggableBehavior();
|
||||
virtual ~DraggableBehavior(){};
|
||||
|
@@ -1,75 +0,0 @@
|
||||
/**
|
||||
|
||||
GDevelop - Draggable Behavior Extension
|
||||
Copyright (c) 2014-2016 Florian Rival (Florian.Rival@gmail.com)
|
||||
This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#include "DraggableRuntimeBehavior.h"
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include "GDCpp/Runtime/CommonTools.h"
|
||||
#include "GDCpp/Runtime/Project/Layout.h"
|
||||
#include "GDCpp/Runtime/RuntimeLayer.h"
|
||||
#include "GDCpp/Runtime/RuntimeObject.h"
|
||||
#include "GDCpp/Runtime/RuntimeScene.h"
|
||||
#include "GDCpp/Runtime/Serialization/SerializerElement.h"
|
||||
|
||||
bool DraggableRuntimeBehavior::somethingDragged = false;
|
||||
bool DraggableRuntimeBehavior::leftPressedLastFrame = false;
|
||||
|
||||
DraggableRuntimeBehavior::DraggableRuntimeBehavior(
|
||||
const gd::SerializerElement& behaviorContent)
|
||||
: RuntimeBehavior(behaviorContent), dragged(false) {}
|
||||
|
||||
void DraggableRuntimeBehavior::DoStepPreEvents(RuntimeScene& scene) {
|
||||
// Begin drag ?
|
||||
if (!dragged && scene.GetInputManager().IsMouseButtonPressed("Left") &&
|
||||
!leftPressedLastFrame && !somethingDragged) {
|
||||
RuntimeLayer& theLayer = scene.GetRuntimeLayer(object->GetLayer());
|
||||
for (std::size_t cameraIndex = 0; cameraIndex < theLayer.GetCameraCount();
|
||||
++cameraIndex) {
|
||||
sf::Vector2f mousePos = scene.renderWindow->mapPixelToCoords(
|
||||
scene.GetInputManager().GetMousePosition(),
|
||||
theLayer.GetCamera(cameraIndex).GetSFMLView());
|
||||
|
||||
if (object->GetDrawableX() <= mousePos.x &&
|
||||
object->GetDrawableX() + object->GetWidth() >= mousePos.x &&
|
||||
object->GetDrawableY() <= mousePos.y &&
|
||||
object->GetDrawableY() + object->GetHeight() >= mousePos.y) {
|
||||
dragged = true;
|
||||
somethingDragged = true;
|
||||
xOffset = mousePos.x - object->GetX();
|
||||
yOffset = mousePos.y - object->GetY();
|
||||
dragCameraIndex = cameraIndex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// End dragging ?
|
||||
else if (!scene.GetInputManager().IsMouseButtonPressed("Left")) {
|
||||
dragged = false;
|
||||
somethingDragged = false;
|
||||
}
|
||||
|
||||
// Being dragging ?
|
||||
if (dragged) {
|
||||
RuntimeLayer& theLayer = scene.GetRuntimeLayer(object->GetLayer());
|
||||
sf::Vector2f mousePos = scene.renderWindow->mapPixelToCoords(
|
||||
scene.GetInputManager().GetMousePosition(),
|
||||
theLayer.GetCamera(dragCameraIndex).GetSFMLView());
|
||||
|
||||
object->SetX(mousePos.x - xOffset);
|
||||
object->SetY(mousePos.y - yOffset);
|
||||
}
|
||||
}
|
||||
|
||||
void DraggableRuntimeBehavior::DoStepPostEvents(RuntimeScene& scene) {
|
||||
leftPressedLastFrame = scene.GetInputManager().IsMouseButtonPressed("Left");
|
||||
}
|
||||
|
||||
void DraggableRuntimeBehavior::OnDeActivate() {
|
||||
if (dragged) somethingDragged = false;
|
||||
dragged = false;
|
||||
}
|
@@ -1,50 +0,0 @@
|
||||
/**
|
||||
|
||||
GDevelop - Draggable Behavior Extension
|
||||
Copyright (c) 2013-2016 Florian Rival (Florian.Rival@gmail.com)
|
||||
This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef DRAGGABLERUNTIMEBEHAVIOR_H
|
||||
#define DRAGGABLERUNTIMEBEHAVIOR_H
|
||||
#include "GDCpp/Runtime/Project/Object.h"
|
||||
#include "GDCpp/Runtime/RuntimeBehavior.h"
|
||||
class RuntimeScene;
|
||||
namespace gd {
|
||||
class SerializerElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Behavior that allows objects to be dragged with the mouse
|
||||
*/
|
||||
class GD_EXTENSION_API DraggableRuntimeBehavior : public RuntimeBehavior {
|
||||
public:
|
||||
DraggableRuntimeBehavior(const gd::SerializerElement& behaviorContent);
|
||||
virtual ~DraggableRuntimeBehavior(){};
|
||||
virtual DraggableRuntimeBehavior* Clone() const {
|
||||
return new DraggableRuntimeBehavior(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the object is being dragged.
|
||||
*/
|
||||
bool IsDragged() const { return dragged; };
|
||||
|
||||
virtual void OnDeActivate();
|
||||
|
||||
private:
|
||||
virtual void DoStepPreEvents(RuntimeScene& scene);
|
||||
virtual void DoStepPostEvents(RuntimeScene& scene);
|
||||
|
||||
float xOffset;
|
||||
float yOffset;
|
||||
std::size_t dragCameraIndex; ///< The camera being used to move the object. (
|
||||
///< The layer is the object's layer ).
|
||||
bool dragged; ///< True if the object is being dragged.
|
||||
static bool somethingDragged; ///< Used to avoid start dragging an object
|
||||
///< while another is being dragged.
|
||||
static bool
|
||||
leftPressedLastFrame; ///< Used to only start dragging when clicking.
|
||||
};
|
||||
|
||||
#endif // DRAGGABLERUNTIMEBEHAVIOR_H
|
@@ -6,8 +6,9 @@ This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#include "DraggableBehavior.h"
|
||||
#include "DraggableRuntimeBehavior.h"
|
||||
#include "GDCpp/Extensions/ExtensionBase.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/Project/BehaviorsSharedData.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
|
||||
void DeclareDraggableBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
extension
|
||||
@@ -46,33 +47,3 @@ void DeclareDraggableBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
.SetFunctionName("IsDragged");
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief This class declares information about the extension.
|
||||
*/
|
||||
class Extension : public ExtensionBase {
|
||||
public:
|
||||
/**
|
||||
* Constructor of an extension declares everything the extension contains:
|
||||
* objects, actions, conditions and expressions.
|
||||
*/
|
||||
Extension() {
|
||||
DeclareDraggableBehaviorExtension(*this);
|
||||
AddRuntimeBehavior<DraggableRuntimeBehavior>(
|
||||
GetBehaviorMetadata("DraggableBehavior::Draggable"),
|
||||
"DraggableRuntimeBehavior");
|
||||
GetBehaviorMetadata("DraggableBehavior::Draggable")
|
||||
.SetIncludeFile("DraggableBehavior/DraggableRuntimeBehavior.h");
|
||||
GD_COMPLETE_EXTENSION_COMPILATION_INFORMATION();
|
||||
};
|
||||
};
|
||||
|
||||
#if !defined(EMSCRIPTEN)
|
||||
/**
|
||||
* Used by GDevelop to create the extension class
|
||||
* -- Do not need to be modified. --
|
||||
*/
|
||||
extern "C" ExtensionBase* GD_EXTENSION_API CreateGDExtension() {
|
||||
return new Extension;
|
||||
}
|
||||
#endif
|
||||
|
@@ -897,7 +897,8 @@ module.exports = {
|
||||
.setFullName(_('Radial Blur'))
|
||||
.setDescription(_('Applies a Motion blur to an object.'))
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-radial-blur.js')
|
||||
.addIncludeFile('Extensions/Effects/radial-blur-pixi-filter.js');
|
||||
.addIncludeFile('Extensions/Effects/radial-blur-pixi-filter.js')
|
||||
.markAsNotWorkingForObjects(); // See https://github.com/pixijs/filters/issues/304
|
||||
const radialBlurProperties = radialBlurEffect.getProperties();
|
||||
radialBlurProperties
|
||||
.getOrCreate('radius')
|
||||
@@ -1084,7 +1085,8 @@ module.exports = {
|
||||
)
|
||||
)
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-twist.js')
|
||||
.addIncludeFile('Extensions/Effects/twist-pixi-filter.js');
|
||||
.addIncludeFile('Extensions/Effects/twist-pixi-filter.js')
|
||||
.markAsNotWorkingForObjects(); // See https://github.com/pixijs/filters/issues/304
|
||||
const twistProperties = twistEffect.getProperties();
|
||||
twistProperties
|
||||
.getOrCreate('radius')
|
||||
@@ -1120,7 +1122,8 @@ module.exports = {
|
||||
.setFullName(_('Zoom blur'))
|
||||
.setDescription(_('Applies a Zoom blur.'))
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-zoom-blur.js')
|
||||
.addIncludeFile('Extensions/Effects/zoom-blur-pixi-filter.js');
|
||||
.addIncludeFile('Extensions/Effects/zoom-blur-pixi-filter.js')
|
||||
.markAsNotWorkingForObjects(); // See https://github.com/pixijs/filters/issues/304
|
||||
const zoomBlurProperties = zoomBlurEffect.getProperties();
|
||||
zoomBlurProperties
|
||||
.getOrCreate('centerX')
|
||||
|
@@ -1,10 +1,10 @@
|
||||
namespace gdjs {
|
||||
gdjs.PixiFiltersTools.registerFilterCreator('Adjustment', {
|
||||
makePIXIFilter: function (layer, effectData) {
|
||||
makePIXIFilter: function (target, effectData) {
|
||||
const adjustmentFilter = new PIXI.filters.AdjustmentFilter();
|
||||
return adjustmentFilter;
|
||||
},
|
||||
update: function (filter, layer) {},
|
||||
updatePreRender: function (filter, target) {},
|
||||
updateDoubleParameter: function (filter, parameterName, value) {
|
||||
const adjustmentFilter = (filter as unknown) as PIXI.filters.AdjustmentFilter;
|
||||
if (parameterName === 'gamma') {
|
||||
|
@@ -1,10 +1,10 @@
|
||||
namespace gdjs {
|
||||
gdjs.PixiFiltersTools.registerFilterCreator('AdvancedBloom', {
|
||||
makePIXIFilter: function (layer, effectData) {
|
||||
makePIXIFilter: function (target, effectData) {
|
||||
const advancedBloomFilter = new PIXI.filters.AdvancedBloomFilter();
|
||||
return advancedBloomFilter;
|
||||
},
|
||||
update: function (filter, layer) {},
|
||||
updatePreRender: function (filter, target) {},
|
||||
updateDoubleParameter: function (filter, parameterName, value) {
|
||||
const advancedBloomFilter = (filter as unknown) as PIXI.filters.AdvancedBloomFilter;
|
||||
if (parameterName === 'threshold') {
|
||||
|
@@ -1,10 +1,10 @@
|
||||
namespace gdjs {
|
||||
gdjs.PixiFiltersTools.registerFilterCreator('Ascii', {
|
||||
makePIXIFilter: function (layer, effectData) {
|
||||
makePIXIFilter: function (target, effectData) {
|
||||
const asciiFilter = new PIXI.filters.AsciiFilter();
|
||||
return asciiFilter;
|
||||
},
|
||||
update: function (filter, layer) {},
|
||||
updatePreRender: function (filter, target) {},
|
||||
updateDoubleParameter: function (filter, parameterName, value) {
|
||||
const asciiFilter = (filter as unknown) as PIXI.filters.AsciiFilter;
|
||||
if (parameterName === 'size') {
|
||||
|
@@ -1,10 +1,10 @@
|
||||
namespace gdjs {
|
||||
gdjs.PixiFiltersTools.registerFilterCreator('Bevel', {
|
||||
makePIXIFilter: function (layer, effectData) {
|
||||
makePIXIFilter: function (target, effectData) {
|
||||
const bevelFilter = new PIXI.filters.BevelFilter();
|
||||
return bevelFilter;
|
||||
},
|
||||
update: function (filter, layer) {},
|
||||
updatePreRender: function (filter, target) {},
|
||||
updateDoubleParameter: function (filter, parameterName, value) {
|
||||
const bevelFilter = (filter as unknown) as PIXI.filters.BevelFilter;
|
||||
if (parameterName === 'rotation') {
|
||||
|
@@ -1,12 +1,12 @@
|
||||
namespace gdjs {
|
||||
import PIXI = GlobalPIXIModule.PIXI;
|
||||
gdjs.PixiFiltersTools.registerFilterCreator('BlackAndWhite', {
|
||||
makePIXIFilter: function (layer, effectData) {
|
||||
makePIXIFilter: function (target, effectData) {
|
||||
const colorMatrix = new PIXI.filters.ColorMatrixFilter();
|
||||
colorMatrix.blackAndWhite(false);
|
||||
return colorMatrix;
|
||||
},
|
||||
update: function (filter, layer) {},
|
||||
updatePreRender: function (filter, target) {},
|
||||
updateDoubleParameter: function (filter, parameterName, value) {
|
||||
// @ts-ignore - unsure why PIXI.filters is not recognised.
|
||||
const colorMatrix = (filter as unknown) as PIXI.filters.ColorMatrixFilter;
|
||||
|
@@ -1,11 +1,11 @@
|
||||
namespace gdjs {
|
||||
import PIXI = GlobalPIXIModule.PIXI;
|
||||
gdjs.PixiFiltersTools.registerFilterCreator('BlendingMode', {
|
||||
makePIXIFilter: function (layer, effectData) {
|
||||
makePIXIFilter: function (target, effectData) {
|
||||
const blendingModeFilter = new PIXI.filters.AlphaFilter();
|
||||
return blendingModeFilter;
|
||||
},
|
||||
update: function (filter, layer) {},
|
||||
updatePreRender: function (filter, target) {},
|
||||
updateDoubleParameter: function (filter, parameterName, value) {
|
||||
// @ts-ignore - unsure why PIXI.filters is not recognised.
|
||||
const blendingModeFilter = (filter as unknown) as PIXI.filters.AlphaFilter;
|
||||
|
@@ -1,11 +1,11 @@
|
||||
namespace gdjs {
|
||||
import PIXI = GlobalPIXIModule.PIXI;
|
||||
gdjs.PixiFiltersTools.registerFilterCreator('Blur', {
|
||||
makePIXIFilter: function (layer, effectData) {
|
||||
makePIXIFilter: function (target, effectData) {
|
||||
const blur = new PIXI.filters.BlurFilter();
|
||||
return blur;
|
||||
},
|
||||
update: function (filter, layer) {},
|
||||
updatePreRender: function (filter, target) {},
|
||||
updateDoubleParameter: function (filter, parameterName, value) {
|
||||
if (
|
||||
parameterName !== 'blur' &&
|
||||
|
@@ -1,12 +1,12 @@
|
||||
namespace gdjs {
|
||||
import PIXI = GlobalPIXIModule.PIXI;
|
||||
gdjs.PixiFiltersTools.registerFilterCreator('Brightness', {
|
||||
makePIXIFilter: function (layer, effectData) {
|
||||
makePIXIFilter: function (target, effectData) {
|
||||
const brightness = new PIXI.filters.ColorMatrixFilter();
|
||||
brightness.brightness(1, false);
|
||||
return brightness;
|
||||
},
|
||||
update: function (filter, layer) {},
|
||||
updatePreRender: function (filter, target) {},
|
||||
updateDoubleParameter: function (filter, parameterName, value) {
|
||||
// @ts-ignore - unsure why PIXI.filters is not recognised.
|
||||
const brightnessFilter = (filter as unknown) as PIXI.filters.ColorMatrixFilter;
|
||||
|
@@ -1,10 +1,10 @@
|
||||
namespace gdjs {
|
||||
gdjs.PixiFiltersTools.registerFilterCreator('BulgePinch', {
|
||||
makePIXIFilter: function (layer, effectData) {
|
||||
makePIXIFilter: function (target, effectData) {
|
||||
const bulgePinchFilter = new PIXI.filters.BulgePinchFilter();
|
||||
return bulgePinchFilter;
|
||||
},
|
||||
update: function (filter, layer) {},
|
||||
updatePreRender: function (filter, target) {},
|
||||
updateDoubleParameter: function (filter, parameterName, value) {
|
||||
const bulgePinchFilter = (filter as unknown) as PIXI.filters.BulgePinchFilter;
|
||||
if (parameterName === 'centerX') {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
namespace gdjs {
|
||||
gdjs.PixiFiltersTools.registerFilterCreator('ColorMap', {
|
||||
makePIXIFilter: function (layer, effectData) {
|
||||
const colorMapTexture = layer
|
||||
makePIXIFilter: function (target, effectData) {
|
||||
const colorMapTexture = target
|
||||
.getRuntimeScene()
|
||||
.getGame()
|
||||
.getImageManager()
|
||||
@@ -17,7 +17,7 @@ namespace gdjs {
|
||||
);
|
||||
return colorMapFilter;
|
||||
},
|
||||
update: function (filter, layer) {},
|
||||
updatePreRender: function (filter, target) {},
|
||||
updateDoubleParameter: function (filter, parameterName, value) {
|
||||
const colorMapFilter = (filter as unknown) as PIXI.filters.ColorMapFilter;
|
||||
if (parameterName === 'mix') {
|
||||
|
@@ -1,10 +1,10 @@
|
||||
namespace gdjs {
|
||||
gdjs.PixiFiltersTools.registerFilterCreator('ColorReplace', {
|
||||
makePIXIFilter: function (layer, effectData) {
|
||||
makePIXIFilter: function (target, effectData) {
|
||||
const colorReplaceFilter = new PIXI.filters.ColorReplaceFilter();
|
||||
return colorReplaceFilter;
|
||||
},
|
||||
update: function (filter, layer) {},
|
||||
updatePreRender: function (filter, target) {},
|
||||
updateDoubleParameter: function (filter, parameterName, value) {
|
||||
const colorReplaceFilter = (filter as unknown) as PIXI.filters.ColorReplaceFilter;
|
||||
if (parameterName === 'epsilon') {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user