mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
137 Commits
v5.0.0-bet
...
v5.0.122-b
Author | SHA1 | Date | |
---|---|---|---|
![]() |
36fb4ec9b2 | ||
![]() |
124e1f3683 | ||
![]() |
9c350729a8 | ||
![]() |
9186daa782 | ||
![]() |
c6161c4752 | ||
![]() |
5d3f207216 | ||
![]() |
cf462f6c6e | ||
![]() |
bc979031e3 | ||
![]() |
406bae5e12 | ||
![]() |
5f5f50e039 | ||
![]() |
394fb4c587 | ||
![]() |
599d48afca | ||
![]() |
bccef185cb | ||
![]() |
d0f4370026 | ||
![]() |
77d6f0310c | ||
![]() |
c73a5a046f | ||
![]() |
c37e129a5b | ||
![]() |
aeecb0e29f | ||
![]() |
a6525e5617 | ||
![]() |
f67aeedaeb | ||
![]() |
0c2f023c63 | ||
![]() |
d6d4569dbf | ||
![]() |
965ec330cf | ||
![]() |
c09d29a959 | ||
![]() |
67612009d1 | ||
![]() |
2da5194672 | ||
![]() |
7f5821a299 | ||
![]() |
a3fdeec6a7 | ||
![]() |
852ad1d92b | ||
![]() |
8fdba503ab | ||
![]() |
50d7bec375 | ||
![]() |
0c85e9bf30 | ||
![]() |
08c41ece71 | ||
![]() |
bd9fffba3f | ||
![]() |
413caf6f62 | ||
![]() |
530d0baffe | ||
![]() |
e78d2c6962 | ||
![]() |
bc606ed1be | ||
![]() |
c705f89de8 | ||
![]() |
3b73b5eb6d | ||
![]() |
107410f0a4 | ||
![]() |
b7b95d5e09 | ||
![]() |
a470e9b86c | ||
![]() |
cf5c8ae631 | ||
![]() |
8f8ac2fd1e | ||
![]() |
cdac70425e | ||
![]() |
378f0a48ad | ||
![]() |
e653639366 | ||
![]() |
e105d4c9f6 | ||
![]() |
5b80bed305 | ||
![]() |
a4ac323e63 | ||
![]() |
bc23d6a084 | ||
![]() |
2c24359fba | ||
![]() |
a6b01fc01d | ||
![]() |
44b81f52ea | ||
![]() |
cfdf13538e | ||
![]() |
7ee38a50bf | ||
![]() |
e2b8620b83 | ||
![]() |
7ed8660edc | ||
![]() |
75cc70368c | ||
![]() |
0d3dfe5cf4 | ||
![]() |
e7aa75bcd7 | ||
![]() |
c5ad127e83 | ||
![]() |
acfdebfc0f | ||
![]() |
d3f8b410b0 | ||
![]() |
4b7d67ce97 | ||
![]() |
46a81ef4be | ||
![]() |
fe2812b8e8 | ||
![]() |
042cf49b3b | ||
![]() |
7cf334ad1c | ||
![]() |
f999bee387 | ||
![]() |
0627d4b865 | ||
![]() |
92e6a5e67f | ||
![]() |
d980400c2b | ||
![]() |
e235694fac | ||
![]() |
cdf00d10f1 | ||
![]() |
218520b836 | ||
![]() |
3ce71813ba | ||
![]() |
90300f895c | ||
![]() |
9c8aa57fb6 | ||
![]() |
84876a1dff | ||
![]() |
19ef8742f0 | ||
![]() |
567efafa70 | ||
![]() |
c70685ccc7 | ||
![]() |
ec8daa7d8d | ||
![]() |
0d817f4dae | ||
![]() |
9dbbaada01 | ||
![]() |
342a6dc56f | ||
![]() |
baae910fe8 | ||
![]() |
2c6d30b28e | ||
![]() |
9321f0ec7c | ||
![]() |
e463f352b7 | ||
![]() |
5e3430aea5 | ||
![]() |
2d899d7c52 | ||
![]() |
0b933a569e | ||
![]() |
4904e7e7fb | ||
![]() |
bfb1b6b15d | ||
![]() |
9364a485cd | ||
![]() |
176a2a0b47 | ||
![]() |
a10c9362dd | ||
![]() |
3a0f55ee1b | ||
![]() |
0b6bddc5a4 | ||
![]() |
bf910e0cba | ||
![]() |
763d8e8175 | ||
![]() |
135ba2b4df | ||
![]() |
d4a3722ec8 | ||
![]() |
477e88d4ce | ||
![]() |
023ed8f7b5 | ||
![]() |
55020a3d15 | ||
![]() |
552219e48f | ||
![]() |
4dfac41d81 | ||
![]() |
33deca92e3 | ||
![]() |
adc7584981 | ||
![]() |
23d5296a52 | ||
![]() |
2febbf439f | ||
![]() |
169a49a246 | ||
![]() |
c8c4322ece | ||
![]() |
349703e287 | ||
![]() |
1326ffd3b6 | ||
![]() |
baff4d3cb0 | ||
![]() |
b40e2d3fdf | ||
![]() |
8e6ba3abce | ||
![]() |
aaebbe47d5 | ||
![]() |
a51003040c | ||
![]() |
cfce635419 | ||
![]() |
3d299c5a14 | ||
![]() |
f33196dc85 | ||
![]() |
7b2dc2223c | ||
![]() |
b37d05f78c | ||
![]() |
dcba0b45a6 | ||
![]() |
f2ec46ca1e | ||
![]() |
5c33e9e8d0 | ||
![]() |
fc23517bae | ||
![]() |
24c74af79b | ||
![]() |
2a19ea5182 | ||
![]() |
705c7af134 | ||
![]() |
028eebefab |
15
.github/stale.yml
vendored
Normal file
15
.github/stale.yml
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# Automatically close issues with certain tags indicating that we need more information,
|
||||
# after some days have passed.
|
||||
|
||||
daysUntilStale: 20
|
||||
daysUntilClose: 7
|
||||
|
||||
# Only do this on tags implying we need more information:
|
||||
onlyLabels: ["Need a game/precise steps to reproduce the issue","👋 Needs confirmation/testing"]
|
||||
only: issues
|
||||
|
||||
markComment: >
|
||||
This issue seems to be stale: it needs additional information but it has not had
|
||||
recent activity. It will be closed in 7 days if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
|
71
.github/workflows/build-storybook.yml
vendored
Normal file
71
.github/workflows/build-storybook.yml
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
# GitHub Action to build the Storybook of the editor and publish it for testing.
|
||||
#
|
||||
# Note that only the Storybook is built and GDevelop.js is not rebuilt (for speed concerns),
|
||||
# so changes in the C++ source could not be reflected if the CI run by Travis-CI
|
||||
# did not upload a freshly built GDevelop.js.
|
||||
|
||||
name: Build Storybook
|
||||
|
||||
on:
|
||||
# Launch on all commits.
|
||||
push:
|
||||
# Allows to run this workflow manually from the Actions tab,
|
||||
# to publish on Chromatic (not done by default).
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-storybook:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Configure AWS Credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1
|
||||
with:
|
||||
aws-access-key-id: ${{ secrets.BUILD_STORYBOOK_AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.BUILD_STORYBOOK_AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: us-east-1
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 50
|
||||
|
||||
# Cache npm dependencies to speed up the workflow
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v2
|
||||
env:
|
||||
cache-name: cache-newIDE-app-node_modules
|
||||
with:
|
||||
# npm cache files are stored in `~/.npm` on Linux/macOS
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('newIDE/app/package-lock.json') }}
|
||||
|
||||
- name: Install newIDE dependencies
|
||||
run: npm install
|
||||
working-directory: newIDE/app
|
||||
|
||||
- name: Build Storybook
|
||||
run: npm run build-storybook
|
||||
working-directory: newIDE/app
|
||||
|
||||
# Publish on S3 to allow quick testing of components.
|
||||
- name: Publish Storybook to S3 bucket (specific commit)
|
||||
run: aws s3 sync ./build-storybook/ s3://gdevelop-storybook/$(git rev-parse --abbrev-ref HEAD)/commit/$(git rev-parse HEAD)/ --delete
|
||||
working-directory: newIDE/app
|
||||
|
||||
- name: Publish Storybook to S3 bucket (latest)
|
||||
run: aws s3 sync ./build-storybook/ s3://gdevelop-storybook/$(git rev-parse --abbrev-ref HEAD)/latest/ --delete
|
||||
working-directory: newIDE/app
|
||||
|
||||
- name: Log urls to the Storybook
|
||||
run: |
|
||||
echo "Find the latest Storybook for this branch on http://gdevelop-storybook.s3-website-us-east-1.amazonaws.com/$(git rev-parse --abbrev-ref HEAD)/latest/index.html"
|
||||
echo "Find the Storybook for this commit on http://gdevelop-storybook.s3-website-us-east-1.amazonaws.com/$(git rev-parse --abbrev-ref HEAD)/commit/$(git rev-parse HEAD)/index.html"
|
||||
|
||||
# Publish on Chromatic, only when manually launched (too costly to run on every commit).
|
||||
- name: Publish Storybook to Chromatic
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
uses: chromaui/action@v1
|
||||
with:
|
||||
workingDir: newIDE/app
|
||||
storybookBuildDir: "build-storybook"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
47
.github/workflows/extract-translations.yml
vendored
Normal file
47
.github/workflows/extract-translations.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
# GitHub Action to extract translations and (later) upload them to Crowdin.
|
||||
|
||||
name: Extract translations
|
||||
on:
|
||||
# Execute for all commits (to ensure translations extraction works)
|
||||
push:
|
||||
# Allows to run this workflow manually from the Actions tab.
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
extract-translations:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
# Cache npm dependencies to speed up the workflow
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v2
|
||||
env:
|
||||
cache-name: cache-newIDE-app-node_modules
|
||||
with:
|
||||
# npm cache files are stored in `~/.npm` on Linux/macOS
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('newIDE/app/package-lock.json') }}
|
||||
|
||||
- name: Install gettext
|
||||
run: sudo apt update && sudo apt install gettext -y
|
||||
|
||||
- name: Install newIDE dependencies
|
||||
run: npm install
|
||||
working-directory: newIDE/app
|
||||
|
||||
- name: Extract translations
|
||||
run: npm run extract-all-translations
|
||||
working-directory: newIDE/app
|
||||
|
||||
# Only upload on Crowdin for the master branch
|
||||
- name: Install Crowdin CLI
|
||||
if: github.ref == 'refs/heads/master'
|
||||
run: npm i -g @crowdin/cli
|
||||
|
||||
- name: Upload translations to Crowdin
|
||||
run: crowdin upload sources
|
||||
if: github.ref == 'refs/heads/master'
|
||||
env:
|
||||
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
|
||||
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
73
.github/workflows/update-translations.yml
vendored
Normal file
73
.github/workflows/update-translations.yml
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
# GitHub Action to update translations by downloading them from Crowdin,
|
||||
# and open a Pull Request with the changes.
|
||||
|
||||
name: Update translations
|
||||
on:
|
||||
# Execute only on master
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
# Allows to run this workflow manually from the Actions tab.
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
update-translations:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
# Cache npm dependencies to speed up the workflow
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v2
|
||||
env:
|
||||
cache-name: cache-newIDE-app-node_modules
|
||||
with:
|
||||
# npm cache files are stored in `~/.npm` on Linux/macOS
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('newIDE/app/package-lock.json') }}
|
||||
|
||||
- name: Install gettext
|
||||
run: sudo apt update && sudo apt install gettext -y
|
||||
|
||||
- name: Install newIDE dependencies
|
||||
run: npm install
|
||||
working-directory: newIDE/app
|
||||
|
||||
# We need to extract translations first to make sure all the source strings
|
||||
# are included in the English catalogs. Otherwise, missing source strings
|
||||
# with parameters (like "My name is {0}.") would be shown as-is when
|
||||
# the app is built (but not in development - unclear why, LinguiJS issue?).
|
||||
- name: Extract translations
|
||||
run: npm run extract-all-translations
|
||||
working-directory: newIDE/app
|
||||
|
||||
# (Build and) download the most recent translations (PO files) from Crowdin.
|
||||
- name: Install Crowdin CLI
|
||||
run: npm i -g @crowdin/cli
|
||||
|
||||
- name: Download new translations from Crowdin
|
||||
run: crowdin download
|
||||
env:
|
||||
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
|
||||
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
||||
|
||||
# Seems like the three letters code is not handled properly by LinguiJS?
|
||||
# Do without this language while we find a solution.
|
||||
- name: Remove catalogs not handled properly by LinguiJS compile command.
|
||||
run: rm -rf newIDE/app/src/locales/pcm_NG/
|
||||
|
||||
- name: Compile translations into .js files that are read by LinguiJS
|
||||
run: npm run compile-translations
|
||||
working-directory: newIDE/app
|
||||
|
||||
- name: Create a Pull Request with the changes
|
||||
uses: peter-evans/create-pull-request@v3.10.1
|
||||
with:
|
||||
commit-message: Update translations [skip ci]
|
||||
branch: chore/update-translations
|
||||
delete-branch: true
|
||||
title: '[Auto PR] Update translations'
|
||||
body: |
|
||||
This updates the translations by downloading them from Crowdin and compiling them for usage by the app.
|
||||
|
||||
Please double check the values in `newIDE/app/src/locales/LocalesMetadata.js` to ensure the changes are sensible.
|
@@ -14,25 +14,26 @@ blocks:
|
||||
- name: Install node_modules and cache them
|
||||
commands:
|
||||
- checkout
|
||||
- node -v
|
||||
- node -v && npm -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
|
||||
npm ci
|
||||
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
|
||||
git checkout package-lock.json # Ensure no changes was made by newIDE post-install tasks.
|
||||
npm ci
|
||||
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
|
||||
npm ci
|
||||
cd ../..
|
||||
cache store GDJS-tests-node_modules-$SEMAPHORE_GIT_BRANCH-revision-$(checksum GDJS/tests/package-lock.json) GDJS/tests/node_modules
|
||||
fi
|
||||
@@ -50,6 +51,7 @@ blocks:
|
||||
- cd newIDE/app
|
||||
- npm run postinstall
|
||||
- npm run flow
|
||||
- npm run check-script-types
|
||||
- cd ../..
|
||||
- name: GDJS typing and documentation generation
|
||||
commands:
|
||||
|
@@ -102,6 +102,7 @@ script:
|
||||
- npm test
|
||||
- npm run flow
|
||||
- npm run check-format
|
||||
- npm run check-script-types
|
||||
- cd ../..
|
||||
# GDJS tests:
|
||||
- cd GDJS
|
||||
|
29
.vscode/launch.json
vendored
29
.vscode/launch.json
vendored
@@ -4,13 +4,36 @@
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "GDevelop.js Jest tests (all)",
|
||||
"program": "${workspaceFolder}/GDevelop.js/node_modules/.bin/jest",
|
||||
"args": ["--runInBand"],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen",
|
||||
"disableOptimisticBPs": true,
|
||||
"cwd": "${workspaceFolder}/GDevelop.js"
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "GDevelop.js Jest tests (current file)",
|
||||
"program": "${workspaceFolder}/GDevelop.js/node_modules/.bin/jest",
|
||||
"args": [
|
||||
"${fileBasenameNoExtension}"
|
||||
],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen",
|
||||
"disableOptimisticBPs": true,
|
||||
"cwd": "${workspaceFolder}/GDevelop.js"
|
||||
},
|
||||
{
|
||||
"type": "pwa-chrome",
|
||||
"request": "launch",
|
||||
"name": "Launch Chrome against localhost",
|
||||
"name": "Debug with Chrome (web-app, local development server)",
|
||||
"url": "http://localhost:3000",
|
||||
"webRoot": "${workspaceFolder}",
|
||||
"preLaunchTask": "Start development server"
|
||||
"webRoot": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
2
.vscode/tasks.json
vendored
2
.vscode/tasks.json
vendored
@@ -80,7 +80,7 @@
|
||||
},
|
||||
{
|
||||
"type": "typescript",
|
||||
"tsconfig": "GDJS/tsconfig.json",
|
||||
"tsconfig": "tsconfig.json",
|
||||
"option": "watch",
|
||||
"problemMatcher": ["$tsc-watch"],
|
||||
"group": "test",
|
||||
|
@@ -47,7 +47,6 @@ IF(APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_WCHAR_H_CPLUSPLUS_98_CONFORMANCE_")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-potentially-evaluated-expression")
|
||||
ENDIF()
|
||||
|
||||
#Sanity checks
|
||||
IF ("${CMAKE_BUILD_TYPE}" STREQUAL "")
|
||||
message( "CMAKE_BUILD_TYPE is empty, assuming build type is Release" )
|
||||
@@ -72,6 +71,13 @@ endif()
|
||||
|
||||
# Mark some warnings as errors
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
# Activate as much warnings as possible to avoid errors like
|
||||
# uninitialized variables or other hard to debug bugs.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-warning-option")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-reorder-ctor -Wno-reorder -Wno-pessimizing-move -Wno-unused-variable -Wno-unused-private-field")
|
||||
|
||||
# Make as much warnings considered as errors as possible (only one for now).
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=return-stack-address")
|
||||
endif()
|
||||
|
||||
|
@@ -37,7 +37,7 @@ void ExposeProjectEffects(
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t i; i < layout.GetObjectsCount(); i++) {
|
||||
for (std::size_t i = 0; i < layout.GetObjectsCount(); i++) {
|
||||
auto& object = layout.GetObject(i);
|
||||
auto& effects = object.GetEffects();
|
||||
for (std::size_t e = 0; e < effects.GetEffectsCount(); e++) {
|
||||
|
@@ -621,8 +621,14 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
argOutput = GenerateGetBehaviorNameCode(parameter);
|
||||
} else if (metadata.type == "key") {
|
||||
argOutput = "\"" + ConvertToString(parameter) + "\"";
|
||||
} else if (metadata.type == "password" || metadata.type == "musicfile" ||
|
||||
metadata.type == "soundfile" || metadata.type == "police") {
|
||||
} else if (metadata.type == "password" || // Deprecated
|
||||
metadata.type ==
|
||||
"musicfile" || // Should be renamed "largeAudioResource"
|
||||
metadata.type ==
|
||||
"soundfile" || // Should be renamed "audioResource"
|
||||
metadata.type == "police" || // Should be renamed "fontResource"
|
||||
metadata.type == "bitmapFontResource" ||
|
||||
metadata.type == "imageResource") {
|
||||
argOutput = "\"" + ConvertToString(parameter) + "\"";
|
||||
} else if (metadata.type == "mouse") {
|
||||
argOutput = "\"" + ConvertToString(parameter) + "\"";
|
||||
|
@@ -67,13 +67,13 @@ class GD_CORE_API ExpressionParser2 {
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an object name (or empty if none) and a behavior name (or empty if none),
|
||||
* return the index of the first parameter that is inside the parenthesis:
|
||||
* 0, 1 or 2.
|
||||
*
|
||||
* For example, in an expression like `Object.MyBehavior::Method("hello")`, the
|
||||
* parameter "hello" is the second parameter (the first being by convention Object,
|
||||
* and the second MyBehavior, also by convention).
|
||||
* Given an object name (or empty if none) and a behavior name (or empty if
|
||||
* none), return the index of the first parameter that is inside the
|
||||
* parenthesis: 0, 1 or 2.
|
||||
*
|
||||
* For example, in an expression like `Object.MyBehavior::Method("hello")`,
|
||||
* the parameter "hello" is the second parameter (the first being by
|
||||
* convention Object, and the second MyBehavior, also by convention).
|
||||
*/
|
||||
static size_t WrittenParametersFirstIndex(const gd::String &objectName,
|
||||
const gd::String &behaviorName) {
|
||||
@@ -403,9 +403,18 @@ class GD_CORE_API ExpressionParser2 {
|
||||
const gd::ExpressionMetadata &metadata =
|
||||
MetadataProvider::GetAnyExpressionMetadata(platform, functionFullName);
|
||||
|
||||
// In case we can't find a valid expression, ensure the node has the type
|
||||
// that is requested by the parent, so we avoid putting "unknown" (which
|
||||
// would be also correct, but less precise and would prevent completions to
|
||||
// be shown to the user)
|
||||
const gd::String returnType =
|
||||
gd::MetadataProvider::IsBadExpressionMetadata(metadata) == true
|
||||
? type
|
||||
: metadata.GetReturnType();
|
||||
|
||||
auto parametersNode = Parameters(metadata.parameters);
|
||||
auto function =
|
||||
gd::make_unique<FunctionCallNode>(metadata.GetReturnType(),
|
||||
gd::make_unique<FunctionCallNode>(returnType,
|
||||
std::move(parametersNode.parameters),
|
||||
metadata,
|
||||
functionFullName);
|
||||
@@ -458,9 +467,18 @@ class GD_CORE_API ExpressionParser2 {
|
||||
MetadataProvider::GetObjectAnyExpressionMetadata(
|
||||
platform, objectType, objectFunctionOrBehaviorName);
|
||||
|
||||
// In case we can't find a valid expression, ensure the node has the type
|
||||
// that is requested by the parent, so we avoid putting "unknown" (which
|
||||
// would be also correct, but less precise and would prevent completions
|
||||
// to be shown to the user)
|
||||
const gd::String returnType =
|
||||
gd::MetadataProvider::IsBadExpressionMetadata(metadata) == true
|
||||
? type
|
||||
: metadata.GetReturnType();
|
||||
|
||||
auto parametersNode = Parameters(metadata.parameters, objectName);
|
||||
auto function = gd::make_unique<FunctionCallNode>(
|
||||
metadata.GetReturnType(),
|
||||
returnType,
|
||||
objectName,
|
||||
std::move(parametersNode.parameters),
|
||||
metadata,
|
||||
@@ -520,10 +538,19 @@ class GD_CORE_API ExpressionParser2 {
|
||||
MetadataProvider::GetBehaviorAnyExpressionMetadata(
|
||||
platform, behaviorType, functionName);
|
||||
|
||||
// In case we can't find a valid expression, ensure the node has the type
|
||||
// that is requested by the parent, so we avoid putting "unknown" (which
|
||||
// would be also correct, but less precise and would prevent completions
|
||||
// to be shown to the user)
|
||||
const gd::String returnType =
|
||||
gd::MetadataProvider::IsBadExpressionMetadata(metadata) == true
|
||||
? type
|
||||
: metadata.GetReturnType();
|
||||
|
||||
auto parametersNode =
|
||||
Parameters(metadata.parameters, objectName, behaviorName);
|
||||
auto function = gd::make_unique<FunctionCallNode>(
|
||||
metadata.GetReturnType(),
|
||||
returnType,
|
||||
objectName,
|
||||
behaviorName,
|
||||
std::move(parametersNode.parameters),
|
||||
|
@@ -43,6 +43,7 @@ struct ExpressionParserLocation {
|
||||
* \brief A diagnostic that can be attached to a gd::ExpressionNode.
|
||||
*/
|
||||
struct ExpressionParserDiagnostic {
|
||||
virtual ~ExpressionParserDiagnostic() = default;
|
||||
virtual bool IsError() { return false; }
|
||||
virtual const gd::String &GetMessage() { return noMessage; }
|
||||
virtual size_t GetStartPosition() { return 0; }
|
||||
|
@@ -7,21 +7,21 @@
|
||||
#define GDCORE_EXPRESSIONPARSER2NODEWORKER_H
|
||||
|
||||
namespace gd {
|
||||
class ExpressionNode;
|
||||
class SubExpressionNode;
|
||||
class OperatorNode;
|
||||
class UnaryOperatorNode;
|
||||
class NumberNode;
|
||||
class TextNode;
|
||||
class VariableNode;
|
||||
class VariableAccessorNode;
|
||||
class VariableBracketAccessorNode;
|
||||
class IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode;
|
||||
class IdentifierNode;
|
||||
class FunctionCallOrObjectFunctionNameOrEmptyNode;
|
||||
class ObjectFunctionNameNode;
|
||||
class FunctionCallNode;
|
||||
class EmptyNode;
|
||||
struct ExpressionNode;
|
||||
struct SubExpressionNode;
|
||||
struct OperatorNode;
|
||||
struct UnaryOperatorNode;
|
||||
struct NumberNode;
|
||||
struct TextNode;
|
||||
struct VariableNode;
|
||||
struct VariableAccessorNode;
|
||||
struct VariableBracketAccessorNode;
|
||||
struct IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode;
|
||||
struct IdentifierNode;
|
||||
struct FunctionCallOrObjectFunctionNameOrEmptyNode;
|
||||
struct ObjectFunctionNameNode;
|
||||
struct FunctionCallNode;
|
||||
struct EmptyNode;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
@@ -34,21 +34,21 @@ namespace gd {
|
||||
* \see gd::ExpressionNode
|
||||
*/
|
||||
class GD_CORE_API ExpressionParser2NodeWorker {
|
||||
friend class ExpressionNode;
|
||||
friend class SubExpressionNode;
|
||||
friend class OperatorNode;
|
||||
friend class UnaryOperatorNode;
|
||||
friend class NumberNode;
|
||||
friend class TextNode;
|
||||
friend class VariableNode;
|
||||
friend class VariableAccessorNode;
|
||||
friend class VariableBracketAccessorNode;
|
||||
friend class IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode;
|
||||
friend class IdentifierNode;
|
||||
friend class FunctionCallOrObjectFunctionNameOrEmptyNode;
|
||||
friend class ObjectFunctionNameNode;
|
||||
friend class FunctionCallNode;
|
||||
friend class EmptyNode;
|
||||
friend struct ExpressionNode;
|
||||
friend struct SubExpressionNode;
|
||||
friend struct OperatorNode;
|
||||
friend struct UnaryOperatorNode;
|
||||
friend struct NumberNode;
|
||||
friend struct TextNode;
|
||||
friend struct VariableNode;
|
||||
friend struct VariableAccessorNode;
|
||||
friend struct VariableBracketAccessorNode;
|
||||
friend struct IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode;
|
||||
friend struct IdentifierNode;
|
||||
friend struct FunctionCallOrObjectFunctionNameOrEmptyNode;
|
||||
friend struct ObjectFunctionNameNode;
|
||||
friend struct FunctionCallNode;
|
||||
friend struct EmptyNode;
|
||||
|
||||
public:
|
||||
virtual ~ExpressionParser2NodeWorker();
|
||||
|
@@ -18,7 +18,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)");
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
extension
|
||||
.AddCondition("Toujours",
|
||||
_("Always"),
|
||||
@@ -104,7 +103,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
|
||||
_("Functions"),
|
||||
"res/function16.png")
|
||||
.AddParameter("string", "Parameter name");
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -21,7 +21,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/all-features/audio");
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
extension
|
||||
.AddAction("PlaySoundCanal",
|
||||
_("Play a sound on a channel"),
|
||||
@@ -579,7 +578,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
|
||||
"res/conditions/volume.png")
|
||||
.AddCodeOnlyParameter("currentScene", "");
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -25,7 +25,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
gd::ObjectMetadata& obj = extension.AddObject<gd::Object>(
|
||||
"", _("Base object"), _("Base object"), "res/objeticon24.png");
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
obj.AddCondition("PosX",
|
||||
_("X position"),
|
||||
_("Compare the X position of the object."),
|
||||
@@ -84,9 +83,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"res/actions/position.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("operator", _("Modification's sign"), "number")
|
||||
.AddParameter("expression", _("X position"))
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("operator", _("Modification's sign"), "number")
|
||||
.AddParameter("expression", _("Y position"))
|
||||
.MarkAsSimple();
|
||||
|
||||
@@ -99,9 +98,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"res/actions/position24.png",
|
||||
"res/actions/position.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("operator", _("Modification's sign"), "number")
|
||||
.AddParameter("expression", _("X position"))
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("operator", _("Modification's sign"), "number")
|
||||
.AddParameter("expression", _("Y position"))
|
||||
.MarkAsSimple();
|
||||
|
||||
@@ -1080,7 +1079,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("string", _("Effect Name"))
|
||||
.AddParameter("objectEffectName", _("Effect name"))
|
||||
.AddParameter("yesorno", _("Enable?"))
|
||||
.MarkAsSimple();
|
||||
|
||||
@@ -1094,8 +1093,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("string", _("Effect Name"))
|
||||
.AddParameter("string", _("Parameter name"))
|
||||
.AddParameter("objectEffectName", _("Effect name"))
|
||||
.AddParameter("objectEffectParameterName", _("Parameter name"))
|
||||
.AddParameter("expression", _("New value"))
|
||||
.MarkAsSimple();
|
||||
|
||||
@@ -1109,8 +1108,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("string", _("Effect Name"))
|
||||
.AddParameter("string", _("Parameter name"))
|
||||
.AddParameter("objectEffectName", _("Effect name"))
|
||||
.AddParameter("objectEffectParameterName", _("Parameter name"))
|
||||
.AddParameter("string", _("New value"))
|
||||
.MarkAsSimple();
|
||||
|
||||
@@ -1124,8 +1123,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("string", _("Effect Name"))
|
||||
.AddParameter("string", _("Parameter Name"))
|
||||
.AddParameter("objectEffectName", _("Effect name"))
|
||||
.AddParameter("objectEffectParameterName", _("Parameter name"))
|
||||
.AddParameter("yesorno", _("Enable?"))
|
||||
.MarkAsSimple();
|
||||
|
||||
@@ -1137,7 +1136,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("string", _("Effect Name"))
|
||||
.AddParameter("objectEffectName", _("Effect name"))
|
||||
.MarkAsSimple();
|
||||
|
||||
extension
|
||||
@@ -1441,7 +1440,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Objects"),
|
||||
"res/actions/layer.png")
|
||||
.AddParameter("object", _("Object"));
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -24,7 +24,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/interface/scene-editor/layers-and-cameras");
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
extension
|
||||
.AddExpressionAndConditionAndAction(
|
||||
"number",
|
||||
@@ -342,8 +341,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("string", _("Effect"))
|
||||
.AddParameter("string", _("Parameter name"))
|
||||
.AddParameter("layerEffectName", _("Effect name"))
|
||||
.AddParameter("layerEffectParameterName", _("Parameter name"))
|
||||
.AddParameter("expression", _("New value"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
@@ -361,8 +360,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("string", _("Effect"))
|
||||
.AddParameter("string", _("Parameter name"))
|
||||
.AddParameter("layerEffectName", _("Effect name"))
|
||||
.AddParameter("layerEffectParameterName", _("Parameter name"))
|
||||
.AddParameter("string", _("New value"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
@@ -380,8 +379,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("string", _("Effect"))
|
||||
.AddParameter("string", _("Parameter name"))
|
||||
.AddParameter("layerEffectName", _("Effect name"))
|
||||
.AddParameter("layerEffectParameterName", _("Parameter name"))
|
||||
.AddParameter("yesorno", _("Enable this parameter"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
@@ -396,7 +395,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("string", _("Effect"))
|
||||
.AddParameter("layerEffectName", _("Effect name"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -410,7 +409,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("string", _("Effect"))
|
||||
.AddParameter("layerEffectName", _("Effect name"))
|
||||
.AddParameter("yesorno", _("Enable"), "", true)
|
||||
.MarkAsAdvanced();
|
||||
|
||||
@@ -567,7 +566,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"res/actions/camera.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer"));
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -21,7 +21,6 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/all-features/common-conversions");
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
|
||||
extension
|
||||
.AddExpression("ToNumber",
|
||||
@@ -65,7 +64,6 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
|
||||
_("Conversion"),
|
||||
"res/conditions/toujours24.png")
|
||||
.AddParameter("expression", _("Angle, in radians"));
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -5,7 +5,6 @@
|
||||
*/
|
||||
#include "AllBuiltinExtensions.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#include "GDCore/Events/Builtin/CommentEvent.h"
|
||||
#include "GDCore/Events/Builtin/ForEachChildVariableEvent.h"
|
||||
#include "GDCore/Events/Builtin/ForEachEvent.h"
|
||||
@@ -15,7 +14,6 @@
|
||||
#include "GDCore/Events/Builtin/StandardEvent.h"
|
||||
#include "GDCore/Events/Builtin/WhileEvent.h"
|
||||
#include "GDCore/Events/Event.h"
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
namespace gd {
|
||||
@@ -33,7 +31,6 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/all-features/advanced-conditions");
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
extension
|
||||
.AddCondition("Or",
|
||||
_("Or"),
|
||||
@@ -86,29 +83,29 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
|
||||
std::make_shared<gd::StandardEvent>());
|
||||
|
||||
extension.AddEvent("Link",
|
||||
_("Link"),
|
||||
_("Link to some external events"),
|
||||
_("Link external events"),
|
||||
_("Link to external events."),
|
||||
"",
|
||||
"res/lienaddicon.png",
|
||||
std::make_shared<gd::LinkEvent>());
|
||||
|
||||
extension.AddEvent("Comment",
|
||||
_("Comment"),
|
||||
_("Event displaying a text in the events editor"),
|
||||
_("Event displaying a text in the events editor."),
|
||||
"",
|
||||
"res/comment.png",
|
||||
std::make_shared<gd::CommentEvent>());
|
||||
|
||||
extension.AddEvent("While",
|
||||
_("While"),
|
||||
_("The event is repeated while the conditions are true"),
|
||||
_("Repeat the event while the conditions are true."),
|
||||
"",
|
||||
"res/while.png",
|
||||
std::make_shared<gd::WhileEvent>());
|
||||
|
||||
extension.AddEvent("Repeat",
|
||||
_("Repeat"),
|
||||
_("Event repeated a number of times"),
|
||||
_("Repeat the event for a specified number of times."),
|
||||
"",
|
||||
"res/repeat.png",
|
||||
std::make_shared<gd::RepeatEvent>());
|
||||
@@ -129,12 +126,11 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
|
||||
std::make_shared<gd::ForEachChildVariableEvent>());
|
||||
|
||||
extension.AddEvent("Group",
|
||||
_("Group"),
|
||||
_("Group containing events"),
|
||||
_("Event group"),
|
||||
_("Group containing events."),
|
||||
"",
|
||||
"res/foreach.png",
|
||||
std::make_shared<gd::GroupEvent>());
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -21,7 +21,6 @@ BuiltinExtensionsImplementer::ImplementsExternalLayoutsExtension(
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/interface/scene-editor/external-layouts");
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
extension
|
||||
.AddAction("CreateObjectsFromExternalLayout",
|
||||
_("Create objects from an external layout"),
|
||||
@@ -37,7 +36,6 @@ BuiltinExtensionsImplementer::ImplementsExternalLayoutsExtension(
|
||||
.AddParameter("expression", _("Y position of the origin"), "", true)
|
||||
.SetDefaultValue("0")
|
||||
.MarkAsAdvanced();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -22,7 +22,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/all-features/storage");
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
extension
|
||||
.AddCondition(
|
||||
"GroupExists",
|
||||
@@ -194,7 +193,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
|
||||
"res/actions/launchFile.png")
|
||||
.AddParameter("string", _("Command"))
|
||||
.MarkAsAdvanced();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -23,11 +23,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsKeyboardExtension(
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/all-features/keyboard");
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
extension
|
||||
.AddCondition("KeyPressed",
|
||||
_("Key pressed"),
|
||||
_("Test if a key is pressed"),
|
||||
_("Check if a key is pressed"),
|
||||
_("_PARAM1_ key is pressed"),
|
||||
_("Keyboard"),
|
||||
"res/conditions/keyboard24.png",
|
||||
@@ -38,7 +37,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsKeyboardExtension(
|
||||
extension
|
||||
.AddCondition("KeyReleased",
|
||||
_("Key released"),
|
||||
_("Test if a key was just released"),
|
||||
_("Check if a key was just released"),
|
||||
_("_PARAM1_ key is released"),
|
||||
_("Keyboard"),
|
||||
"res/conditions/keyboard24.png",
|
||||
@@ -49,33 +48,33 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsKeyboardExtension(
|
||||
extension
|
||||
.AddCondition("KeyFromTextPressed",
|
||||
_("Key pressed (text expression)"),
|
||||
_("Test if a key, retrieved from the result of the "
|
||||
_("Check if a key, retrieved from the result of the "
|
||||
"expression, is pressed"),
|
||||
_("_PARAM1_ key is pressed"),
|
||||
_("Keyboard"),
|
||||
"res/conditions/keyboard24.png",
|
||||
"res/conditions/keyboard.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("string", _("Expression generating the key to test"))
|
||||
.AddParameter("string", _("Expression generating the key to check"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddCondition("KeyFromTextReleased",
|
||||
_("Key released (text expression)"),
|
||||
_("Test if a key, retrieved from the result of the "
|
||||
_("Check if a key, retrieved from the result of the "
|
||||
"expression, was just released"),
|
||||
_("_PARAM1_ key is released"),
|
||||
_("Keyboard"),
|
||||
"res/conditions/keyboard24.png",
|
||||
"res/conditions/keyboard.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("string", _("Expression generating the key to test"))
|
||||
.AddParameter("string", _("Expression generating the key to check"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddCondition("AnyKeyPressed",
|
||||
_("Any key pressed"),
|
||||
_("Test if any key is pressed"),
|
||||
_("Check if any key is pressed"),
|
||||
_("Any key is pressed"),
|
||||
_("Keyboard"),
|
||||
"res/conditions/keyboard24.png",
|
||||
@@ -85,7 +84,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsKeyboardExtension(
|
||||
extension
|
||||
.AddCondition("AnyKeyReleased",
|
||||
_("Any key released"),
|
||||
_("Test if any key is released"),
|
||||
_("Check if any key is released"),
|
||||
_("Any key is released"),
|
||||
_("Keyboard"),
|
||||
"res/conditions/keyboard24.png",
|
||||
@@ -100,7 +99,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsKeyboardExtension(
|
||||
_("Keyboard"),
|
||||
"res/conditions/keyboard.png")
|
||||
.AddCodeOnlyParameter("currentScene", "");
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -19,7 +19,6 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)");
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
|
||||
extension
|
||||
.AddExpression("normalize",
|
||||
@@ -403,7 +402,6 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
.AddParameter("expression", _("Angle, in degrees"))
|
||||
.AddParameter("expression", _("Distance"));
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -25,7 +25,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/all-features/mouse-touch");
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
extension
|
||||
.AddCondition(
|
||||
"IsMouseWheelScrollingUp",
|
||||
@@ -217,6 +216,39 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
|
||||
.AddParameter("mouse", _("Button to check"))
|
||||
.MarkAsSimple();
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
"MouseButtonFromTextPressed",
|
||||
_("Mouse button pressed or touch held (text expression)"),
|
||||
_("Check if a mouse button, retrieved from the result of the "
|
||||
"expression, is pressed."),
|
||||
_("_PARAM1_ mouse button is pressed"),
|
||||
_("Mouse and touch"),
|
||||
"res/conditions/mouse24.png",
|
||||
"res/conditions/mouse.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("string", _("Expression generating the button to check"))
|
||||
.SetParameterLongDescription(
|
||||
_("Possible values are Left, Right and Middle."))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
"MouseButtonFromTextReleased",
|
||||
_("Mouse button released (text expression)"),
|
||||
_("Check if a mouse button, retrieved from the result of the "
|
||||
"expression, was just released."),
|
||||
_("_PARAM1_ mouse button is released"),
|
||||
_("Mouse and touch"),
|
||||
"res/conditions/mouse24.png",
|
||||
"res/conditions/mouse.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("string",
|
||||
_("Expression generating the mouse button to check"))
|
||||
.SetParameterLongDescription(
|
||||
_("Possible values are Left, Right and Middle."))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddExpressionAndCondition("number",
|
||||
"TouchX",
|
||||
@@ -302,8 +334,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
|
||||
_("Mouse and touch/Multitouch"),
|
||||
"res/conditions/touch.png")
|
||||
.AddCodeOnlyParameter("currentScene", "");
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -21,7 +21,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsNetworkExtension(
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/all-features/network");
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
extension
|
||||
.AddAction(
|
||||
"SendRequest",
|
||||
@@ -196,7 +195,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsNetworkExtension(
|
||||
"res/conditions/toujours24.png")
|
||||
.AddParameter("objectPtr", _("The object with the variable"))
|
||||
.AddParameter("objectvar", _("The object variable to be stringified"));
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -20,7 +20,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSceneExtension(
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("" /*TODO: Add a documentation page for this */);
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
|
||||
extension
|
||||
.AddExpression("Random",
|
||||
@@ -196,7 +195,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSceneExtension(
|
||||
"res/conditions/egal.png")
|
||||
.SetHelpPath("/all-features/advanced-conditions")
|
||||
.AddParameter("expression", _("First expression"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"), "number")
|
||||
.AddParameter("expression", _("Second expression"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
@@ -210,10 +209,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSceneExtension(
|
||||
"res/conditions/egal.png")
|
||||
.SetHelpPath("/all-features/advanced-conditions")
|
||||
.AddParameter("string", _("First string expression"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"), "string")
|
||||
.AddParameter("string", _("Second string expression"))
|
||||
.MarkAsAdvanced();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -75,11 +75,9 @@ void Direction::UnserializeFrom(const gd::SerializerElement& element) {
|
||||
SetTimeBetweenFrames(
|
||||
element.GetDoubleAttribute("timeBetweenFrames", 1, "tempsEntre"));
|
||||
SetLoop(element.GetBoolAttribute("looping", false, "boucle"));
|
||||
#if defined(GD_IDE_ONLY)
|
||||
SetMetadata(element.HasAttribute("metadata") || element.HasChild("metadata")
|
||||
? element.GetStringAttribute("metadata")
|
||||
: "");
|
||||
#endif
|
||||
|
||||
const gd::SerializerElement& spritesElement =
|
||||
element.GetChild("sprites", 0, "Sprites");
|
||||
@@ -135,7 +133,6 @@ void Direction::UnserializeFrom(const gd::SerializerElement& element) {
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
void SavePoint(const Point& point, gd::SerializerElement& element) {
|
||||
element.SetAttribute("name", point.GetName());
|
||||
element.SetAttribute("x", point.GetX());
|
||||
@@ -190,6 +187,5 @@ void Direction::SerializeTo(gd::SerializerElement& element) const {
|
||||
if (!GetMetadata().empty()) element.SetAttribute("metadata", GetMetadata());
|
||||
SaveSpritesDirection(sprites, element.AddChild("sprites"));
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -113,7 +113,6 @@ class GD_CORE_API Direction {
|
||||
*/
|
||||
void MoveSprite(std::size_t oldIndex, std::size_t newIndex);
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* \brief Set the metadata (any string) associated to the Direction.
|
||||
* \note Can be used by external editors to store extra information.
|
||||
@@ -124,20 +123,15 @@ class GD_CORE_API Direction {
|
||||
* \brief Return the (optional) metadata associated to the Direction.
|
||||
*/
|
||||
virtual const gd::String& GetMetadata() const { return metadata; }
|
||||
#endif
|
||||
|
||||
void UnserializeFrom(const gd::SerializerElement& element);
|
||||
#if defined(GD_IDE_ONLY)
|
||||
void SerializeTo(gd::SerializerElement& element) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool loop; ///< true if the animation must loop.
|
||||
double timeBetweenFrame; ///< The time between each sprite of the animation.
|
||||
std::vector<Sprite> sprites; ///< The sprites of the direction.
|
||||
#if defined(GD_IDE_ONLY)
|
||||
gd::String metadata;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -29,7 +29,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Animated object which can be used for most elements of a game"),
|
||||
"CppPlatform/Extensions/spriteicon.png");
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
obj.AddAction("Opacity",
|
||||
_("Change sprite opacity"),
|
||||
_("Change the opacity of a Sprite. 0 is fully transparent, 255 "
|
||||
@@ -536,7 +535,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
.AddParameter("objectList", _("Object 1"), "Sprite")
|
||||
.AddParameter("objectList", _("Object 2"), "Sprite")
|
||||
.AddCodeOnlyParameter("conditionInverted", "");
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -17,11 +17,9 @@
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
|
||||
#endif
|
||||
|
||||
namespace gd {
|
||||
|
||||
@@ -81,7 +79,6 @@ void SpriteObject::DoUnserializeFrom(gd::Project& project,
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
void SpriteObject::DoSerializeTo(gd::SerializerElement& element) const {
|
||||
element.SetAttribute("updateIfNotVisible", updateIfNotVisible);
|
||||
|
||||
@@ -157,7 +154,6 @@ bool SpriteObject::UpdateInitialInstanceProperty(gd::InitialInstance& position,
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
const Animation& SpriteObject::GetAnimation(std::size_t nb) const {
|
||||
if (nb >= animations.size()) return badAnimation;
|
||||
|
@@ -44,7 +44,6 @@ class GD_CORE_API SpriteObject : public gd::Object {
|
||||
return gd::make_unique<SpriteObject>(*this);
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
void ExposeResources(gd::ArbitraryResourceWorker& worker) override;
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetProperties() const override;
|
||||
@@ -60,7 +59,6 @@ class GD_CORE_API SpriteObject : public gd::Object {
|
||||
const gd::String& value,
|
||||
gd::Project& project,
|
||||
gd::Layout& scene) override;
|
||||
#endif
|
||||
|
||||
/** \name Animations
|
||||
* Methods related to animations management
|
||||
@@ -118,14 +116,24 @@ class GD_CORE_API SpriteObject : public gd::Object {
|
||||
* animation of the object.
|
||||
*/
|
||||
const std::vector<Animation>& GetAllAnimations() const { return animations; }
|
||||
|
||||
/**
|
||||
* \brief Set if the object animation should be played even if the object is hidden
|
||||
* or far from the camera.
|
||||
*/
|
||||
void SetUpdateIfNotVisible(bool updateIfNotVisible_) { updateIfNotVisible = updateIfNotVisible_; }
|
||||
|
||||
/**
|
||||
* \brief Check if the object animation should be played even if the object is hidden
|
||||
* or far from the camera (false by default).
|
||||
*/
|
||||
bool GetUpdateIfNotVisible() const { return updateIfNotVisible; }
|
||||
///@}
|
||||
|
||||
private:
|
||||
void DoUnserializeFrom(gd::Project& project,
|
||||
const gd::SerializerElement& element) override;
|
||||
#if defined(GD_IDE_ONLY)
|
||||
void DoSerializeTo(gd::SerializerElement& element) const override;
|
||||
#endif
|
||||
|
||||
mutable std::vector<Animation> animations;
|
||||
bool updateIfNotVisible; ///< If set to true, ask the game engine to play
|
||||
|
@@ -21,7 +21,6 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("" /*TODO: Add a documentation page for this */);
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
extension.AddStrExpression("NewLine",
|
||||
_("Insert a new line"),
|
||||
_("Insert a new line"),
|
||||
@@ -182,7 +181,6 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
|
||||
_("Position of the last character in the string to be "
|
||||
"considered in the search"));
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -22,7 +22,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/all-features/timers");
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
|
||||
extension
|
||||
.AddCondition("Timer",
|
||||
@@ -206,7 +205,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
|
||||
"[\"hour\", \"min\", \"sec\", \"mon\", \"year\", \"wday\", \"mday\", "
|
||||
"\"yday\", \"timestamp\"]");
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -23,7 +23,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/all-features/variables");
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
extension
|
||||
.AddCondition("VarScene",
|
||||
_("Value of a scene variable"),
|
||||
@@ -458,7 +457,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Variables"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"));
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -22,7 +22,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/all-features/window");
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
extension
|
||||
.AddAction(
|
||||
"SetFullScreen",
|
||||
@@ -215,7 +214,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
|
||||
_("Screen"),
|
||||
"res/window.png")
|
||||
.AddCodeOnlyParameter("currentScene", "");
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -34,7 +34,7 @@ ExpressionMetadata& ExpressionMetadata::SetHidden() {
|
||||
gd::ExpressionMetadata& ExpressionMetadata::AddParameter(
|
||||
const gd::String& type,
|
||||
const gd::String& description,
|
||||
const gd::String& optionalObjectType,
|
||||
const gd::String& supplementaryInformation,
|
||||
bool parameterIsOptional) {
|
||||
gd::ParameterMetadata info;
|
||||
info.type = type;
|
||||
@@ -46,15 +46,15 @@ gd::ExpressionMetadata& ExpressionMetadata::AddParameter(
|
||||
// parameter is an object/behavior type...
|
||||
(gd::ParameterMetadata::IsObject(type) ||
|
||||
gd::ParameterMetadata::IsBehavior(type))
|
||||
? (optionalObjectType.empty()
|
||||
? (supplementaryInformation.empty()
|
||||
? ""
|
||||
: extensionNamespace +
|
||||
optionalObjectType //... so prefix it with the extension
|
||||
supplementaryInformation //... so prefix it with the extension
|
||||
// namespace.
|
||||
)
|
||||
: optionalObjectType; // Otherwise don't change anything
|
||||
: supplementaryInformation; // Otherwise don't change anything
|
||||
|
||||
// TODO: Assert against optionalObjectType === "emsc" (when running with
|
||||
// TODO: Assert against supplementaryInformation === "emsc" (when running with
|
||||
// Emscripten), and warn about a missing argument when calling addParameter.
|
||||
|
||||
parameters.push_back(info);
|
||||
|
@@ -190,7 +190,7 @@ class GD_CORE_API ExpressionMetadata {
|
||||
gd::ExpressionMetadata& AddParameter(
|
||||
const gd::String& type,
|
||||
const gd::String& description,
|
||||
const gd::String& optionalObjectType = "",
|
||||
const gd::String& supplementaryInformation = "",
|
||||
bool parameterIsOptional = false);
|
||||
|
||||
/**
|
||||
|
@@ -51,7 +51,7 @@ InstructionMetadata::InstructionMetadata(const gd::String& extensionNamespace_,
|
||||
InstructionMetadata& InstructionMetadata::AddParameter(
|
||||
const gd::String& type,
|
||||
const gd::String& description,
|
||||
const gd::String& optionalObjectType,
|
||||
const gd::String& supplementaryInformation,
|
||||
bool parameterIsOptional) {
|
||||
ParameterMetadata info;
|
||||
info.type = type;
|
||||
@@ -63,15 +63,15 @@ InstructionMetadata& InstructionMetadata::AddParameter(
|
||||
// parameter is an object/behavior type...
|
||||
(gd::ParameterMetadata::IsObject(type) ||
|
||||
gd::ParameterMetadata::IsBehavior(type))
|
||||
? (optionalObjectType.empty()
|
||||
? (supplementaryInformation.empty()
|
||||
? ""
|
||||
: extensionNamespace +
|
||||
optionalObjectType //... so prefix it with the extension
|
||||
supplementaryInformation //... so prefix it with the extension
|
||||
// namespace.
|
||||
)
|
||||
: optionalObjectType; // Otherwise don't change anything
|
||||
: supplementaryInformation; // Otherwise don't change anything
|
||||
|
||||
// TODO: Assert against optionalObjectType === "emsc" (when running with
|
||||
// TODO: Assert against supplementaryInformation === "emsc" (when running with
|
||||
// Emscripten), and warn about a missing argument when calling addParameter.
|
||||
|
||||
parameters.push_back(info);
|
||||
@@ -93,7 +93,7 @@ InstructionMetadata& InstructionMetadata::UseStandardOperatorParameters(
|
||||
const gd::String& type) {
|
||||
SetManipulatedType(type);
|
||||
|
||||
AddParameter("operator", _("Modification's sign"));
|
||||
AddParameter("operator", _("Modification's sign"), type);
|
||||
AddParameter(type == "number" ? "expression" : type, _("Value"));
|
||||
size_t operatorParamIndex = parameters.size() - 2;
|
||||
size_t valueParamIndex = parameters.size() - 1;
|
||||
@@ -129,7 +129,7 @@ InstructionMetadata::UseStandardRelationalOperatorParameters(
|
||||
const gd::String& type) {
|
||||
SetManipulatedType(type);
|
||||
|
||||
AddParameter("relationalOperator", _("Sign of the test"));
|
||||
AddParameter("relationalOperator", _("Sign of the test"), type);
|
||||
AddParameter(type == "number" ? "expression" : type, _("Value to compare"));
|
||||
size_t operatorParamIndex = parameters.size() - 2;
|
||||
size_t valueParamIndex = parameters.size() - 1;
|
||||
|
@@ -6,7 +6,6 @@
|
||||
|
||||
#ifndef INSTRUCTIONMETADATA_H
|
||||
#define INSTRUCTIONMETADATA_H
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
@@ -137,8 +136,11 @@ class GD_CORE_API InstructionMetadata {
|
||||
* will also determine the type of the argument used when calling the function
|
||||
* in the generated code.
|
||||
* \param description Description for parameter
|
||||
* \param optionalObjectType If type is "object", this parameter will describe
|
||||
* which objects are allowed. If it is empty, all objects are allowed.
|
||||
* \param supplementaryInformation Additional information that can be used for
|
||||
* rendering or logic. For example:
|
||||
* - If type is "object", this argument will describe which objects are allowed.
|
||||
* If this argument is empty, all objects are allowed.
|
||||
* - If type is "operator", this argument will be used to display only pertinent operators.
|
||||
* \param parameterIsOptional true if the parameter must be optional, false
|
||||
* otherwise.
|
||||
*
|
||||
@@ -146,7 +148,7 @@ class GD_CORE_API InstructionMetadata {
|
||||
*/
|
||||
InstructionMetadata &AddParameter(const gd::String &type,
|
||||
const gd::String &label,
|
||||
const gd::String &optionalObjectType = "",
|
||||
const gd::String &supplementaryInformation = "",
|
||||
bool parameterIsOptional = false);
|
||||
|
||||
/**
|
||||
@@ -319,7 +321,7 @@ class GD_CORE_API InstructionMetadata {
|
||||
* "CppPlatform/Extensions/text.png");
|
||||
*
|
||||
* .AddParameter("object", _("Object"), "Text", false)
|
||||
* .AddParameter("operator", _("Modification operator"))
|
||||
* .AddParameter("operator", _("Modification operator"), "string")
|
||||
* .AddParameter("string", _("String"))
|
||||
* .SetFunctionName("SetString").SetManipulatedType("string").SetGetter("GetString").SetIncludeFile("MyExtension/TextObject.h");
|
||||
*
|
||||
@@ -452,5 +454,4 @@ class GD_CORE_API InstructionMetadata {
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif
|
||||
#endif // INSTRUCTIONMETADATA_H
|
||||
|
@@ -38,19 +38,17 @@ class GD_CORE_API MultipleInstructionMetadata {
|
||||
MultipleInstructionMetadata &AddParameter(
|
||||
const gd::String &type,
|
||||
const gd::String &label,
|
||||
const gd::String &optionalObjectType = "",
|
||||
const gd::String &supplementaryInformation = "",
|
||||
bool parameterIsOptional = false) {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
if (expression)
|
||||
expression->AddParameter(
|
||||
type, label, optionalObjectType, parameterIsOptional);
|
||||
type, label, supplementaryInformation, parameterIsOptional);
|
||||
if (condition)
|
||||
condition->AddParameter(
|
||||
type, label, optionalObjectType, parameterIsOptional);
|
||||
type, label, supplementaryInformation, parameterIsOptional);
|
||||
if (action)
|
||||
action->AddParameter(
|
||||
type, label, optionalObjectType, parameterIsOptional);
|
||||
#endif
|
||||
type, label, supplementaryInformation, parameterIsOptional);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -59,13 +57,11 @@ class GD_CORE_API MultipleInstructionMetadata {
|
||||
*/
|
||||
MultipleInstructionMetadata &AddCodeOnlyParameter(
|
||||
const gd::String &type, const gd::String &supplementaryInformation) {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
if (expression)
|
||||
expression->AddCodeOnlyParameter(type, supplementaryInformation);
|
||||
if (condition)
|
||||
condition->AddCodeOnlyParameter(type, supplementaryInformation);
|
||||
if (action) action->AddCodeOnlyParameter(type, supplementaryInformation);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -73,11 +69,9 @@ class GD_CORE_API MultipleInstructionMetadata {
|
||||
* \see gd::InstructionMetadata::SetDefaultValue
|
||||
*/
|
||||
MultipleInstructionMetadata &SetDefaultValue(const gd::String &defaultValue) {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
if (expression) expression->SetDefaultValue(defaultValue);
|
||||
if (condition) condition->SetDefaultValue(defaultValue);
|
||||
if (action) action->SetDefaultValue(defaultValue);
|
||||
#endif
|
||||
return *this;
|
||||
};
|
||||
|
||||
@@ -86,11 +80,9 @@ class GD_CORE_API MultipleInstructionMetadata {
|
||||
*/
|
||||
MultipleInstructionMetadata &SetParameterLongDescription(
|
||||
const gd::String &longDescription) {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
if (expression) expression->SetParameterLongDescription(longDescription);
|
||||
if (condition) condition->SetParameterLongDescription(longDescription);
|
||||
if (action) action->SetParameterLongDescription(longDescription);
|
||||
#endif
|
||||
return *this;
|
||||
};
|
||||
|
||||
@@ -98,11 +90,9 @@ class GD_CORE_API MultipleInstructionMetadata {
|
||||
* \see gd::InstructionMetadata::SetHidden
|
||||
*/
|
||||
MultipleInstructionMetadata &SetHidden() {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
if (expression) expression->SetHidden();
|
||||
if (condition) condition->SetHidden();
|
||||
if (action) action->SetHidden();
|
||||
#endif
|
||||
return *this;
|
||||
};
|
||||
|
||||
@@ -111,50 +101,40 @@ class GD_CORE_API MultipleInstructionMetadata {
|
||||
* \see gd::InstructionMetadata::UseStandardRelationalOperatorParameters
|
||||
*/
|
||||
MultipleInstructionMetadata &UseStandardParameters(const gd::String &type) {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
if (condition) condition->UseStandardRelationalOperatorParameters(type);
|
||||
if (action) action->UseStandardOperatorParameters(type);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
MultipleInstructionMetadata &SetFunctionName(const gd::String &functionName) {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
if (expression) expression->SetFunctionName(functionName);
|
||||
if (condition) condition->SetFunctionName(functionName);
|
||||
if (action) action->GetCodeExtraInformation().SetFunctionName(functionName);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
MultipleInstructionMetadata &SetGetter(const gd::String &getter) {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
if (expression) expression->SetFunctionName(getter);
|
||||
if (condition) condition->SetFunctionName(getter);
|
||||
if (action) action->GetCodeExtraInformation().SetGetter(getter);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
MultipleInstructionMetadata &SetIncludeFile(const gd::String &includeFile) {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
if (expression)
|
||||
expression->GetCodeExtraInformation().SetIncludeFile(includeFile);
|
||||
if (condition)
|
||||
condition->GetCodeExtraInformation().SetIncludeFile(includeFile);
|
||||
if (action) action->GetCodeExtraInformation().SetIncludeFile(includeFile);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
MultipleInstructionMetadata &AddIncludeFile(const gd::String &includeFile) {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
if (expression)
|
||||
expression->GetCodeExtraInformation().AddIncludeFile(includeFile);
|
||||
if (condition)
|
||||
condition->GetCodeExtraInformation().AddIncludeFile(includeFile);
|
||||
if (action) action->GetCodeExtraInformation().AddIncludeFile(includeFile);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -162,10 +142,8 @@ class GD_CORE_API MultipleInstructionMetadata {
|
||||
* \see gd::InstructionMetadata::MarkAsSimple
|
||||
*/
|
||||
MultipleInstructionMetadata &MarkAsSimple() {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
if (condition) condition->MarkAsSimple();
|
||||
if (action) action->MarkAsSimple();
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -173,10 +151,8 @@ class GD_CORE_API MultipleInstructionMetadata {
|
||||
* \see gd::InstructionMetadata::MarkAsAdvanced
|
||||
*/
|
||||
MultipleInstructionMetadata &MarkAsAdvanced() {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
if (condition) condition->MarkAsAdvanced();
|
||||
if (action) action->MarkAsAdvanced();
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -184,10 +160,8 @@ class GD_CORE_API MultipleInstructionMetadata {
|
||||
* \see gd::InstructionMetadata::MarkAsComplex
|
||||
*/
|
||||
MultipleInstructionMetadata &MarkAsComplex() {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
if (condition) condition->MarkAsComplex();
|
||||
if (action) action->MarkAsComplex();
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@@ -302,6 +302,38 @@ ObjectMetadata::AddExpressionAndConditionAndAction(
|
||||
expression, condition, action);
|
||||
}
|
||||
|
||||
gd::InstructionMetadata& ObjectMetadata::AddDuplicatedAction(
|
||||
const gd::String& newActionName, const gd::String& copiedActionName) {
|
||||
gd::String newNameWithNamespace = extensionNamespace + newActionName;
|
||||
gd::String copiedNameWithNamespace = extensionNamespace + copiedActionName;
|
||||
|
||||
auto copiedAction = actionsInfos.find(copiedNameWithNamespace);
|
||||
if (copiedAction == actionsInfos.end()) {
|
||||
gd::LogWarning("Could not find an action with name " +
|
||||
copiedNameWithNamespace + " to copy.");
|
||||
} else {
|
||||
actionsInfos[newNameWithNamespace] = copiedAction->second;
|
||||
}
|
||||
|
||||
return actionsInfos[newNameWithNamespace];
|
||||
}
|
||||
|
||||
gd::InstructionMetadata& ObjectMetadata::AddDuplicatedCondition(
|
||||
const gd::String& newConditionName, const gd::String& copiedConditionName) {
|
||||
gd::String newNameWithNamespace = extensionNamespace + newConditionName;
|
||||
gd::String copiedNameWithNamespace = extensionNamespace + copiedConditionName;
|
||||
|
||||
auto copiedCondition = conditionsInfos.find(copiedNameWithNamespace);
|
||||
if (copiedCondition == conditionsInfos.end()) {
|
||||
gd::LogWarning("Could not find a condition with name " +
|
||||
copiedNameWithNamespace + " to copy.");
|
||||
} else {
|
||||
conditionsInfos[newNameWithNamespace] = copiedCondition->second;
|
||||
}
|
||||
|
||||
return conditionsInfos[newNameWithNamespace];
|
||||
}
|
||||
|
||||
ObjectMetadata& ObjectMetadata::SetFullName(const gd::String& fullname_) {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
fullname = fullname_;
|
||||
|
@@ -153,6 +153,25 @@ class GD_CORE_API ObjectMetadata {
|
||||
const gd::String& group,
|
||||
const gd::String& icon);
|
||||
|
||||
/**
|
||||
* \brief Create a new action which is the duplicate of the specified one.
|
||||
*
|
||||
* Useful for handling a deprecated action that is just a "copy" of the new
|
||||
* one.
|
||||
*/
|
||||
gd::InstructionMetadata& AddDuplicatedAction(
|
||||
const gd::String& newActionName, const gd::String& copiedActionName);
|
||||
|
||||
/**
|
||||
* \brief Create a new condition which is the duplicate of the specified one.
|
||||
*
|
||||
* Useful for handling a deprecated condition that is just a "copy" of the new
|
||||
* one.
|
||||
*/
|
||||
gd::InstructionMetadata& AddDuplicatedCondition(
|
||||
const gd::String& newConditionName,
|
||||
const gd::String& copiedConditionName);
|
||||
|
||||
/**
|
||||
* \brief Set the name shown to the user.
|
||||
*/
|
||||
|
@@ -189,6 +189,10 @@ class GD_CORE_API ParameterMetadata {
|
||||
parameterType == "joyaxis" ||
|
||||
parameterType == "stringWithSelector" ||
|
||||
parameterType == "sceneName" ||
|
||||
parameterType == "layerEffectName" ||
|
||||
parameterType == "layerEffectParameterName" ||
|
||||
parameterType == "objectEffectName" ||
|
||||
parameterType == "objectEffectParameterName" ||
|
||||
parameterType == "objectPointName" ||
|
||||
parameterType == "objectAnimationName";
|
||||
} else if (type == "variable") {
|
||||
|
@@ -529,24 +529,6 @@ class GD_CORE_API PlatformExtension {
|
||||
std::map<gd::String, gd::ExpressionMetadata>& GetAllStrExpressionsForBehavior(
|
||||
gd::String autoType);
|
||||
|
||||
/**
|
||||
* Called to inventory resources used by conditions
|
||||
* (and possibly do work on them, like renaming, etc...)
|
||||
*
|
||||
* \see gd::PlatformExtension::ExposeActionsResources
|
||||
*/
|
||||
virtual void ExposeConditionsResources(Instruction& condition,
|
||||
gd::ArbitraryResourceWorker& worker){};
|
||||
|
||||
/**
|
||||
* Called to inventory resources used by actions
|
||||
* (and possibly do work on them, like renaming, etc...)
|
||||
*
|
||||
* \see ArbitraryResourceWorker
|
||||
*/
|
||||
virtual void ExposeActionsResources(Instruction& action,
|
||||
gd::ArbitraryResourceWorker& worker){};
|
||||
|
||||
/**
|
||||
* \brief Get all the properties of the extension. Properties
|
||||
* are shown in the game properties in the editor, and are exported in the
|
||||
|
@@ -19,11 +19,14 @@
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/IDE/Events/ExpressionValidator.h"
|
||||
#include "GDCore/Project/ObjectsContainer.h"
|
||||
#include "GDCore/IDE/Events/InstructionSentenceFormatter.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace gd {
|
||||
|
||||
const gd::String EventsRefactorer::searchIgnoredCharacters = ";:,#()";
|
||||
|
||||
/**
|
||||
* \brief Go through the nodes and change the given object name to a new one.
|
||||
*
|
||||
@@ -675,16 +678,27 @@ bool EventsRefactorer::ReplaceStringInConditions(
|
||||
}
|
||||
|
||||
vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
|
||||
gd::ObjectsContainer& project,
|
||||
gd::ObjectsContainer& layout,
|
||||
const gd::Platform& platform,
|
||||
gd::EventsList& events,
|
||||
gd::String search,
|
||||
bool matchCase,
|
||||
bool inConditions,
|
||||
bool inActions,
|
||||
bool inEventStrings) {
|
||||
bool inEventStrings,
|
||||
bool inEventSentences) {
|
||||
vector<EventsSearchResult> results;
|
||||
|
||||
const gd::String& ignored_characters = EventsRefactorer::searchIgnoredCharacters;
|
||||
|
||||
search.replace_if(search.begin(),
|
||||
search.end(),
|
||||
[ignored_characters](const char &c) {
|
||||
return ignored_characters.find(c) != gd::String::npos;
|
||||
},
|
||||
"");
|
||||
search = search.LeftTrim().RightTrim();
|
||||
search.RemoveConsecutiveOccurrences(search.begin(), search.end(), ' ');
|
||||
|
||||
for (std::size_t i = 0; i < events.size(); ++i) {
|
||||
bool eventAddedInResults = false;
|
||||
|
||||
@@ -694,7 +708,7 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
|
||||
for (std::size_t j = 0; j < conditionsVectors.size(); ++j) {
|
||||
if (!eventAddedInResults &&
|
||||
SearchStringInConditions(
|
||||
project, layout, *conditionsVectors[j], search, matchCase)) {
|
||||
platform, *conditionsVectors[j], search, matchCase, inEventSentences)) {
|
||||
results.push_back(EventsSearchResult(
|
||||
std::weak_ptr<gd::BaseEvent>(events.GetEventSmartPtr(i)),
|
||||
&events,
|
||||
@@ -709,7 +723,7 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
|
||||
for (std::size_t j = 0; j < actionsVectors.size(); ++j) {
|
||||
if (!eventAddedInResults &&
|
||||
SearchStringInActions(
|
||||
project, layout, *actionsVectors[j], search, matchCase)) {
|
||||
platform, *actionsVectors[j], search, matchCase, inEventSentences)) {
|
||||
results.push_back(EventsSearchResult(
|
||||
std::weak_ptr<gd::BaseEvent>(events.GetEventSmartPtr(i)),
|
||||
&events,
|
||||
@@ -720,7 +734,7 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
|
||||
|
||||
if (inEventStrings) {
|
||||
if (!eventAddedInResults &&
|
||||
SearchStringInEvent(project, layout, events[i], search, matchCase)) {
|
||||
SearchStringInEvent(events[i], search, matchCase)) {
|
||||
results.push_back(EventsSearchResult(
|
||||
std::weak_ptr<gd::BaseEvent>(events.GetEventSmartPtr(i)),
|
||||
&events,
|
||||
@@ -730,14 +744,14 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
|
||||
|
||||
if (events[i].CanHaveSubEvents()) {
|
||||
vector<EventsSearchResult> subResults =
|
||||
SearchInEvents(project,
|
||||
layout,
|
||||
SearchInEvents(platform,
|
||||
events[i].GetSubEvents(),
|
||||
search,
|
||||
matchCase,
|
||||
inConditions,
|
||||
inActions,
|
||||
inEventStrings);
|
||||
inEventStrings,
|
||||
inEventSentences);
|
||||
std::copy(
|
||||
subResults.begin(), subResults.end(), std::back_inserter(results));
|
||||
}
|
||||
@@ -746,11 +760,12 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
|
||||
return results;
|
||||
}
|
||||
|
||||
bool EventsRefactorer::SearchStringInActions(gd::ObjectsContainer& project,
|
||||
gd::ObjectsContainer& layout,
|
||||
gd::InstructionsList& actions,
|
||||
gd::String search,
|
||||
bool matchCase) {
|
||||
bool EventsRefactorer::SearchStringInActions(
|
||||
const gd::Platform& platform,
|
||||
gd::InstructionsList& actions,
|
||||
gd::String search,
|
||||
bool matchCase,
|
||||
bool inSentences) {
|
||||
for (std::size_t aId = 0; aId < actions.size(); ++aId) {
|
||||
for (std::size_t pNb = 0; pNb < actions[aId].GetParameters().size();
|
||||
++pNb) {
|
||||
@@ -765,24 +780,60 @@ bool EventsRefactorer::SearchStringInActions(gd::ObjectsContainer& project,
|
||||
if (foundPosition != gd::String::npos) return true;
|
||||
}
|
||||
|
||||
if (inSentences && SearchStringInFormattedText(
|
||||
platform, actions[aId], search, matchCase, false))
|
||||
return true;
|
||||
|
||||
if (!actions[aId].GetSubInstructions().empty() &&
|
||||
SearchStringInActions(project,
|
||||
layout,
|
||||
SearchStringInActions(platform,
|
||||
actions[aId].GetSubInstructions(),
|
||||
search,
|
||||
matchCase))
|
||||
matchCase,
|
||||
inSentences))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EventsRefactorer::SearchStringInFormattedText(
|
||||
const gd::Platform& platform,
|
||||
gd::Instruction& instruction,
|
||||
gd::String search,
|
||||
bool matchCase,
|
||||
bool isCondition) {
|
||||
const auto& metadata = isCondition
|
||||
? gd::MetadataProvider::GetConditionMetadata(
|
||||
platform, instruction.GetType())
|
||||
: gd::MetadataProvider::GetActionMetadata(
|
||||
platform, instruction.GetType());
|
||||
gd::String completeSentence = gd::InstructionSentenceFormatter::Get()->GetFullText(instruction, metadata);
|
||||
|
||||
const gd::String& ignored_characters = EventsRefactorer::searchIgnoredCharacters;
|
||||
|
||||
completeSentence.replace_if(completeSentence.begin(),
|
||||
completeSentence.end(),
|
||||
[ignored_characters](const char &c) {
|
||||
return ignored_characters.find(c) != gd::String::npos;
|
||||
},
|
||||
"");
|
||||
|
||||
completeSentence.RemoveConsecutiveOccurrences(
|
||||
completeSentence.begin(), completeSentence.end(), ' ');
|
||||
|
||||
size_t foundPosition = matchCase
|
||||
? completeSentence.find(search)
|
||||
: completeSentence.FindCaseInsensitive(search);
|
||||
|
||||
return foundPosition != gd::String::npos;
|
||||
}
|
||||
|
||||
bool EventsRefactorer::SearchStringInConditions(
|
||||
gd::ObjectsContainer& project,
|
||||
gd::ObjectsContainer& layout,
|
||||
const gd::Platform& platform,
|
||||
gd::InstructionsList& conditions,
|
||||
gd::String search,
|
||||
bool matchCase) {
|
||||
bool matchCase,
|
||||
bool inSentences) {
|
||||
for (std::size_t cId = 0; cId < conditions.size(); ++cId) {
|
||||
for (std::size_t pNb = 0; pNb < conditions[cId].GetParameters().size();
|
||||
++pNb) {
|
||||
@@ -797,21 +848,23 @@ bool EventsRefactorer::SearchStringInConditions(
|
||||
if (foundPosition != gd::String::npos) return true;
|
||||
}
|
||||
|
||||
if (inSentences && SearchStringInFormattedText(
|
||||
platform, conditions[cId], search, matchCase, true))
|
||||
return true;
|
||||
|
||||
if (!conditions[cId].GetSubInstructions().empty() &&
|
||||
SearchStringInConditions(project,
|
||||
layout,
|
||||
SearchStringInConditions(platform,
|
||||
conditions[cId].GetSubInstructions(),
|
||||
search,
|
||||
matchCase))
|
||||
matchCase,
|
||||
inSentences))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EventsRefactorer::SearchStringInEvent(gd::ObjectsContainer& project,
|
||||
gd::ObjectsContainer& layout,
|
||||
gd::BaseEvent& event,
|
||||
bool EventsRefactorer::SearchStringInEvent(gd::BaseEvent& event,
|
||||
gd::String search,
|
||||
bool matchCase) {
|
||||
for (gd::String str : event.GetAllSearchableStrings()) {
|
||||
|
@@ -41,7 +41,7 @@ class GD_CORE_API EventsSearchResult {
|
||||
std::size_t positionInList;
|
||||
|
||||
bool IsEventsListValid() const { return eventsList != nullptr; }
|
||||
|
||||
|
||||
/**
|
||||
* \brief Get the events list containing the event pointed by the EventsSearchResult.
|
||||
* \warning Only call this when IsEventsListValid returns true.
|
||||
@@ -49,7 +49,7 @@ class GD_CORE_API EventsSearchResult {
|
||||
const gd::EventsList & GetEventsList() const { return *eventsList; }
|
||||
|
||||
std::size_t GetPositionInList() const { return positionInList; }
|
||||
|
||||
|
||||
bool IsEventValid() const { return !event.expired(); }
|
||||
|
||||
/**
|
||||
@@ -72,7 +72,7 @@ class GD_CORE_API EventsSearchResult {
|
||||
class GD_CORE_API EventsRefactorer {
|
||||
public:
|
||||
/**
|
||||
* Replace all occurences of an object name by another name
|
||||
* Replace all occurrences of an object name by another name
|
||||
* ( include : objects in parameters and in math/text expressions of all
|
||||
* events ).
|
||||
*/
|
||||
@@ -98,14 +98,14 @@ class GD_CORE_API EventsRefactorer {
|
||||
* \return A vector containing EventsSearchResult objects filled with events
|
||||
* containing the string
|
||||
*/
|
||||
static std::vector<EventsSearchResult> SearchInEvents(gd::ObjectsContainer& project,
|
||||
gd::ObjectsContainer& layout,
|
||||
static std::vector<EventsSearchResult> SearchInEvents(const gd::Platform& platform,
|
||||
gd::EventsList& events,
|
||||
gd::String search,
|
||||
bool matchCase,
|
||||
bool inConditions,
|
||||
bool inActions,
|
||||
bool inEventStrings);
|
||||
bool inEventStrings,
|
||||
bool inEventSentences);
|
||||
|
||||
/**
|
||||
* Replace all occurrences of a gd::String in events
|
||||
@@ -123,7 +123,7 @@ class GD_CORE_API EventsRefactorer {
|
||||
|
||||
private:
|
||||
/**
|
||||
* Replace all occurences of an object name by another name in an action
|
||||
* Replace all occurrences of an object name by another name in an action
|
||||
* ( include : objects in parameters and in math/text expressions ).
|
||||
*
|
||||
* \return true if something was modified.
|
||||
@@ -136,7 +136,7 @@ class GD_CORE_API EventsRefactorer {
|
||||
gd::String newName);
|
||||
|
||||
/**
|
||||
* Replace all occurences of an object name by another name in a condition
|
||||
* Replace all occurrences of an object name by another name in a condition
|
||||
* ( include : objects in parameters and in math/text expressions ).
|
||||
*
|
||||
* \return true if something was modified.
|
||||
@@ -185,7 +185,7 @@ class GD_CORE_API EventsRefactorer {
|
||||
gd::String name);
|
||||
|
||||
/**
|
||||
* Replace all occurences of a gd::String in conditions
|
||||
* Replace all occurrences of a gd::String in conditions
|
||||
*
|
||||
* \return true if something was modified.
|
||||
*/
|
||||
@@ -197,7 +197,7 @@ class GD_CORE_API EventsRefactorer {
|
||||
bool matchCase);
|
||||
|
||||
/**
|
||||
* Replace all occurences of a gd::String in actions
|
||||
* Replace all occurrences of a gd::String in actions
|
||||
*
|
||||
* \return true if something was modified.
|
||||
*/
|
||||
@@ -208,21 +208,26 @@ class GD_CORE_API EventsRefactorer {
|
||||
gd::String newString,
|
||||
bool matchCase);
|
||||
|
||||
static bool SearchStringInActions(gd::ObjectsContainer& project,
|
||||
gd::ObjectsContainer& layout,
|
||||
static bool SearchStringInFormattedText(const gd::Platform& platform,
|
||||
gd::Instruction& instruction,
|
||||
gd::String search,
|
||||
bool matchCase,
|
||||
bool isCondition);
|
||||
static bool SearchStringInActions(const gd::Platform& platform,
|
||||
gd::InstructionsList& actions,
|
||||
gd::String search,
|
||||
bool matchCase);
|
||||
static bool SearchStringInConditions(gd::ObjectsContainer& project,
|
||||
gd::ObjectsContainer& layout,
|
||||
bool matchCase,
|
||||
bool inSentences);
|
||||
static bool SearchStringInConditions(const gd::Platform& platform,
|
||||
gd::InstructionsList& conditions,
|
||||
gd::String search,
|
||||
bool matchCase);
|
||||
static bool SearchStringInEvent(gd::ObjectsContainer& project,
|
||||
gd::ObjectsContainer& layout,
|
||||
gd::BaseEvent& events,
|
||||
gd::String search,
|
||||
bool matchCase);
|
||||
bool matchCase,
|
||||
bool inSentences);
|
||||
static bool SearchStringInEvent(gd::BaseEvent& events,
|
||||
gd::String search,
|
||||
bool matchCase);
|
||||
|
||||
static const gd::String searchIgnoredCharacters;
|
||||
|
||||
EventsRefactorer(){};
|
||||
};
|
||||
|
@@ -9,12 +9,12 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
|
||||
#include "GDCore/IDE/Events/ExpressionNodeLocationFinder.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
|
||||
namespace gd {
|
||||
class Expression;
|
||||
@@ -326,10 +326,7 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
node.type, "", searchedPosition + 1, searchedPosition + 1));
|
||||
}
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
node.type, "", searchedPosition + 1, searchedPosition + 1));
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
node.type, "", searchedPosition + 1, searchedPosition + 1));
|
||||
// No completions.
|
||||
}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
@@ -359,8 +356,9 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
}
|
||||
// Search the parameter metadata index skipping invisible ones.
|
||||
size_t visibleParameterIndex = 0;
|
||||
size_t metadataParameterIndex = ExpressionParser2::WrittenParametersFirstIndex(
|
||||
functionCall->objectName, functionCall->behaviorName);
|
||||
size_t metadataParameterIndex =
|
||||
ExpressionParser2::WrittenParametersFirstIndex(
|
||||
functionCall->objectName, functionCall->behaviorName);
|
||||
|
||||
const gd::ParameterMetadata* parameterMetadata = nullptr;
|
||||
while (metadataParameterIndex <
|
||||
|
@@ -4,7 +4,6 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#include "GDCore/IDE/Events/InstructionSentenceFormatter.h"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
@@ -90,6 +89,19 @@ InstructionSentenceFormatter::GetAsFormattedText(
|
||||
return formattedStr;
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
gd::String InstructionSentenceFormatter::GetFullText(
|
||||
const gd::Instruction &instr, const gd::InstructionMetadata &metadata)
|
||||
{
|
||||
const std::vector<std::pair<gd::String, gd::TextFormatting> > formattedText =
|
||||
GetAsFormattedText(instr, metadata);
|
||||
|
||||
#endif
|
||||
gd::String completeSentence = "";
|
||||
|
||||
for (std::size_t id = 0; id < formattedText.size(); ++id) {
|
||||
completeSentence += formattedText.at(id).first;
|
||||
}
|
||||
|
||||
return completeSentence;
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -4,7 +4,6 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#ifndef TRANSLATEACTION_H
|
||||
#define TRANSLATEACTION_H
|
||||
#include <map>
|
||||
@@ -39,6 +38,9 @@ class GD_CORE_API InstructionSentenceFormatter {
|
||||
return (static_cast<InstructionSentenceFormatter *>(_singleton));
|
||||
}
|
||||
|
||||
gd::String GetFullText(const gd::Instruction &instr,
|
||||
const gd::InstructionMetadata &metadata);
|
||||
|
||||
static void DestroySingleton() {
|
||||
if (NULL != _singleton) {
|
||||
delete _singleton;
|
||||
@@ -55,4 +57,3 @@ class GD_CORE_API InstructionSentenceFormatter {
|
||||
|
||||
} // namespace gd
|
||||
#endif // TRANSLATEACTION_H
|
||||
#endif
|
||||
|
@@ -19,12 +19,15 @@ bool InstructionsParameterMover::DoVisitInstruction(
|
||||
gd::Instruction& instruction, bool isCondition) {
|
||||
if (instruction.GetType() == instructionType) {
|
||||
std::vector<gd::Expression> updatedParameters = instruction.GetParameters();
|
||||
if (oldIndex < updatedParameters.size() ||
|
||||
newIndex < updatedParameters.size()) {
|
||||
gd::Expression movedParameter = updatedParameters[oldIndex];
|
||||
if (oldIndex < updatedParameters.size()) {
|
||||
gd::Expression movedParameter = updatedParameters.at(oldIndex);
|
||||
updatedParameters.erase(updatedParameters.begin() + oldIndex);
|
||||
updatedParameters.insert(updatedParameters.begin() + newIndex,
|
||||
movedParameter);
|
||||
if (newIndex < updatedParameters.size()) {
|
||||
updatedParameters.insert(updatedParameters.begin() + newIndex,
|
||||
movedParameter);
|
||||
} else {
|
||||
updatedParameters.push_back(movedParameter);
|
||||
}
|
||||
instruction.SetParameters(updatedParameters);
|
||||
}
|
||||
}
|
||||
|
@@ -13,8 +13,11 @@
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Extensions/Metadata/InstructionMetadata.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/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/ResourcesManager.h"
|
||||
|
||||
@@ -23,8 +26,13 @@ using namespace std;
|
||||
namespace gd {
|
||||
|
||||
void ArbitraryResourceWorker::ExposeImage(gd::String& imageName){
|
||||
// Nothing to do, the image is a reference to a resource that
|
||||
// is already exposed.
|
||||
// Nothing to do by default - each child class can define here the action to
|
||||
// do.
|
||||
};
|
||||
|
||||
void ArbitraryResourceWorker::ExposeBitmapFont(gd::String& bitmapFontName){
|
||||
// Nothing to do by default - each child class can define here the action to
|
||||
// do.
|
||||
};
|
||||
|
||||
void ArbitraryResourceWorker::ExposeAudio(gd::String& audioName) {
|
||||
@@ -33,12 +41,14 @@ void ArbitraryResourceWorker::ExposeAudio(gd::String& audioName) {
|
||||
|
||||
if (resources->HasResource(audioName) &&
|
||||
resources->GetResource(audioName).GetKind() == "audio") {
|
||||
// Nothing to do, the audio is a reference to a resource that
|
||||
// is already exposed.
|
||||
// Nothing to do, the audio is a reference to a proper resource.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// For compatibility with older projects (where events were refering to files
|
||||
// directly), we consider that this resource name is a filename, and so expose
|
||||
// it as a file.
|
||||
ExposeFile(audioName);
|
||||
};
|
||||
|
||||
@@ -48,30 +58,17 @@ void ArbitraryResourceWorker::ExposeFont(gd::String& fontName) {
|
||||
|
||||
if (resources->HasResource(fontName) &&
|
||||
resources->GetResource(fontName).GetKind() == "font") {
|
||||
// Nothing to do, the font is a reference to a resource that
|
||||
// is already exposed.
|
||||
// Nothing to do, the font is a reference to a proper resource.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// For compatibility with older projects (where events were refering to files
|
||||
// directly), we consider that this resource name is a filename, and so expose
|
||||
// it as a file.
|
||||
ExposeFile(fontName);
|
||||
};
|
||||
|
||||
void ArbitraryResourceWorker::ExposeBitmapFont(gd::String& bitmapFontName) {
|
||||
for (auto resources : GetResources()) {
|
||||
if (!resources) continue;
|
||||
|
||||
if (resources->HasResource(bitmapFontName) &&
|
||||
resources->GetResource(bitmapFontName).GetKind() == "bitmapFont") {
|
||||
// Nothing to do, the font is a reference to a resource that
|
||||
// is already exposed.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ExposeFile(bitmapFontName);
|
||||
};
|
||||
|
||||
void ArbitraryResourceWorker::ExposeResources(
|
||||
gd::ResourcesManager* resourcesManager) {
|
||||
if (!resourcesManager) return;
|
||||
@@ -95,101 +92,67 @@ void ArbitraryResourceWorker::ExposeResource(gd::Resource& resource) {
|
||||
|
||||
ArbitraryResourceWorker::~ArbitraryResourceWorker() {}
|
||||
|
||||
/**
|
||||
* Launch the specified resource worker on every resource referenced in the
|
||||
* events.
|
||||
*/
|
||||
class ResourceWorkerInEventsWorker : public ArbitraryEventsWorker {
|
||||
public:
|
||||
ResourceWorkerInEventsWorker(const gd::Project& project_,
|
||||
gd::ArbitraryResourceWorker& worker_)
|
||||
: project(project_), worker(worker_){};
|
||||
virtual ~ResourceWorkerInEventsWorker() {};
|
||||
|
||||
private:
|
||||
bool DoVisitInstruction(gd::Instruction& instruction, bool isCondition) {
|
||||
const auto& platform = project.GetCurrentPlatform();
|
||||
const auto& metadata = isCondition
|
||||
? gd::MetadataProvider::GetConditionMetadata(
|
||||
platform, instruction.GetType())
|
||||
: gd::MetadataProvider::GetActionMetadata(
|
||||
platform, instruction.GetType());
|
||||
|
||||
gd::ParameterMetadataTools::IterateOverParametersWithIndex(
|
||||
instruction.GetParameters(),
|
||||
metadata.GetParameters(),
|
||||
[this, &instruction](const gd::ParameterMetadata& parameterMetadata,
|
||||
const gd::String& parameterValue,
|
||||
size_t parameterIndex,
|
||||
const gd::String& lastObjectName) {
|
||||
if (parameterMetadata.GetType() ==
|
||||
"police") { // Should be renamed fontResource
|
||||
gd::String updatedParameterValue = parameterValue;
|
||||
worker.ExposeFont(updatedParameterValue);
|
||||
instruction.SetParameter(parameterIndex, updatedParameterValue);
|
||||
} else if (parameterMetadata.GetType() == "soundfile" ||
|
||||
parameterMetadata.GetType() ==
|
||||
"musicfile") { // Should be renamed audioResource
|
||||
gd::String updatedParameterValue = parameterValue;
|
||||
worker.ExposeAudio(updatedParameterValue);
|
||||
instruction.SetParameter(parameterIndex, updatedParameterValue);
|
||||
} else if (parameterMetadata.GetType() == "bitmapFontResource") {
|
||||
gd::String updatedParameterValue = parameterValue;
|
||||
worker.ExposeBitmapFont(updatedParameterValue);
|
||||
instruction.SetParameter(parameterIndex, updatedParameterValue);
|
||||
} else if (parameterMetadata.GetType() == "imageResource") {
|
||||
gd::String updatedParameterValue = parameterValue;
|
||||
worker.ExposeImage(updatedParameterValue);
|
||||
instruction.SetParameter(parameterIndex, updatedParameterValue);
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
const gd::Project& project;
|
||||
gd::ArbitraryResourceWorker& worker;
|
||||
};
|
||||
|
||||
void LaunchResourceWorkerOnEvents(const gd::Project& project,
|
||||
gd::EventsList& events,
|
||||
gd::ArbitraryResourceWorker& worker) {
|
||||
// Get all extensions used
|
||||
auto allGameExtensions =
|
||||
project.GetCurrentPlatform().GetAllPlatformExtensions();
|
||||
|
||||
for (std::size_t j = 0; j < events.size(); j++) {
|
||||
vector<gd::InstructionsList*> allActionsVectors =
|
||||
events[j].GetAllActionsVectors();
|
||||
for (std::size_t i = 0; i < allActionsVectors.size(); ++i) {
|
||||
for (std::size_t k = 0; k < allActionsVectors[i]->size(); k++) {
|
||||
gd::String type = allActionsVectors[i]->Get(k).GetType();
|
||||
for (std::size_t e = 0; e < allGameExtensions.size(); ++e) {
|
||||
bool extensionHasAction = false;
|
||||
|
||||
const std::map<gd::String, gd::InstructionMetadata>& allActions =
|
||||
allGameExtensions[e]->GetAllActions();
|
||||
if (allActions.find(type) != allActions.end())
|
||||
extensionHasAction = true;
|
||||
|
||||
const vector<gd::String>& objects =
|
||||
allGameExtensions[e]->GetExtensionObjectsTypes();
|
||||
for (std::size_t o = 0; o < objects.size(); ++o) {
|
||||
const std::map<gd::String, gd::InstructionMetadata>&
|
||||
allObjectsActions =
|
||||
allGameExtensions[e]->GetAllActionsForObject(objects[o]);
|
||||
if (allObjectsActions.find(type) != allObjectsActions.end())
|
||||
extensionHasAction = true;
|
||||
}
|
||||
|
||||
const vector<gd::String>& autos =
|
||||
allGameExtensions[e]->GetBehaviorsTypes();
|
||||
for (std::size_t a = 0; a < autos.size(); ++a) {
|
||||
const std::map<gd::String, gd::InstructionMetadata>&
|
||||
allAutosActions =
|
||||
allGameExtensions[e]->GetAllActionsForBehavior(autos[a]);
|
||||
if (allAutosActions.find(type) != allAutosActions.end())
|
||||
extensionHasAction = true;
|
||||
}
|
||||
|
||||
if (extensionHasAction) {
|
||||
allGameExtensions[e]->ExposeActionsResources(
|
||||
allActionsVectors[i]->Get(k), worker);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vector<gd::InstructionsList*> allConditionsVector =
|
||||
events[j].GetAllConditionsVectors();
|
||||
for (std::size_t i = 0; i < allConditionsVector.size(); ++i) {
|
||||
for (std::size_t k = 0; k < allConditionsVector[i]->size(); k++) {
|
||||
gd::String type = allConditionsVector[i]->Get(k).GetType();
|
||||
for (std::size_t e = 0; e < allGameExtensions.size(); ++e) {
|
||||
bool extensionHasCondition = false;
|
||||
|
||||
const std::map<gd::String, gd::InstructionMetadata>& allConditions =
|
||||
allGameExtensions[e]->GetAllConditions();
|
||||
if (allConditions.find(type) != allConditions.end())
|
||||
extensionHasCondition = true;
|
||||
|
||||
const vector<gd::String>& objects =
|
||||
allGameExtensions[e]->GetExtensionObjectsTypes();
|
||||
for (std::size_t j = 0; j < objects.size(); ++j) {
|
||||
const std::map<gd::String, gd::InstructionMetadata>&
|
||||
allObjectsConditions =
|
||||
allGameExtensions[e]->GetAllConditionsForObject(objects[j]);
|
||||
if (allObjectsConditions.find(type) != allObjectsConditions.end())
|
||||
extensionHasCondition = true;
|
||||
}
|
||||
|
||||
const vector<gd::String>& autos =
|
||||
allGameExtensions[e]->GetBehaviorsTypes();
|
||||
for (std::size_t j = 0; j < autos.size(); ++j) {
|
||||
const std::map<gd::String, gd::InstructionMetadata>&
|
||||
allAutosConditions =
|
||||
allGameExtensions[e]->GetAllConditionsForBehavior(autos[j]);
|
||||
if (allAutosConditions.find(type) != allAutosConditions.end())
|
||||
extensionHasCondition = true;
|
||||
}
|
||||
|
||||
if (extensionHasCondition)
|
||||
allGameExtensions[e]->ExposeConditionsResources(
|
||||
allConditionsVector[i]->Get(k), worker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (events[j].CanHaveSubEvents())
|
||||
LaunchResourceWorkerOnEvents(project, events[j].GetSubEvents(), worker);
|
||||
}
|
||||
|
||||
return;
|
||||
ResourceWorkerInEventsWorker eventsWorker(project, worker);
|
||||
eventsWorker.Launch(events);
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -60,19 +60,18 @@ class GD_CORE_API ArbitraryResourceWorker {
|
||||
|
||||
/**
|
||||
* \brief Expose an audio, which is either a reference to an "audio" resource,
|
||||
* or a filename if no resource with this name exists.
|
||||
* or a filename if no resource with this name exists (for backward compatibility).
|
||||
*/
|
||||
virtual void ExposeAudio(gd::String &audioName);
|
||||
|
||||
/**
|
||||
* \brief Expose a font, which is either a reference to a "font" resource,
|
||||
* or a filename if no resource with this name exists.
|
||||
* or a filename if no resource with this name exists (for backward compatibility).
|
||||
*/
|
||||
virtual void ExposeFont(gd::String &fontName);
|
||||
|
||||
/**
|
||||
* \brief Expose a bitmap font, which is either a reference to a "bitmapFont" resource,
|
||||
* or a filename if no resource with this name exists.
|
||||
* \brief Expose a bitmap font, which is always a reference to a "bitmapFont" resource.
|
||||
*/
|
||||
virtual void ExposeBitmapFont(gd::String &bitmapFontName);
|
||||
|
||||
|
@@ -14,25 +14,6 @@ using namespace std;
|
||||
|
||||
namespace gd {
|
||||
|
||||
bool ProjectResourcesAdder::AddAllMissing(gd::Project& project,
|
||||
const gd::String& resourceType) {
|
||||
// Search for resources used in the project
|
||||
gd::ResourcesInUseHelper resourcesInUse;
|
||||
project.ExposeResources(resourcesInUse);
|
||||
|
||||
ResourcesManager& resourcesManager = project.GetResourcesManager();
|
||||
for (auto& resourceName : resourcesInUse.GetAll(resourceType)) {
|
||||
if (!resourcesManager.HasResource(resourceName)) {
|
||||
std::cout << "Adding missing resource \"" << resourceName
|
||||
<< "\"to the project." << std::endl;
|
||||
resourcesManager.AddResource(
|
||||
resourceName, /*filename=*/resourceName, resourceType);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<gd::String> ProjectResourcesAdder::GetAllUseless(
|
||||
gd::Project& project, const gd::String& resourceType) {
|
||||
std::vector<gd::String> unusedResources;
|
||||
@@ -42,15 +23,13 @@ std::vector<gd::String> ProjectResourcesAdder::GetAllUseless(
|
||||
std::set<gd::String>& usedResources = resourcesInUse.GetAll(resourceType);
|
||||
|
||||
// Search all resources not used
|
||||
std::vector<gd::String> resources =
|
||||
project.GetResourcesManager().GetAllResourceNames();
|
||||
const std::vector<std::shared_ptr<Resource>>& resources =
|
||||
project.GetResourcesManager().GetAllResources();
|
||||
for (std::size_t i = 0; i < resources.size(); i++) {
|
||||
if (project.GetResourcesManager().GetResource(resources[i]).GetKind() !=
|
||||
resourceType)
|
||||
continue;
|
||||
if (resources[i]->GetKind() != resourceType) continue;
|
||||
|
||||
if (usedResources.find(resources[i]) == usedResources.end())
|
||||
unusedResources.push_back(resources[i]);
|
||||
if (usedResources.find(resources[i]->GetName()) == usedResources.end())
|
||||
unusedResources.push_back(resources[i]->GetName());
|
||||
}
|
||||
|
||||
return unusedResources;
|
||||
|
@@ -20,17 +20,6 @@ namespace gd {
|
||||
*/
|
||||
class GD_CORE_API ProjectResourcesAdder {
|
||||
public:
|
||||
/**
|
||||
* \brief Update the project so that all missing resources are added, with an
|
||||
* filename that is equal to the missing resource name.
|
||||
*
|
||||
* \param project The project to be updated.
|
||||
* \param resourceType The type of the resource the be searched
|
||||
*
|
||||
* \return true if no error happened
|
||||
*/
|
||||
static bool AddAllMissing(gd::Project& project, const gd::String & resourceType);
|
||||
|
||||
/**
|
||||
* \brief Find all resources of the specified kind that are
|
||||
* not used by the project.
|
||||
|
@@ -22,7 +22,7 @@ void ResourcesMergingHelper::ExposeFile(gd::String& resourceFilename) {
|
||||
resourceFullFilename = gd::AbstractFileSystem::NormalizeSeparator(
|
||||
resourceFullFilename); // Protect against \ on Linux.
|
||||
|
||||
// In the case of absolute filnames that we don't want to preserve, or
|
||||
// In the case of absolute filenames that we don't want to preserve, or
|
||||
// in the case of copying files without preserving relative folders, the new
|
||||
// names will be generated from the filename alone (with collision protection).
|
||||
auto stripToFilenameOnly = [&]() {
|
||||
|
@@ -71,7 +71,7 @@ class GD_CORE_API ResourcesMergingHelper : public ArbitraryResourceWorker {
|
||||
* Resources merging helper collects all resources filenames and update these
|
||||
* filenames.
|
||||
*/
|
||||
virtual void ExposeFile(gd::String& resource);
|
||||
virtual void ExposeFile(gd::String& resource) override;
|
||||
|
||||
protected:
|
||||
void SetNewFilename(gd::String oldFilename, gd::String newFilename);
|
||||
|
@@ -33,8 +33,9 @@ class ResourcesRenamer : public gd::ArbitraryResourceWorker {
|
||||
: gd::ArbitraryResourceWorker(), oldToNewNames(oldToNewNames_){};
|
||||
virtual ~ResourcesRenamer(){};
|
||||
|
||||
virtual void ExposeFile(gd::String& resourceName) override {
|
||||
RenameIfNeeded(resourceName);
|
||||
virtual void ExposeFile(gd::String& resourceFileName) override{
|
||||
// Don't do anything: we're renaming resources, not the files they are
|
||||
// pointing to.
|
||||
};
|
||||
virtual void ExposeImage(gd::String& imageResourceName) override {
|
||||
RenameIfNeeded(imageResourceName);
|
||||
@@ -45,6 +46,9 @@ class ResourcesRenamer : public gd::ArbitraryResourceWorker {
|
||||
virtual void ExposeFont(gd::String& fontResourceName) override {
|
||||
RenameIfNeeded(fontResourceName);
|
||||
};
|
||||
virtual void ExposeBitmapFont(gd::String& bitmapFontName) override {
|
||||
RenameIfNeeded(bitmapFontName);
|
||||
};
|
||||
|
||||
private:
|
||||
void RenameIfNeeded(gd::String& resourceName) {
|
||||
|
@@ -238,7 +238,7 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
};
|
||||
|
||||
auto renameBehaviorEventsFunction =
|
||||
[&project, &eventsFunctionsExtension, &oldName, &newName](
|
||||
[&project, &oldName, &newName](
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::EventsFunction& eventsFunction) {
|
||||
if (eventsFunction.GetFunctionType() == gd::EventsFunction::Action ||
|
||||
@@ -261,7 +261,7 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
};
|
||||
|
||||
auto renameBehaviorPropertyFunctions =
|
||||
[&project, &eventsFunctionsExtension, &oldName, &newName](
|
||||
[&project, &oldName, &newName](
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::NamedPropertyDescriptor& property) {
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
@@ -805,7 +805,6 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
auto renameBehaviorEventsFunction =
|
||||
[&project,
|
||||
&eventsFunctionsExtension,
|
||||
&eventsBasedBehavior,
|
||||
&oldBehaviorName,
|
||||
&newBehaviorName](const gd::EventsFunction& eventsFunction) {
|
||||
if (eventsFunction.GetFunctionType() == gd::EventsFunction::Action ||
|
||||
@@ -832,7 +831,6 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
|
||||
auto renameBehaviorProperty = [&project,
|
||||
&eventsFunctionsExtension,
|
||||
&eventsBasedBehavior,
|
||||
&oldBehaviorName,
|
||||
&newBehaviorName](
|
||||
const gd::NamedPropertyDescriptor&
|
||||
|
@@ -36,6 +36,7 @@ void EventsFunctionsExtension::Init(const gd::EventsFunctionsExtension& other) {
|
||||
fullName = other.fullName;
|
||||
tags = other.tags;
|
||||
author = other.author;
|
||||
authorIds = other.authorIds;
|
||||
previewIconUrl = other.previewIconUrl;
|
||||
iconUrl = other.iconUrl;
|
||||
helpPath = other.helpPath;
|
||||
@@ -55,6 +56,11 @@ void EventsFunctionsExtension::SerializeTo(SerializerElement& element) const {
|
||||
for (const auto& tag : tags) {
|
||||
tagsElement.AddChild("").SetStringValue(tag);
|
||||
}
|
||||
auto& authorIdsElement = element.AddChild("authorIds");
|
||||
authorIdsElement.ConsiderAsArray();
|
||||
for (const auto& authorId : authorIds) {
|
||||
authorIdsElement.AddChild("").SetStringValue(authorId);
|
||||
}
|
||||
element.SetAttribute("author", author);
|
||||
element.SetAttribute("previewIconUrl", previewIconUrl);
|
||||
element.SetAttribute("iconUrl", iconUrl);
|
||||
@@ -99,6 +105,13 @@ void EventsFunctionsExtension::UnserializeFrom(
|
||||
}
|
||||
}
|
||||
|
||||
authorIds.clear();
|
||||
auto& authorIdsElement = element.GetChild("authorIds");
|
||||
authorIdsElement.ConsiderAsArray();
|
||||
for (std::size_t i = 0; i < authorIdsElement.GetChildrenCount(); ++i) {
|
||||
authorIds.push_back(authorIdsElement.GetChild(i).GetStringValue());
|
||||
}
|
||||
|
||||
dependencies.clear();
|
||||
const auto& dependenciesElement = element.GetChild("dependencies");
|
||||
dependenciesElement.ConsiderAsArray();
|
||||
|
@@ -88,6 +88,9 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
|
||||
const std::vector<gd::String>& GetTags() const { return tags; };
|
||||
std::vector<gd::String>& GetTags() { return tags; };
|
||||
|
||||
const std::vector<gd::String>& GetAuthorIds() const { return authorIds; };
|
||||
std::vector<gd::String>& GetAuthorIds() { return authorIds; };
|
||||
|
||||
const gd::String& GetAuthor() const { return author; };
|
||||
EventsFunctionsExtension& SetAuthor(const gd::String& author_) {
|
||||
author = author_;
|
||||
@@ -220,6 +223,7 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
|
||||
gd::String name;
|
||||
gd::String fullName;
|
||||
std::vector<gd::String> tags;
|
||||
std::vector<gd::String> authorIds;
|
||||
gd::String author;
|
||||
gd::String previewIconUrl;
|
||||
gd::String iconUrl;
|
||||
|
@@ -52,12 +52,12 @@ class GD_CORE_API ExtensionProperties {
|
||||
/**
|
||||
* \brief Serialize the Extension Properties.
|
||||
*/
|
||||
virtual void SerializeTo(SerializerElement& element) const;
|
||||
void SerializeTo(SerializerElement& element) const;
|
||||
|
||||
/**
|
||||
* \brief Unserialize the Extension Properties.
|
||||
*/
|
||||
virtual void UnserializeFrom(const SerializerElement& element);
|
||||
void UnserializeFrom(const SerializerElement& element);
|
||||
///@}
|
||||
|
||||
private:
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#include "GDCore/Project/ExternalEvents.h"
|
||||
|
||||
#include "ExternalEvents.h"
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/Serialization.h"
|
||||
@@ -48,4 +48,3 @@ void ExternalEvents::UnserializeFrom(gd::Project& project,
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
#endif
|
||||
|
@@ -3,12 +3,12 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#ifndef GDCORE_EXTERNALEVENTS_H
|
||||
#define GDCORE_EXTERNALEVENTS_H
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
@@ -135,4 +135,3 @@ struct ExternalEventsHasName
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EXTERNALEVENTS_H
|
||||
#endif
|
||||
|
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "GDCore/Project/ExternalLayout.h"
|
||||
|
||||
#include "GDCore/IDE/Dialogs/LayoutEditorCanvas/EditorSettings.h"
|
||||
#include "GDCore/Project/InitialInstancesContainer.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
@@ -15,19 +16,15 @@ namespace gd {
|
||||
void ExternalLayout::UnserializeFrom(const SerializerElement& element) {
|
||||
name = element.GetStringAttribute("name", "", "Name");
|
||||
instances.UnserializeFrom(element.GetChild("instances", 0, "Instances"));
|
||||
#if defined(GD_IDE_ONLY)
|
||||
editorSettings.UnserializeFrom(element.GetChild("editionSettings"));
|
||||
#endif
|
||||
associatedLayout = element.GetStringAttribute("associatedLayout");
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
void ExternalLayout::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("name", name);
|
||||
instances.SerializeTo(element.AddChild("instances"));
|
||||
editorSettings.SerializeTo(element.AddChild("editionSettings"));
|
||||
element.SetAttribute("associatedLayout", associatedLayout);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -7,14 +7,13 @@
|
||||
#ifndef GDCORE_EXTERNALLAYOUT_H
|
||||
#define GDCORE_EXTERNALLAYOUT_H
|
||||
#include <memory>
|
||||
|
||||
#include "GDCore/Project/InitialInstancesContainer.h"
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class SerializerElement;
|
||||
}
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#include "GDCore/IDE/Dialogs/LayoutEditorCanvas/EditorSettings.h"
|
||||
#endif
|
||||
|
||||
namespace gd {
|
||||
|
||||
@@ -54,7 +53,6 @@ class GD_CORE_API ExternalLayout {
|
||||
*/
|
||||
gd::InitialInstancesContainer& GetInitialInstances() { return instances; }
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* \brief Get the user settings for the IDE.
|
||||
*/
|
||||
@@ -65,10 +63,7 @@ class GD_CORE_API ExternalLayout {
|
||||
/**
|
||||
* \brief Get the user settings for the IDE.
|
||||
*/
|
||||
gd::EditorSettings& GetAssociatedEditorSettings() {
|
||||
return editorSettings;
|
||||
}
|
||||
#endif
|
||||
gd::EditorSettings& GetAssociatedEditorSettings() { return editorSettings; }
|
||||
|
||||
/**
|
||||
* \brief Get the name of the layout last used to edit the external layout.
|
||||
@@ -80,15 +75,13 @@ class GD_CORE_API ExternalLayout {
|
||||
*/
|
||||
void SetAssociatedLayout(const gd::String& name) { associatedLayout = name; }
|
||||
|
||||
/** \name Serialization
|
||||
*/
|
||||
///@{
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/** \name Serialization
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* \brief Serialize external layout.
|
||||
*/
|
||||
void SerializeTo(SerializerElement& element) const;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Unserialize the external layout.
|
||||
@@ -99,9 +92,7 @@ class GD_CORE_API ExternalLayout {
|
||||
private:
|
||||
gd::String name;
|
||||
gd::InitialInstancesContainer instances;
|
||||
#if defined(GD_IDE_ONLY)
|
||||
gd::EditorSettings editorSettings;
|
||||
#endif
|
||||
gd::String associatedLayout;
|
||||
};
|
||||
|
||||
|
@@ -50,6 +50,10 @@ class GD_CORE_API LoadingScreen {
|
||||
return backgroundImageResourceName;
|
||||
};
|
||||
|
||||
gd::String& GetBackgroundImageResourceName() {
|
||||
return backgroundImageResourceName;
|
||||
};
|
||||
|
||||
LoadingScreen& SetBackgroundImageResourceName(const gd::String& value) {
|
||||
backgroundImageResourceName = value;
|
||||
return *this;
|
||||
|
@@ -87,7 +87,6 @@ class GD_CORE_API ObjectsContainer {
|
||||
*/
|
||||
std::size_t GetObjectsCount() const;
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* \brief Add a new empty object of type \a objectType called \a name at the
|
||||
* specified position in the list.<br>
|
||||
@@ -99,7 +98,6 @@ class GD_CORE_API ObjectsContainer {
|
||||
const gd::String& objectType,
|
||||
const gd::String& name,
|
||||
std::size_t position);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Add a new object to the list
|
||||
@@ -176,7 +174,6 @@ class GD_CORE_API ObjectsContainer {
|
||||
*/
|
||||
///@{
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* \brief Return a reference to the project's objects groups.
|
||||
*/
|
||||
@@ -186,7 +183,6 @@ class GD_CORE_API ObjectsContainer {
|
||||
* \brief Return a const reference to the project's objects groups.
|
||||
*/
|
||||
const ObjectGroupsContainer& GetObjectGroups() const { return objectGroups; }
|
||||
#endif
|
||||
|
||||
///@}
|
||||
|
||||
|
@@ -49,14 +49,11 @@ using namespace std;
|
||||
namespace gd {
|
||||
|
||||
Project::Project()
|
||||
:
|
||||
#if defined(GD_IDE_ONLY)
|
||||
name(_("Project")),
|
||||
: name(_("Project")),
|
||||
version("1.0.0"),
|
||||
packageName("com.example.gamename"),
|
||||
orientation("landscape"),
|
||||
folderProject(false),
|
||||
#endif
|
||||
windowWidth(800),
|
||||
windowHeight(600),
|
||||
maxFPS(60),
|
||||
@@ -67,17 +64,12 @@ Project::Project()
|
||||
adaptGameResolutionAtRuntime(true),
|
||||
sizeOnStartupMode("adaptWidth"),
|
||||
projectUuid(""),
|
||||
useDeprecatedZeroAsDefaultZOrder(false)
|
||||
#if defined(GD_IDE_ONLY)
|
||||
,
|
||||
useDeprecatedZeroAsDefaultZOrder(false),
|
||||
useExternalSourceFiles(false),
|
||||
currentPlatform(NULL),
|
||||
gdMajorVersion(gd::VersionWrapper::Major()),
|
||||
gdMinorVersion(gd::VersionWrapper::Minor()),
|
||||
gdBuildVersion(gd::VersionWrapper::Build())
|
||||
#endif
|
||||
{
|
||||
}
|
||||
gdBuildVersion(gd::VersionWrapper::Build()) {}
|
||||
|
||||
Project::~Project() {}
|
||||
|
||||
@@ -102,7 +94,6 @@ std::unique_ptr<gd::Object> Project::CreateObject(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
std::shared_ptr<gd::BaseEvent> Project::CreateEvent(
|
||||
const gd::String& type, const gd::String& platformName) {
|
||||
for (std::size_t i = 0; i < platforms.size(); ++i) {
|
||||
@@ -161,7 +152,6 @@ bool Project::RemovePlatform(const gd::String& platformName) {
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool Project::HasLayoutNamed(const gd::String& name) const {
|
||||
return (find_if(scenes.begin(),
|
||||
@@ -188,13 +178,11 @@ std::size_t Project::GetLayoutPosition(const gd::String& name) const {
|
||||
}
|
||||
std::size_t Project::GetLayoutsCount() const { return scenes.size(); }
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
void Project::SwapLayouts(std::size_t first, std::size_t second) {
|
||||
if (first >= scenes.size() || second >= scenes.size()) return;
|
||||
|
||||
std::iter_swap(scenes.begin() + first, scenes.begin() + second);
|
||||
}
|
||||
#endif
|
||||
|
||||
gd::Layout& Project::InsertNewLayout(const gd::String& name,
|
||||
std::size_t position) {
|
||||
@@ -203,9 +191,7 @@ gd::Layout& Project::InsertNewLayout(const gd::String& name,
|
||||
new Layout())));
|
||||
|
||||
newlyInsertedLayout.SetName(name);
|
||||
#if defined(GD_IDE_ONLY)
|
||||
newlyInsertedLayout.UpdateBehaviorsSharedData(*this);
|
||||
#endif
|
||||
|
||||
return newlyInsertedLayout;
|
||||
}
|
||||
@@ -216,9 +202,7 @@ gd::Layout& Project::InsertLayout(const gd::Layout& layout,
|
||||
position < scenes.size() ? scenes.begin() + position : scenes.end(),
|
||||
new Layout(layout))));
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
newlyInsertedLayout.UpdateBehaviorsSharedData(*this);
|
||||
#endif
|
||||
|
||||
return newlyInsertedLayout;
|
||||
}
|
||||
@@ -231,7 +215,6 @@ void Project::RemoveLayout(const gd::String& name) {
|
||||
scenes.erase(scene);
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
bool Project::HasExternalEventsNamed(const gd::String& name) const {
|
||||
return (find_if(externalEvents.begin(),
|
||||
externalEvents.end(),
|
||||
@@ -311,7 +294,6 @@ void Project::SwapExternalLayouts(std::size_t first, std::size_t second) {
|
||||
std::iter_swap(externalLayouts.begin() + first,
|
||||
externalLayouts.begin() + second);
|
||||
}
|
||||
#endif
|
||||
bool Project::HasExternalLayoutNamed(const gd::String& name) const {
|
||||
return (find_if(externalLayouts.begin(),
|
||||
externalLayouts.end(),
|
||||
@@ -377,7 +359,6 @@ void Project::RemoveExternalLayout(const gd::String& name) {
|
||||
externalLayouts.erase(externalLayout);
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
void Project::SwapEventsFunctionsExtensions(std::size_t first,
|
||||
std::size_t second) {
|
||||
if (first >= eventsFunctionsExtensions.size() ||
|
||||
@@ -476,11 +457,8 @@ void Project::RemoveEventsFunctionsExtension(const gd::String& name) {
|
||||
void Project::ClearEventsFunctionsExtensions() {
|
||||
eventsFunctionsExtensions.clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
// Checking version
|
||||
#if defined(GD_IDE_ONLY)
|
||||
const SerializerElement& gdVersionElement =
|
||||
element.GetChild("gdVersion", 0, "GDVersion");
|
||||
gdMajorVersion =
|
||||
@@ -513,7 +491,6 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
"available.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
const SerializerElement& propElement =
|
||||
element.GetChild("properties", 0, "Info");
|
||||
@@ -534,7 +511,6 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
propElement.GetBoolAttribute("adaptGameResolutionAtRuntime", false));
|
||||
SetSizeOnStartupMode(propElement.GetStringAttribute("sizeOnStartupMode", ""));
|
||||
SetProjectUuid(propElement.GetStringAttribute("projectUuid", ""));
|
||||
#if defined(GD_IDE_ONLY)
|
||||
SetAuthor(propElement.GetChild("author", 0, "Auteur").GetValue().GetString());
|
||||
SetPackageName(propElement.GetStringAttribute("packageName"));
|
||||
SetOrientation(propElement.GetStringAttribute("orientation", "default"));
|
||||
@@ -552,6 +528,13 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
useExternalSourceFiles =
|
||||
propElement.GetBoolAttribute("useExternalSourceFiles");
|
||||
|
||||
authorIds.clear();
|
||||
auto& authorIdsElement = propElement.GetChild("authorIds");
|
||||
authorIdsElement.ConsiderAsArray();
|
||||
for (std::size_t i = 0; i < authorIdsElement.GetChildrenCount(); ++i) {
|
||||
authorIds.push_back(authorIdsElement.GetChild(i).GetStringValue());
|
||||
}
|
||||
|
||||
// Compatibility with GD <= 5.0.0-beta101
|
||||
if (VersionWrapper::IsOlderOrEqual(
|
||||
gdMajorVersion, gdMinorVersion, gdBuildVersion, 0, 4, 0, 98, 0) &&
|
||||
@@ -583,9 +566,6 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
}
|
||||
// end of compatibility code
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
currentPlatform = NULL;
|
||||
gd::String currentPlatformName =
|
||||
propElement.GetChild("currentPlatform").GetValue().GetString();
|
||||
@@ -635,12 +615,9 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
|
||||
if (currentPlatform == NULL && !platforms.empty())
|
||||
currentPlatform = platforms.back();
|
||||
#endif
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
GetObjectGroups().UnserializeFrom(
|
||||
element.GetChild("objectsGroups", 0, "ObjectGroups"));
|
||||
#endif
|
||||
resourcesManager.UnserializeFrom(
|
||||
element.GetChild("resources", 0, "Resources"));
|
||||
UnserializeObjectsFrom(*this, element.GetChild("objects", 0, "Objects"));
|
||||
@@ -658,7 +635,6 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
layout.UnserializeFrom(*this, layoutElement);
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
externalEvents.clear();
|
||||
const SerializerElement& externalEventsElement =
|
||||
element.GetChild("externalEvents", 0, "ExternalEvents");
|
||||
@@ -690,7 +666,6 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
newEventsFunctionsExtension.UnserializeFrom(
|
||||
*this, eventsFunctionsExtensionElement);
|
||||
}
|
||||
#endif
|
||||
|
||||
externalLayouts.clear();
|
||||
const SerializerElement& externalLayoutsElement =
|
||||
@@ -705,7 +680,6 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
newExternalLayout.UnserializeFrom(externalLayoutElement);
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
externalSourceFiles.clear();
|
||||
const SerializerElement& externalSourceFilesElement =
|
||||
element.GetChild("externalSourceFiles", 0, "ExternalSourceFiles");
|
||||
@@ -718,10 +692,8 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
gd::SourceFile& newSourceFile = InsertNewSourceFile("", "");
|
||||
newSourceFile.UnserializeFrom(sourceFileElement);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
void Project::SerializeTo(SerializerElement& element) const {
|
||||
SerializerElement& versionElement = element.AddChild("gdVersion");
|
||||
versionElement.SetAttribute("major", gd::VersionWrapper::Major());
|
||||
@@ -755,6 +727,12 @@ void Project::SerializeTo(SerializerElement& element) const {
|
||||
loadingScreen.SerializeTo(propElement.AddChild("loadingScreen"));
|
||||
propElement.SetAttribute("useExternalSourceFiles", useExternalSourceFiles);
|
||||
|
||||
auto& authorIdsElement = propElement.AddChild("authorIds");
|
||||
authorIdsElement.ConsiderAsArray();
|
||||
for (const auto& authorId : authorIds) {
|
||||
authorIdsElement.AddChild("").SetStringValue(authorId);
|
||||
}
|
||||
|
||||
// Compatibility with GD <= 5.0.0-beta101
|
||||
if (useDeprecatedZeroAsDefaultZOrder) {
|
||||
propElement.SetAttribute("useDeprecatedZeroAsDefaultZOrder", true);
|
||||
@@ -865,6 +843,10 @@ void Project::ExposeResources(gd::ArbitraryResourceWorker& worker) {
|
||||
for (std::size_t j = 0; j < GetObjectsCount(); ++j) {
|
||||
GetObject(j).ExposeResources(worker);
|
||||
}
|
||||
|
||||
// Add loading screen background image if present
|
||||
if (loadingScreen.GetBackgroundImageResourceName() != "")
|
||||
worker.ExposeImage(loadingScreen.GetBackgroundImageResourceName());
|
||||
}
|
||||
|
||||
bool Project::HasSourceFile(gd::String name, gd::String language) const {
|
||||
@@ -915,7 +897,6 @@ gd::SourceFile& Project::InsertNewSourceFile(const gd::String& name,
|
||||
|
||||
return newlyInsertedSourceFile;
|
||||
}
|
||||
#endif
|
||||
|
||||
Project::Project(const Project& other) { Init(other); }
|
||||
|
||||
@@ -940,8 +921,8 @@ void Project::Init(const gd::Project& game) {
|
||||
projectUuid = game.projectUuid;
|
||||
useDeprecatedZeroAsDefaultZOrder = game.useDeprecatedZeroAsDefaultZOrder;
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
author = game.author;
|
||||
authorIds = game.authorIds;
|
||||
packageName = game.packageName;
|
||||
orientation = game.orientation;
|
||||
folderProject = game.folderProject;
|
||||
@@ -957,33 +938,26 @@ void Project::Init(const gd::Project& game) {
|
||||
gdBuildVersion = game.gdBuildVersion;
|
||||
|
||||
currentPlatform = game.currentPlatform;
|
||||
#endif
|
||||
platforms = game.platforms;
|
||||
|
||||
resourcesManager = game.resourcesManager;
|
||||
|
||||
|
||||
initialObjects = gd::Clone(game.initialObjects);
|
||||
|
||||
scenes = gd::Clone(game.scenes);
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
externalEvents = gd::Clone(game.externalEvents);
|
||||
#endif
|
||||
|
||||
externalLayouts = gd::Clone(game.externalLayouts);
|
||||
#if defined(GD_IDE_ONLY)
|
||||
eventsFunctionsExtensions = gd::Clone(game.eventsFunctionsExtensions);
|
||||
|
||||
useExternalSourceFiles = game.useExternalSourceFiles;
|
||||
|
||||
externalSourceFiles = gd::Clone(game.externalSourceFiles);
|
||||
#endif
|
||||
|
||||
variables = game.GetVariables();
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
projectFile = game.GetProjectFile();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -77,7 +77,6 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
*/
|
||||
const gd::String& GetVersion() const { return version; }
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* \brief Change the author of the project.
|
||||
*/
|
||||
@@ -88,6 +87,16 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
*/
|
||||
const gd::String& GetAuthor() const { return author; }
|
||||
|
||||
/**
|
||||
* \brief Get the author ids of the project.
|
||||
*/
|
||||
const std::vector<gd::String>& GetAuthorIds() const { return authorIds; };
|
||||
|
||||
/**
|
||||
* \brief Get the author ids of the project, to modify them (non-const).
|
||||
*/
|
||||
std::vector<gd::String>& GetAuthorIds() { return authorIds; };
|
||||
|
||||
/**
|
||||
* \brief Change project package name.
|
||||
*/
|
||||
@@ -178,7 +187,6 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
* \brief Return a reference to loading screen setup for the project
|
||||
*/
|
||||
const gd::LoadingScreen& GetLoadingScreen() const { return loadingScreen; }
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Change game's main window default width.
|
||||
@@ -279,16 +287,13 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
/**
|
||||
* Return true if pixels rounding option is enabled.
|
||||
*/
|
||||
bool GetPixelsRounding() const {
|
||||
return pixelsRounding;
|
||||
}
|
||||
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
|
||||
@@ -325,7 +330,6 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
*/
|
||||
void ResetProjectUuid();
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* \brief Get the properties set by extensions.
|
||||
*
|
||||
@@ -376,7 +380,6 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
* current platform won't be changed.
|
||||
*/
|
||||
void SetCurrentPlatform(const gd::String& platformName);
|
||||
#endif
|
||||
|
||||
///@}
|
||||
|
||||
@@ -402,7 +405,6 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
const gd::String& name,
|
||||
const gd::String& platformName = "");
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* Create an event of the given type.
|
||||
*
|
||||
@@ -418,7 +420,6 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
std::shared_ptr<gd::BaseEvent> CreateEvent(
|
||||
const gd::String& type, const gd::String& platformName = "");
|
||||
///@}
|
||||
#endif
|
||||
|
||||
/** \name Layouts management
|
||||
* Members functions related to layout management.
|
||||
@@ -456,14 +457,12 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
*/
|
||||
std::size_t GetLayoutPosition(const gd::String& name) const;
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* \brief Swap the specified layouts.
|
||||
*
|
||||
* Do nothing if indexes are not correct.
|
||||
*/
|
||||
void SwapLayouts(std::size_t first, std::size_t second);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Return the number of layouts.
|
||||
@@ -502,7 +501,6 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
*/
|
||||
void UnserializeFrom(const SerializerElement& element);
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* \brief Serialize the project.
|
||||
*
|
||||
@@ -524,13 +522,11 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
* Get the minor version of GDevelop used to save the project.
|
||||
*/
|
||||
unsigned int GetLastSaveGDBuildVersion() { return gdBuildVersion; };
|
||||
#endif
|
||||
|
||||
/** \name External events management
|
||||
* Members functions related to external events management.
|
||||
*/
|
||||
///@{
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/** \name External events management
|
||||
* Members functions related to external events management.
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* Return true if external events called "name" exists.
|
||||
*/
|
||||
@@ -598,7 +594,6 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
* \brief Delete external events named "name".
|
||||
*/
|
||||
void RemoveExternalEvents(const gd::String& name);
|
||||
#endif
|
||||
///@}
|
||||
|
||||
/** \name External layout management
|
||||
@@ -639,14 +634,12 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
*/
|
||||
std::size_t GetExternalLayoutPosition(const gd::String& name) const;
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* \brief Swap the specified external layouts.
|
||||
*
|
||||
* Do nothing if indexes are not correct.
|
||||
*/
|
||||
void SwapExternalLayouts(std::size_t first, std::size_t second);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Return the number of external layout.
|
||||
@@ -690,12 +683,11 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
*/
|
||||
const gd::String& GetFirstLayout() { return firstLayout; }
|
||||
|
||||
///@}
|
||||
///@}
|
||||
|
||||
/** \name Events functions extensions management
|
||||
*/
|
||||
///@{
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/** \name Events functions extensions management
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* \brief Check if events functions extension called "name" exists.
|
||||
*/
|
||||
@@ -770,7 +762,6 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
* \brief Remove all the events functions extensions.
|
||||
*/
|
||||
void ClearEventsFunctionsExtensions();
|
||||
#endif
|
||||
///@}
|
||||
|
||||
/** \name Resources management
|
||||
@@ -833,13 +824,12 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
* behavior, events function name, etc...).
|
||||
*/
|
||||
static bool ValidateName(const gd::String& name);
|
||||
///@}
|
||||
///@}
|
||||
|
||||
/** \name External source files
|
||||
* To manage external C++ or Javascript source files used by the game
|
||||
*/
|
||||
///@{
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/** \name External source files
|
||||
* To manage external C++ or Javascript source files used by the game
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* \brief Return true if the game activated the use of external source files.
|
||||
*/
|
||||
@@ -884,8 +874,7 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
gd::SourceFile& InsertNewSourceFile(const gd::String& name,
|
||||
const gd::String& language,
|
||||
std::size_t position = -1);
|
||||
#endif
|
||||
///@}
|
||||
///@}
|
||||
|
||||
private:
|
||||
/**
|
||||
@@ -903,8 +892,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 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
|
||||
@@ -921,23 +910,22 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
gd::VariablesContainer variables; ///< Initial global variables
|
||||
std::vector<std::unique_ptr<gd::ExternalLayout> >
|
||||
externalLayouts; ///< List of all externals layouts
|
||||
#if defined(GD_IDE_ONLY)
|
||||
std::vector<std::unique_ptr<gd::EventsFunctionsExtension> >
|
||||
eventsFunctionsExtensions;
|
||||
#endif
|
||||
gd::ResourcesManager
|
||||
resourcesManager; ///< Contains all resources used by the project
|
||||
std::vector<gd::Platform*>
|
||||
platforms; ///< Pointers to the platforms this project supports.
|
||||
gd::String firstLayout;
|
||||
#if defined(GD_IDE_ONLY)
|
||||
bool useExternalSourceFiles; ///< True if game used external source files.
|
||||
std::vector<std::unique_ptr<gd::SourceFile> >
|
||||
externalSourceFiles; ///< List of external source files used.
|
||||
gd::String author; ///< Game author name
|
||||
gd::String packageName; ///< Game package name
|
||||
gd::String orientation; ///< Lock game orientation (on mobile devices).
|
||||
///< "default", "landscape" or "portrait".
|
||||
gd::String author; ///< Game author name, for publishing purpose.
|
||||
std::vector<gd::String>
|
||||
authorIds; ///< Game author ids, from GDevelop users DB.
|
||||
gd::String packageName; ///< Game package name
|
||||
gd::String orientation; ///< Lock game orientation (on mobile devices).
|
||||
///< "default", "landscape" or "portrait".
|
||||
bool
|
||||
folderProject; ///< True if folder project, false if single file project.
|
||||
gd::String
|
||||
@@ -957,7 +945,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.
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
@@ -130,6 +131,22 @@ std::vector<gd::String> ResourcesManager::GetAllResourceNames() const {
|
||||
return allResources;
|
||||
}
|
||||
|
||||
std::vector<gd::String> ResourcesManager::FindFilesNotInResources(
|
||||
const std::vector<gd::String>& filesToCheck) const {
|
||||
std::unordered_set<gd::String> resourceFiles;
|
||||
for (const auto& resource: resources) {
|
||||
resourceFiles.insert(resource->GetFile());
|
||||
}
|
||||
|
||||
std::vector<gd::String> filesNotInResources;
|
||||
for(const gd::String& file: filesToCheck) {
|
||||
if (resourceFiles.find(file) == resourceFiles.end())
|
||||
filesNotInResources.push_back(file);
|
||||
}
|
||||
|
||||
return filesNotInResources;
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
std::map<gd::String, gd::PropertyDescriptor> Resource::GetProperties() const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> nothing;
|
||||
@@ -159,7 +176,8 @@ bool ImageResource::UpdateProperty(const gd::String& name,
|
||||
return true;
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> AudioResource::GetProperties() const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> AudioResource::GetProperties()
|
||||
const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties;
|
||||
properties[_("Preload as sound")]
|
||||
.SetValue(preloadAsSound ? "true" : "false")
|
||||
|
@@ -243,7 +243,7 @@ class GD_CORE_API AudioResource : public Resource {
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetProperties() const override;
|
||||
bool UpdateProperty(const gd::String& name, const gd::String& value) override;
|
||||
|
||||
|
||||
void SerializeTo(SerializerElement& element) const override;
|
||||
#endif
|
||||
|
||||
@@ -447,11 +447,22 @@ class GD_CORE_API ResourcesManager {
|
||||
*/
|
||||
std::shared_ptr<Resource> CreateResource(const gd::String& kind);
|
||||
|
||||
/**
|
||||
* Get a list containing all the resources.
|
||||
*/
|
||||
const std::vector<std::shared_ptr<Resource>>& GetAllResources() const { return resources; };
|
||||
|
||||
/**
|
||||
* \brief Get a list containing the names of all resources.
|
||||
*/
|
||||
std::vector<gd::String> GetAllResourceNames() const;
|
||||
|
||||
/**
|
||||
* \brief Return a list of the files, from the specified input list,
|
||||
* that are not used as files by the resources.
|
||||
*/
|
||||
std::vector<gd::String> FindFilesNotInResources(const std::vector<gd::String>& filesToCheck) const;
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* \brief Return a (smart) pointer to a resource.
|
||||
|
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "GDCore/String.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string.h>
|
||||
|
||||
#include <SFML/System/String.hpp>
|
||||
@@ -283,6 +284,42 @@ String& String::insert( size_type pos, const String &str )
|
||||
return *this;
|
||||
}
|
||||
|
||||
String& String::replace_if(iterator i1, iterator i2, std::function<bool(char32_t)> p, const String &str)
|
||||
{
|
||||
String::size_type offset = 1;
|
||||
iterator it = i1.base();
|
||||
while(it < i2.base())
|
||||
{
|
||||
if (p(*it)) { replace(std::distance(begin(), it), offset, str); }
|
||||
else { it++; }
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
String& String::RemoveConsecutiveOccurrences(iterator i1, iterator i2, const char c)
|
||||
{
|
||||
std::vector<std::pair<size_type, size_type>> ranges_to_remove;
|
||||
for(iterator current_index = i1.base(); current_index < i2.base(); current_index++)
|
||||
{
|
||||
if (*current_index == c){
|
||||
iterator current_subindex = current_index;
|
||||
std::advance(current_subindex, 1);
|
||||
if (*current_subindex == c) {
|
||||
while(current_subindex < end() && *current_subindex == c)
|
||||
{
|
||||
current_subindex++;
|
||||
}
|
||||
replace(std::distance(begin(), current_index),
|
||||
std::distance(current_index, current_subindex),
|
||||
c);
|
||||
|
||||
std::advance(current_index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
String& String::replace( iterator i1, iterator i2, const String &str )
|
||||
{
|
||||
m_string.replace(i1.base(), i2.base(), str.m_string);
|
||||
@@ -290,6 +327,31 @@ String& String::replace( iterator i1, iterator i2, const String &str )
|
||||
return *this;
|
||||
}
|
||||
|
||||
String& String::replace( iterator i1, iterator i2, size_type n, const char c )
|
||||
{
|
||||
m_string.replace(i1.base(), i2.base(), n, c);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
String& String::replace( String::size_type pos, String::size_type len, const char c )
|
||||
{
|
||||
if(pos > size())
|
||||
throw std::out_of_range("[gd::String::replace] starting pos greater than size");
|
||||
|
||||
iterator i1 = begin();
|
||||
std::advance( i1, pos );
|
||||
|
||||
iterator i2 = i1;
|
||||
while(i2 != end() && len > 0) //Increment "len" times and stop if end() is reached
|
||||
{
|
||||
++i2;
|
||||
--len;
|
||||
}
|
||||
|
||||
return replace( i1, i2, 1, c );
|
||||
}
|
||||
|
||||
String& String::replace( String::size_type pos, String::size_type len, const String &str )
|
||||
{
|
||||
if(pos > size())
|
||||
|
@@ -438,15 +438,52 @@ public:
|
||||
*/
|
||||
String& replace( iterator i1, iterator i2, const String &str );
|
||||
|
||||
/**
|
||||
* \brief Replace the portion of the String between **i1** and **i2** (**i2** not
|
||||
* included) by **n** consecutive copies of character **c**.
|
||||
* \return *this
|
||||
*
|
||||
* **Iterators :** All iterators may be invalidated.
|
||||
*/
|
||||
String& replace( iterator i1, iterator i2, size_type n, const char c );
|
||||
|
||||
/**
|
||||
* \brief Replace the portion of the String between **pos** and **pos** + **len**
|
||||
* (the character at **pos** + **len** is not included)
|
||||
* (the character at **pos** + **len** is not included) with **str**.
|
||||
* \return *this
|
||||
*
|
||||
* **Iterators :** All iterators may be invalidated.
|
||||
*/
|
||||
String& replace( size_type pos, size_type len, const String &str );
|
||||
|
||||
/**
|
||||
* \brief Replace the portion of the String between **pos** and **pos** + **len**
|
||||
* (the character at **pos** + **len** is not included) with the character **c**.
|
||||
* \return *this
|
||||
*
|
||||
* **Iterators :** All iterators may be invalidated.
|
||||
*/
|
||||
String& replace( size_type pos, size_type len, const char c );
|
||||
|
||||
/**
|
||||
* \brief Search in the portion of the String between **i1** and **i2** (**i2** not
|
||||
* included) for characters matching predicate function **p** and replace them
|
||||
* by the String **str**.
|
||||
* \return *this
|
||||
*
|
||||
* **Iterators :** All iterators may be invalidated.
|
||||
*/
|
||||
String& replace_if( iterator i1, iterator i2, std::function<bool(char32_t)> p, const String &str );
|
||||
|
||||
/**
|
||||
* \brief Remove consecutive occurrences of the character **c** in the portion of the
|
||||
* between **i1** and **i2** (**i2** not included) to replace it by a single occurrence.
|
||||
* \return *this
|
||||
*
|
||||
* **Iterators :** All iterators may be invalidated.
|
||||
*/
|
||||
String& RemoveConsecutiveOccurrences(iterator i1, iterator i2, const char c);
|
||||
|
||||
/**
|
||||
* \brief Erase the characters between **first** and **last** (**last** not included).
|
||||
* \param first an iterator to the first character to remove
|
||||
|
132
Core/tests/ArbitraryResourceWorker.cpp
Normal file
132
Core/tests/ArbitraryResourceWorker.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
/**
|
||||
* @file Tests covering common features of GDevelop Core.
|
||||
*/
|
||||
#include <string>
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
|
||||
#include "GDCore/IDE/Project/ProjectResourcesAdder.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Events/Builtin/StandardEvent.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Serialization/Serializer.h"
|
||||
#include "GDCore/Tools/SystemStats.h"
|
||||
#include "GDCore/Tools/VersionWrapper.h"
|
||||
#include "DummyPlatform.h"
|
||||
#include "catch.hpp"
|
||||
|
||||
class ArbitraryResourceWorkerTest : public gd::ArbitraryResourceWorker {
|
||||
public:
|
||||
virtual void ExposeFile(gd::String& file) { files.push_back(file); };
|
||||
virtual void ExposeImage(gd::String& imageName) {
|
||||
images.push_back(imageName);
|
||||
};
|
||||
virtual void ExposeBitmapFont(gd::String& bitmapFontName) {
|
||||
bitmapFonts.push_back(bitmapFontName);
|
||||
};
|
||||
virtual void ExposeAudio(gd::String& audioName) {
|
||||
audios.push_back(audioName);
|
||||
};
|
||||
|
||||
std::vector<gd::String> files;
|
||||
std::vector<gd::String> images;
|
||||
std::vector<gd::String> bitmapFonts;
|
||||
std::vector<gd::String> audios;
|
||||
};
|
||||
|
||||
TEST_CASE("ArbitraryResourceWorker", "[common][resources]") {
|
||||
SECTION("Basics") {
|
||||
gd::Project project;
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res1", "path/to/file1.png", "image");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res2", "path/to/file2.png", "image");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res3", "path/to/file3.png", "image");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res4", "path/to/file4.png", "audio");
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
project.ExposeResources(worker);
|
||||
REQUIRE(worker.files.size() == 4);
|
||||
REQUIRE(std::find(worker.files.begin(),
|
||||
worker.files.end(),
|
||||
"path/to/file2.png") != worker.files.end());
|
||||
REQUIRE(std::find(worker.files.begin(),
|
||||
worker.files.end(),
|
||||
"path/to/file4.png") != worker.files.end());
|
||||
|
||||
SECTION("Object using a resource") {
|
||||
gd::SpriteObject obj("myObject");
|
||||
|
||||
gd::Animation anim;
|
||||
gd::Sprite sprite;
|
||||
sprite.SetImageName("res1");
|
||||
anim.SetDirectionsCount(1);
|
||||
anim.GetDirection(0).AddSprite(sprite);
|
||||
obj.AddAnimation(anim);
|
||||
project.InsertObject(obj, 0);
|
||||
|
||||
worker.files.clear();
|
||||
worker.images.clear();
|
||||
project.ExposeResources(worker);
|
||||
REQUIRE(worker.files.size() == 4);
|
||||
REQUIRE(worker.images.size() == 1);
|
||||
REQUIRE(worker.images[0] == "res1");
|
||||
|
||||
SECTION("ProjectResourcesAdder") {
|
||||
std::vector<gd::String> uselessResources =
|
||||
gd::ProjectResourcesAdder::GetAllUseless(project, "image");
|
||||
|
||||
REQUIRE(uselessResources.size() == 2);
|
||||
|
||||
gd::ProjectResourcesAdder::RemoveAllUseless(project, "image");
|
||||
std::vector<gd::String> remainingResources =
|
||||
project.GetResourcesManager().GetAllResourceNames();
|
||||
REQUIRE(remainingResources.size() == 2);
|
||||
REQUIRE(remainingResources[0] == "res1");
|
||||
REQUIRE(remainingResources[1] == "res4");
|
||||
}
|
||||
}
|
||||
}
|
||||
SECTION("With events") {
|
||||
gd::Platform platform;
|
||||
gd::Project project;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res1", "path/to/file1.png", "image");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res2", "path/to/file2.png", "image");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res3", "path/to/file3.fnt", "bitmapFont");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res4", "path/to/file4.png", "audio");
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
auto& layout = project.InsertNewLayout("Scene", 0);
|
||||
|
||||
gd::StandardEvent standardEvent;
|
||||
gd::Instruction instruction;
|
||||
instruction.SetType("MyExtension::DoSomethingWithResources");
|
||||
instruction.SetParametersCount(3);
|
||||
instruction.SetParameter(0, "res3");
|
||||
instruction.SetParameter(1, "res1");
|
||||
instruction.SetParameter(2, "res4");
|
||||
standardEvent.GetActions().Insert(instruction);
|
||||
layout.GetEvents().InsertEvent(standardEvent);
|
||||
|
||||
project.ExposeResources(worker);
|
||||
REQUIRE(worker.bitmapFonts.size() == 1);
|
||||
REQUIRE(worker.bitmapFonts[0] == "res3");
|
||||
REQUIRE(worker.images.size() == 1);
|
||||
REQUIRE(worker.images[0] == "res1");
|
||||
REQUIRE(worker.audios.size() == 1);
|
||||
REQUIRE(worker.audios[0] == "res4");
|
||||
}
|
||||
}
|
@@ -96,6 +96,7 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
|
||||
std::shared_ptr<gd::PlatformExtension>(new gd::PlatformExtension);
|
||||
extension->SetExtensionInformation(
|
||||
"MyExtension", "My testing extension", "", "", "");
|
||||
|
||||
extension
|
||||
->AddAction("DoSomething",
|
||||
"Do something",
|
||||
@@ -106,6 +107,20 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
|
||||
"")
|
||||
.AddParameter("expression", "Parameter 1 (a number)")
|
||||
.SetFunctionName("doSomething");
|
||||
|
||||
extension
|
||||
->AddAction("DoSomethingWithResources",
|
||||
"Do something with resources",
|
||||
"This does something with resources",
|
||||
"Do something with resources please",
|
||||
"",
|
||||
"",
|
||||
"")
|
||||
.AddParameter("bitmapFontResource", "Parameter 1 (a bitmap font resource)")
|
||||
.AddParameter("imageResource", "Parameter 2 (an image resource)")
|
||||
.AddParameter("soundfile", "Parameter 3 (an audio resource)")
|
||||
.SetFunctionName("doSomethingWithResources");
|
||||
|
||||
extension->AddExpression("GetNumber", "Get me a number", "", "", "")
|
||||
.SetFunctionName("getNumber");
|
||||
extension
|
||||
|
@@ -87,42 +87,27 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
}
|
||||
}
|
||||
SECTION("Operator (number)") {
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions1{
|
||||
gd::ExpressionCompletionDescription::ForObject("number", "", 1, 1),
|
||||
gd::ExpressionCompletionDescription::ForExpression("number", "", 1, 1)};
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions2{
|
||||
gd::ExpressionCompletionDescription::ForObject("number", "", 2, 2),
|
||||
gd::ExpressionCompletionDescription::ForExpression("number", "", 2, 2)};
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions3{
|
||||
gd::ExpressionCompletionDescription::ForObject("number", "", 3, 3),
|
||||
gd::ExpressionCompletionDescription::ForExpression("number", "", 3, 3)};
|
||||
REQUIRE(getCompletionsFor("number", "1 + ", 1) == expectedCompletions1);
|
||||
REQUIRE(getCompletionsFor("number", "1 + ", 2) == expectedCompletions2);
|
||||
REQUIRE(getCompletionsFor("number", "1 + ", 3) == expectedCompletions3);
|
||||
REQUIRE(getCompletionsFor("number", "1 + ", 1) == expectedEmptyCompletions);
|
||||
REQUIRE(getCompletionsFor("number", "1 + ", 2) == expectedEmptyCompletions);
|
||||
REQUIRE(getCompletionsFor("number", "1 + ", 3) == expectedEmptyCompletions);
|
||||
}
|
||||
SECTION("Operator (string)") {
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions3{
|
||||
gd::ExpressionCompletionDescription::ForObject("string", "", 3, 3),
|
||||
gd::ExpressionCompletionDescription::ForExpression("string", "", 3, 3)};
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions4{
|
||||
gd::ExpressionCompletionDescription::ForObject("string", "", 4, 4),
|
||||
gd::ExpressionCompletionDescription::ForExpression("string", "", 4, 4)};
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions5{
|
||||
gd::ExpressionCompletionDescription::ForObject("string", "", 5, 5),
|
||||
gd::ExpressionCompletionDescription::ForExpression("string", "", 5, 5)};
|
||||
REQUIRE(getCompletionsFor("string", "\"a\" + ", 3) == expectedCompletions3);
|
||||
REQUIRE(getCompletionsFor("string", "\"a\" + ", 4) == expectedCompletions4);
|
||||
REQUIRE(getCompletionsFor("string", "\"a\" + ", 5) == expectedCompletions5);
|
||||
REQUIRE(getCompletionsFor("string", "\"a\" + ", 3) ==
|
||||
expectedEmptyCompletions);
|
||||
REQUIRE(getCompletionsFor("string", "\"a\" + ", 4) ==
|
||||
expectedEmptyCompletions);
|
||||
REQUIRE(getCompletionsFor("string", "\"a\" + ", 5) ==
|
||||
expectedEmptyCompletions);
|
||||
}
|
||||
|
||||
SECTION("Free function") {
|
||||
SECTION("Test 1") {
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
|
||||
gd::ExpressionCompletionDescription::ForExpression(
|
||||
"unknown", "Function", 0, 8)};
|
||||
"string", "Function", 0, 8)};
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedExactCompletions{
|
||||
gd::ExpressionCompletionDescription::ForExpression(
|
||||
"unknown", "Function", 0, 8)
|
||||
"string", "Function", 0, 8)
|
||||
.SetIsExact(true)};
|
||||
REQUIRE(getCompletionsFor("string", "Function(", 0) ==
|
||||
expectedCompletions);
|
||||
@@ -230,17 +215,17 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
std::vector<gd::ExpressionCompletionDescription>
|
||||
expectedObjectCompletions{
|
||||
gd::ExpressionCompletionDescription::ForObject(
|
||||
"unknown", "MyObject", 0, 8)};
|
||||
"string", "MyObject", 0, 8)};
|
||||
std::vector<gd::ExpressionCompletionDescription>
|
||||
expectedBehaviorOrFunctionCompletions{
|
||||
gd::ExpressionCompletionDescription::ForBehavior(
|
||||
"Func", 9, 13, "MyObject"),
|
||||
gd::ExpressionCompletionDescription::ForExpression(
|
||||
"unknown", "Func", 9, 13, "MyObject")};
|
||||
"string", "Func", 9, 13, "MyObject")};
|
||||
std::vector<gd::ExpressionCompletionDescription>
|
||||
expectedExactFunctionCompletions{
|
||||
gd::ExpressionCompletionDescription::ForExpression(
|
||||
"unknown", "Func", 9, 13, "MyObject")
|
||||
"string", "Func", 9, 13, "MyObject")
|
||||
.SetIsExact(true)};
|
||||
REQUIRE(getCompletionsFor("string", "MyObject.Func(", 0) ==
|
||||
expectedObjectCompletions);
|
||||
@@ -329,7 +314,7 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
std::vector<gd::ExpressionCompletionDescription>
|
||||
expectedObjectCompletions{
|
||||
gd::ExpressionCompletionDescription::ForObject(
|
||||
"unknown", "MyObject", 0, 8)};
|
||||
"string", "MyObject", 0, 8)};
|
||||
std::vector<gd::ExpressionCompletionDescription>
|
||||
expectedBehaviorCompletions{
|
||||
gd::ExpressionCompletionDescription::ForBehavior(
|
||||
@@ -337,11 +322,11 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
std::vector<gd::ExpressionCompletionDescription>
|
||||
expectedFunctionCompletions{
|
||||
gd::ExpressionCompletionDescription::ForExpression(
|
||||
"unknown", "Func", 21, 25, "MyObject", "MyBehavior")};
|
||||
"string", "Func", 21, 25, "MyObject", "MyBehavior")};
|
||||
std::vector<gd::ExpressionCompletionDescription>
|
||||
expectedExactFunctionCompletions{
|
||||
gd::ExpressionCompletionDescription::ForExpression(
|
||||
"unknown", "Func", 21, 25, "MyObject", "MyBehavior")
|
||||
"string", "Func", 21, 25, "MyObject", "MyBehavior")
|
||||
.SetIsExact(true)};
|
||||
REQUIRE(getCompletionsFor("string", "MyObject.MyBehavior::Func(", 0) ==
|
||||
expectedObjectCompletions);
|
||||
|
@@ -971,6 +971,35 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
REQUIRE(objectFunctionName.objectFunctionOrBehaviorName == "");
|
||||
}
|
||||
|
||||
SECTION("Unfinished object function name of type string with parentheses") {
|
||||
auto node = parser.ParseExpression("string", "MyObject.()");
|
||||
REQUIRE(node != nullptr);
|
||||
auto &objectFunctionCall = dynamic_cast<gd::FunctionCallNode &>(*node);
|
||||
REQUIRE(objectFunctionCall.objectName == "MyObject");
|
||||
REQUIRE(objectFunctionCall.functionName == "");
|
||||
REQUIRE(objectFunctionCall.type == "string");
|
||||
}
|
||||
|
||||
SECTION("Unfinished object function name of type number with parentheses") {
|
||||
auto node = parser.ParseExpression("number", "MyObject.()");
|
||||
REQUIRE(node != nullptr);
|
||||
auto &objectFunctionCall = dynamic_cast<gd::FunctionCallNode &>(*node);
|
||||
REQUIRE(objectFunctionCall.objectName == "MyObject");
|
||||
REQUIRE(objectFunctionCall.functionName == "");
|
||||
REQUIRE(objectFunctionCall.type == "number");
|
||||
}
|
||||
|
||||
SECTION(
|
||||
"Unfinished object function name of type number|string with "
|
||||
"parentheses") {
|
||||
auto node = parser.ParseExpression("number|string", "MyObject.()");
|
||||
REQUIRE(node != nullptr);
|
||||
auto &objectFunctionCall = dynamic_cast<gd::FunctionCallNode &>(*node);
|
||||
REQUIRE(objectFunctionCall.objectName == "MyObject");
|
||||
REQUIRE(objectFunctionCall.functionName == "");
|
||||
REQUIRE(objectFunctionCall.type == "number|string");
|
||||
}
|
||||
|
||||
SECTION("Unfinished object behavior name") {
|
||||
auto node = parser.ParseExpression("string", "MyObject.MyBehavior::");
|
||||
REQUIRE(node != nullptr);
|
||||
@@ -981,6 +1010,67 @@ TEST_CASE("ExpressionParser2", "[common][events]") {
|
||||
REQUIRE(objectFunctionName.behaviorFunctionName == "");
|
||||
}
|
||||
|
||||
SECTION("Unfinished object behavior name of type string with parentheses") {
|
||||
auto node = parser.ParseExpression("string", "MyObject.MyBehavior::()");
|
||||
REQUIRE(node != nullptr);
|
||||
auto &objectFunctionName = dynamic_cast<gd::FunctionCallNode &>(*node);
|
||||
REQUIRE(objectFunctionName.objectName == "MyObject");
|
||||
REQUIRE(objectFunctionName.behaviorName == "MyBehavior");
|
||||
REQUIRE(objectFunctionName.functionName == "");
|
||||
REQUIRE(objectFunctionName.type == "string");
|
||||
}
|
||||
|
||||
SECTION("Unfinished object behavior name of type number with parentheses") {
|
||||
auto node = parser.ParseExpression("number", "MyObject.MyBehavior::()");
|
||||
REQUIRE(node != nullptr);
|
||||
auto &objectFunctionName = dynamic_cast<gd::FunctionCallNode &>(*node);
|
||||
REQUIRE(objectFunctionName.objectName == "MyObject");
|
||||
REQUIRE(objectFunctionName.behaviorName == "MyBehavior");
|
||||
REQUIRE(objectFunctionName.functionName == "");
|
||||
REQUIRE(objectFunctionName.type == "number");
|
||||
}
|
||||
|
||||
SECTION(
|
||||
"Unfinished object behavior name of type number|string with "
|
||||
"parentheses") {
|
||||
auto node =
|
||||
parser.ParseExpression("number|string", "MyObject.MyBehavior::()");
|
||||
REQUIRE(node != nullptr);
|
||||
auto &objectFunctionName = dynamic_cast<gd::FunctionCallNode &>(*node);
|
||||
REQUIRE(objectFunctionName.objectName == "MyObject");
|
||||
REQUIRE(objectFunctionName.behaviorName == "MyBehavior");
|
||||
REQUIRE(objectFunctionName.functionName == "");
|
||||
REQUIRE(objectFunctionName.type == "number|string");
|
||||
}
|
||||
|
||||
SECTION("Unfinished free function name of type string with parentheses") {
|
||||
auto node = parser.ParseExpression("string", "fun()");
|
||||
REQUIRE(node != nullptr);
|
||||
auto &freeFunctionCall = dynamic_cast<gd::FunctionCallNode &>(*node);
|
||||
REQUIRE(freeFunctionCall.objectName == "");
|
||||
REQUIRE(freeFunctionCall.functionName == "fun");
|
||||
REQUIRE(freeFunctionCall.type == "string");
|
||||
}
|
||||
|
||||
SECTION("Unfinished free function name of type number with parentheses") {
|
||||
auto node = parser.ParseExpression("number", "fun()");
|
||||
REQUIRE(node != nullptr);
|
||||
auto &freeFunctionCall = dynamic_cast<gd::FunctionCallNode &>(*node);
|
||||
REQUIRE(freeFunctionCall.objectName == "");
|
||||
REQUIRE(freeFunctionCall.functionName == "fun");
|
||||
REQUIRE(freeFunctionCall.type == "number");
|
||||
}
|
||||
|
||||
SECTION(
|
||||
"Unfinished free function name of type number|string with parentheses") {
|
||||
auto node = parser.ParseExpression("number|string", "fun()");
|
||||
REQUIRE(node != nullptr);
|
||||
auto &freeFunctionCall = dynamic_cast<gd::FunctionCallNode &>(*node);
|
||||
REQUIRE(freeFunctionCall.objectName == "");
|
||||
REQUIRE(freeFunctionCall.functionName == "fun");
|
||||
REQUIRE(freeFunctionCall.type == "number|string");
|
||||
}
|
||||
|
||||
SECTION("Invalid function calls") {
|
||||
{
|
||||
auto node = parser.ParseExpression("number", "Idontexist(12)");
|
||||
|
77
Core/tests/InstructionsParameterMover.cpp
Normal file
77
Core/tests/InstructionsParameterMover.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
/**
|
||||
* @file Tests covering common features of GDevelop Core.
|
||||
*/
|
||||
#include "GDCore/IDE/Events/InstructionsParameterMover.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "DummyPlatform.h"
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Events/Builtin/StandardEvent.h"
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
|
||||
#include "GDCore/IDE/Project/ProjectResourcesAdder.h"
|
||||
#include "GDCore/IDE/WholeProjectRefactorer.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Serialization/Serializer.h"
|
||||
#include "GDCore/Tools/SystemStats.h"
|
||||
#include "GDCore/Tools/VersionWrapper.h"
|
||||
#include "catch.hpp"
|
||||
|
||||
TEST_CASE("InstructionsParameterMover", "[common][events]") {
|
||||
gd::Platform platform;
|
||||
gd::Project project;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
auto& layout = project.InsertNewLayout("Scene", 0);
|
||||
|
||||
gd::StandardEvent standardEvent;
|
||||
gd::Instruction instruction;
|
||||
instruction.SetType("MyExtension::DoSomething");
|
||||
instruction.SetParametersCount(3);
|
||||
instruction.SetParameter(0, "Param1");
|
||||
instruction.SetParameter(1, "Param2");
|
||||
instruction.SetParameter(2, "Param3");
|
||||
standardEvent.GetActions().Insert(instruction);
|
||||
layout.GetEvents().InsertEvent(standardEvent);
|
||||
|
||||
gd::Instruction& insertedInstruction =
|
||||
dynamic_cast<gd::StandardEvent&>(layout.GetEvents().GetEvent(0))
|
||||
.GetActions()
|
||||
.Get(0);
|
||||
|
||||
SECTION("Move a parameter from one valid index to another") {
|
||||
gd::InstructionsParameterMover mover(
|
||||
project, "MyExtension::DoSomething", 0, 2);
|
||||
|
||||
gd::WholeProjectRefactorer::ExposeProjectEvents(project, mover);
|
||||
REQUIRE(insertedInstruction.GetParameter(0).GetPlainString() == "Param2");
|
||||
REQUIRE(insertedInstruction.GetParameter(1).GetPlainString() == "Param3");
|
||||
REQUIRE(insertedInstruction.GetParameter(2).GetPlainString() == "Param1");
|
||||
}
|
||||
SECTION("Move a parameter to an out of bound new index") {
|
||||
gd::InstructionsParameterMover mover(
|
||||
project, "MyExtension::DoSomething", 0, 99);
|
||||
|
||||
gd::WholeProjectRefactorer::ExposeProjectEvents(project, mover);
|
||||
REQUIRE(insertedInstruction.GetParameter(0).GetPlainString() == "Param2");
|
||||
REQUIRE(insertedInstruction.GetParameter(1).GetPlainString() == "Param3");
|
||||
REQUIRE(insertedInstruction.GetParameter(2).GetPlainString() == "Param1");
|
||||
}
|
||||
SECTION("Don't move a parameter if out of bound old index") {
|
||||
gd::InstructionsParameterMover mover(
|
||||
project, "MyExtension::DoSomething", 99, 2);
|
||||
|
||||
gd::WholeProjectRefactorer::ExposeProjectEvents(project, mover);
|
||||
REQUIRE(insertedInstruction.GetParameter(0).GetPlainString() == "Param1");
|
||||
REQUIRE(insertedInstruction.GetParameter(1).GetPlainString() == "Param2");
|
||||
REQUIRE(insertedInstruction.GetParameter(2).GetPlainString() == "Param3");
|
||||
}
|
||||
}
|
@@ -7,27 +7,13 @@
|
||||
* @file Tests covering common features of GDevelop Core.
|
||||
*/
|
||||
#include <string>
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
|
||||
#include "GDCore/IDE/Project/ProjectResourcesAdder.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Serialization/Serializer.h"
|
||||
#include "GDCore/Tools/SystemStats.h"
|
||||
#include "GDCore/Tools/VersionWrapper.h"
|
||||
#include "catch.hpp"
|
||||
|
||||
class ArbitraryResourceWorkerTest : public gd::ArbitraryResourceWorker {
|
||||
public:
|
||||
virtual void ExposeFile(gd::String& file) { files.push_back(file); };
|
||||
virtual void ExposeImage(gd::String& imageName) {
|
||||
images.push_back(imageName);
|
||||
};
|
||||
|
||||
std::vector<gd::String> files;
|
||||
std::vector<gd::String> images;
|
||||
};
|
||||
|
||||
TEST_CASE("Resources", "[common][resources]") {
|
||||
SECTION("Basics") {
|
||||
gd::ImageResource image;
|
||||
@@ -46,58 +32,4 @@ TEST_CASE("Resources", "[common][resources]") {
|
||||
image.SetFile("Lots\\\\Of\\\\\\..\\Backslashs");
|
||||
REQUIRE(image.GetFile() == "Lots//Of///../Backslashs");
|
||||
}
|
||||
SECTION("ArbitraryResourceWorker") {
|
||||
gd::Project project;
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res1", "path/to/file1.png", "image");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res2", "path/to/file2.png", "image");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res3", "path/to/file3.png", "image");
|
||||
project.GetResourcesManager().AddResource(
|
||||
"res4", "path/to/file4.png", "audio");
|
||||
ArbitraryResourceWorkerTest worker;
|
||||
|
||||
project.ExposeResources(worker);
|
||||
REQUIRE(worker.files.size() == 4);
|
||||
REQUIRE(std::find(worker.files.begin(),
|
||||
worker.files.end(),
|
||||
"path/to/file2.png") != worker.files.end());
|
||||
REQUIRE(std::find(worker.files.begin(),
|
||||
worker.files.end(),
|
||||
"path/to/file4.png") != worker.files.end());
|
||||
|
||||
SECTION("Object using a resource") {
|
||||
gd::SpriteObject obj("myObject");
|
||||
|
||||
gd::Animation anim;
|
||||
gd::Sprite sprite;
|
||||
sprite.SetImageName("res1");
|
||||
anim.SetDirectionsCount(1);
|
||||
anim.GetDirection(0).AddSprite(sprite);
|
||||
obj.AddAnimation(anim);
|
||||
project.InsertObject(obj, 0);
|
||||
|
||||
worker.files.clear();
|
||||
worker.images.clear();
|
||||
project.ExposeResources(worker);
|
||||
REQUIRE(worker.files.size() == 4);
|
||||
REQUIRE(worker.images.size() == 1);
|
||||
REQUIRE(worker.images[0] == "res1");
|
||||
|
||||
SECTION("ProjectResourcesAdder") {
|
||||
std::vector<gd::String> uselessResources =
|
||||
gd::ProjectResourcesAdder::GetAllUseless(project, "image");
|
||||
|
||||
REQUIRE(uselessResources.size() == 2);
|
||||
|
||||
gd::ProjectResourcesAdder::RemoveAllUseless(project, "image");
|
||||
std::vector<gd::String> remainingResources =
|
||||
project.GetResourcesManager().GetAllResourceNames();
|
||||
REQUIRE(remainingResources.size() == 2);
|
||||
REQUIRE(remainingResources[0] == "res1");
|
||||
REQUIRE(remainingResources[1] == "res4");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2,6 +2,8 @@ namespace gdjs {
|
||||
declare var admob: any;
|
||||
|
||||
export namespace adMob {
|
||||
const logger = new gdjs.Logger('AdMob');
|
||||
|
||||
export enum AdSizeType {
|
||||
BANNER,
|
||||
LARGE_BANNER,
|
||||
@@ -127,13 +129,13 @@ namespace gdjs {
|
||||
() => {
|
||||
bannerShowing = true;
|
||||
bannerLoading = false;
|
||||
console.info('AdMob banner successfully shown.');
|
||||
logger.info('AdMob banner successfully shown.');
|
||||
},
|
||||
(error) => {
|
||||
bannerShowing = false;
|
||||
bannerLoading = false;
|
||||
bannerErrored = true;
|
||||
console.error('Error while showing an AdMob banner:', error);
|
||||
logger.error('Error while showing an AdMob banner:', error);
|
||||
}
|
||||
);
|
||||
};
|
||||
@@ -190,14 +192,14 @@ namespace gdjs {
|
||||
})
|
||||
.then(
|
||||
() => {
|
||||
console.info('AdMob interstitial successfully loaded.');
|
||||
logger.info('AdMob interstitial successfully loaded.');
|
||||
if (displayWhenLoaded) showInterstitial();
|
||||
},
|
||||
(error) => {
|
||||
interstitialLoading = false;
|
||||
interstitialReady = false;
|
||||
interstitialErrored = true;
|
||||
console.error('Error while loading a interstitial:', error);
|
||||
logger.error('Error while loading a interstitial:', error);
|
||||
}
|
||||
);
|
||||
};
|
||||
@@ -216,7 +218,7 @@ namespace gdjs {
|
||||
(error) => {
|
||||
interstitialShowing = false;
|
||||
interstitialErrored = true;
|
||||
console.error('Error while trying to show an interstitial:', error);
|
||||
logger.error('Error while trying to show an interstitial:', error);
|
||||
}
|
||||
);
|
||||
};
|
||||
@@ -270,7 +272,7 @@ namespace gdjs {
|
||||
})
|
||||
.then(
|
||||
() => {
|
||||
console.info('AdMob reward video successfully loaded.');
|
||||
logger.info('AdMob reward video successfully loaded.');
|
||||
|
||||
if (displayWhenLoaded) showVideo();
|
||||
},
|
||||
@@ -278,7 +280,7 @@ namespace gdjs {
|
||||
videoLoading = false;
|
||||
videoReady = false;
|
||||
videoErrored = true;
|
||||
console.error('Error while loading a reward video:', error);
|
||||
logger.error('Error while loading a reward video:', error);
|
||||
}
|
||||
);
|
||||
};
|
||||
@@ -298,7 +300,7 @@ namespace gdjs {
|
||||
(error) => {
|
||||
videoShowing = false;
|
||||
videoErrored = true;
|
||||
console.error('Error while trying to show a reward video:', error);
|
||||
logger.error('Error while trying to show a reward video:', error);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
@@ -256,11 +256,7 @@ module.exports = {
|
||||
.addAction(
|
||||
'SetBitmapFontAndTextureAtlasResourceName',
|
||||
_('Bitmap files resources'),
|
||||
_('Change the Bitmap Font and/or the atlas image used by the object.') +
|
||||
' ' +
|
||||
_(
|
||||
'The resource name can be found in: `Project Manager > Game settings > Resources`.'
|
||||
),
|
||||
_('Change the Bitmap Font and/or the atlas image used by the object.'),
|
||||
_(
|
||||
'Set the bitmap font of _PARAM0_ to _PARAM1_ and the atlas to _PARAM2_'
|
||||
),
|
||||
@@ -269,7 +265,7 @@ module.exports = {
|
||||
'res/actions/font.png'
|
||||
)
|
||||
.addParameter('object', _('Bitmap text'), 'BitmapTextObject', false)
|
||||
.addParameter('bitmapFont', _('Bitmap font resource name'), '', false)
|
||||
.addParameter('bitmapFontResource', _('Bitmap font resource name'), '', false)
|
||||
.setParameterLongDescription(
|
||||
'The resource name of the font file, without quotes.'
|
||||
)
|
||||
@@ -658,6 +654,11 @@ module.exports = {
|
||||
// Release the old font (if it was installed).
|
||||
releaseBitmapFont(this._pixiObject.fontName);
|
||||
|
||||
// Temporarily go back to the default font, as the PIXI.BitmapText
|
||||
// object does not support being displayed with a font not installed at all.
|
||||
// It will be replaced as soon as the proper font is loaded.
|
||||
this._pixiObject.fontName = getDefaultBitmapFont().font;
|
||||
|
||||
this._currentBitmapFontResourceName = bitmapFontResourceName;
|
||||
this._currentTextureAtlasResourceName = textureAtlasResourceName;
|
||||
obtainBitmapFont(
|
||||
|
@@ -83,6 +83,30 @@ module.exports = {
|
||||
.setIncludeFile('Extensions/DebuggerTools/debuggertools.js')
|
||||
.setFunctionName('gdjs.evtTools.debuggerTools.enableDebugDraw');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'ConsoleLog',
|
||||
_('Log a message to the console'),
|
||||
_("Logs a message to the debugger's console."),
|
||||
_(
|
||||
'Log message _PARAM0_ of type _PARAM1_ to the console in group _PARAM2_'
|
||||
),
|
||||
_('Debugger Tools'),
|
||||
'res/actions/bug32.png',
|
||||
'res/actions/bug32.png'
|
||||
)
|
||||
.addParameter('string', 'Message to log', '', false)
|
||||
.addParameter(
|
||||
'stringWithSelector',
|
||||
'Message type',
|
||||
'["info", "warning", "error"]',
|
||||
true
|
||||
)
|
||||
.addParameter('string', 'Group of messages', '', true)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/DebuggerTools/debuggertools.js')
|
||||
.setFunctionName('gdjs.evtTools.debuggerTools.log');
|
||||
|
||||
return extension;
|
||||
},
|
||||
runExtensionSanityTests: function (
|
||||
|
@@ -13,6 +13,20 @@ namespace gdjs {
|
||||
runtimeScene.getGame().pause(true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Logs a message to the console.
|
||||
* @param message - The message to log.
|
||||
* @param type - The type of log (info, warning or error).
|
||||
* @param group - The group of messages it belongs to.
|
||||
*/
|
||||
export const log = function (
|
||||
message: string,
|
||||
type: 'info' | 'warning' | 'error',
|
||||
group: string
|
||||
) {
|
||||
gdjs.Logger.getLoggerOutput().log(group, message, type, false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Enable or disable the debug draw.
|
||||
* @param runtimeScene - The current scene.
|
||||
|
@@ -62,7 +62,7 @@ module.exports = {
|
||||
"JsPlatform/Extensions/orientation_alpha24.png",
|
||||
"JsPlatform/Extensions/orientation_alpha32.png"
|
||||
)
|
||||
.addParameter("relationalOperator", _("Sign of the test"))
|
||||
.addParameter("relationalOperator", _("Sign of the test"), "number")
|
||||
.addParameter("expression", _("Value"))
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
@@ -82,7 +82,7 @@ module.exports = {
|
||||
"JsPlatform/Extensions/orientation_beta24.png",
|
||||
"JsPlatform/Extensions/orientation_beta32.png"
|
||||
)
|
||||
.addParameter("relationalOperator", _("Sign of the test"))
|
||||
.addParameter("relationalOperator", _("Sign of the test"), "number")
|
||||
.addParameter("expression", _("Value"))
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
@@ -102,7 +102,7 @@ module.exports = {
|
||||
"JsPlatform/Extensions/orientation_gamma24.png",
|
||||
"JsPlatform/Extensions/orientation_gamma32.png"
|
||||
)
|
||||
.addParameter("relationalOperator", _("Sign of the test"))
|
||||
.addParameter("relationalOperator", _("Sign of the test"), "number")
|
||||
.addParameter("expression", _("Value"))
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
@@ -228,7 +228,7 @@ module.exports = {
|
||||
"JsPlatform/Extensions/motion_rotation_alpha24.png",
|
||||
"JsPlatform/Extensions/motion_rotation_alpha32.png"
|
||||
)
|
||||
.addParameter("relationalOperator", _("Sign of the test"))
|
||||
.addParameter("relationalOperator", _("Sign of the test"), "number")
|
||||
.addParameter("expression", _("Value (m/s²)"))
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
@@ -248,7 +248,7 @@ module.exports = {
|
||||
"JsPlatform/Extensions/motion_rotation_beta24.png",
|
||||
"JsPlatform/Extensions/motion_rotation_beta32.png"
|
||||
)
|
||||
.addParameter("relationalOperator", _("Sign of the test"))
|
||||
.addParameter("relationalOperator", _("Sign of the test"), "number")
|
||||
.addParameter("expression", _("Value (m/s²)"))
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
@@ -268,7 +268,7 @@ module.exports = {
|
||||
"JsPlatform/Extensions/motion_rotation_gamma24.png",
|
||||
"JsPlatform/Extensions/motion_rotation_gamma32.png"
|
||||
)
|
||||
.addParameter("relationalOperator", _("Sign of the test"))
|
||||
.addParameter("relationalOperator", _("Sign of the test"), "number")
|
||||
.addParameter("expression", _("Value (m/s²)"))
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
@@ -288,7 +288,7 @@ module.exports = {
|
||||
"JsPlatform/Extensions/motion_acceleration_x24.png",
|
||||
"JsPlatform/Extensions/motion_acceleration_x32.png"
|
||||
)
|
||||
.addParameter("relationalOperator", _("Sign of the test"))
|
||||
.addParameter("relationalOperator", _("Sign of the test"), "number")
|
||||
.addParameter("expression", _("Value (m/s²)"))
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
@@ -308,7 +308,7 @@ module.exports = {
|
||||
"JsPlatform/Extensions/motion_acceleration_y24.png",
|
||||
"JsPlatform/Extensions/motion_acceleration_y32.png"
|
||||
)
|
||||
.addParameter("relationalOperator", _("Sign of the test"))
|
||||
.addParameter("relationalOperator", _("Sign of the test"), "number")
|
||||
.addParameter("expression", _("Value (m/s²)"))
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
@@ -328,7 +328,7 @@ module.exports = {
|
||||
"JsPlatform/Extensions/motion_acceleration_z24.png",
|
||||
"JsPlatform/Extensions/motion_acceleration_z32.png"
|
||||
)
|
||||
.addParameter("relationalOperator", _("Sign of the test"))
|
||||
.addParameter("relationalOperator", _("Sign of the test"), "number")
|
||||
.addParameter("expression", _("Value (m/s²)"))
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
|
@@ -1,6 +1,8 @@
|
||||
// @ts-nocheck - Weird usage of `this` in this file. Should be refactored.
|
||||
|
||||
namespace gdjs {
|
||||
const logger = new gdjs.Logger('Dialogue tree');
|
||||
|
||||
gdjs.dialogueTree = {};
|
||||
gdjs.dialogueTree.runner = new bondage.Runner();
|
||||
|
||||
@@ -21,7 +23,7 @@ namespace gdjs {
|
||||
gdjs.dialogueTree.startFrom(startDialogueNode);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
logger.error('Error while loading from scene variable: ', e);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -42,10 +44,7 @@ namespace gdjs {
|
||||
.getJsonManager()
|
||||
.loadJson(jsonResourceName, function (error, content) {
|
||||
if (error) {
|
||||
console.error(
|
||||
'An error happened while loading JSON resource:',
|
||||
error
|
||||
);
|
||||
logger.error('An error happened while loading JSON resource:', error);
|
||||
} else {
|
||||
if (!content) {
|
||||
return;
|
||||
@@ -54,7 +53,7 @@ namespace gdjs {
|
||||
try {
|
||||
gdjs.dialogueTree.runner.load(gdjs.dialogueTree.yarnData);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
logger.error(
|
||||
'An error happened while loading parsing the dialogue tree data:',
|
||||
error
|
||||
);
|
||||
@@ -155,7 +154,7 @@ namespace gdjs {
|
||||
this.clipTextEnd >= this.dialogueText.length
|
||||
) {
|
||||
if (gdjs.dialogueTree.getVariable('debug')) {
|
||||
console.warn(
|
||||
logger.warn(
|
||||
'Scroll completed:',
|
||||
this.clipTextEnd,
|
||||
'/',
|
||||
@@ -244,7 +243,7 @@ namespace gdjs {
|
||||
gdjs.dialogueTree.pauseScrolling = false;
|
||||
commandCalls.splice(index, 1);
|
||||
if (gdjs.dialogueTree.getVariable('debug')) {
|
||||
console.info('CMD:', call);
|
||||
logger.info('CMD:', call);
|
||||
}
|
||||
}, parseInt(call.params[1], 10));
|
||||
}
|
||||
@@ -252,7 +251,7 @@ namespace gdjs {
|
||||
gdjs.dialogueTree.commandParameters = call.params;
|
||||
commandCalls.splice(index, 1);
|
||||
if (gdjs.dialogueTree.getVariable('debug')) {
|
||||
console.info('CMD:', call);
|
||||
logger.info('CMD:', call);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -366,7 +365,7 @@ namespace gdjs {
|
||||
this.dialogueData = this.dialogue.next().value;
|
||||
gdjs.dialogueTree.goToNextDialogueLine();
|
||||
} catch (error) {
|
||||
console.error(
|
||||
logger.error(
|
||||
`An error happened when trying to access the dialogue branch!`,
|
||||
error
|
||||
);
|
||||
@@ -562,7 +561,7 @@ namespace gdjs {
|
||||
this.selectedOption = -1;
|
||||
this.selectedOptionUpdated = false;
|
||||
if (gdjs.dialogueTree.getVariable('debug')) {
|
||||
console.info('parsing:', this.dialogueData);
|
||||
logger.info('Parsing:', this.dialogueData);
|
||||
}
|
||||
if (!this.dialogueData) {
|
||||
gdjs.dialogueTree.stopRunningDialogue();
|
||||
@@ -739,7 +738,7 @@ namespace gdjs {
|
||||
* @param key The name of the variable you want to get the value of
|
||||
*/
|
||||
gdjs.dialogueTree.getVariable = function (key: string) {
|
||||
if (this.dialogueIsRunning && key in this.runner.variables.data) {
|
||||
if (this.runner.variables && key in this.runner.variables.data) {
|
||||
return this.runner.variables.get(key);
|
||||
}
|
||||
return '';
|
||||
@@ -754,7 +753,7 @@ namespace gdjs {
|
||||
key: string,
|
||||
value: string | boolean | number
|
||||
) {
|
||||
if (this.dialogueIsRunning && key in this.runner.variables.data) {
|
||||
if (this.runner.variables && key in this.runner.variables.data) {
|
||||
return this.runner.variables.get(key) === value;
|
||||
}
|
||||
return false;
|
||||
@@ -797,7 +796,7 @@ namespace gdjs {
|
||||
gdjs.dialogueTree.loadState = function (inputVariable: gdjs.Variable) {
|
||||
const loadedState = inputVariable.toJSObject();
|
||||
if (!loadedState) {
|
||||
console.error('Load state variable is empty:', inputVariable);
|
||||
logger.error('Load state variable is empty:', inputVariable);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
@@ -808,7 +807,7 @@ namespace gdjs {
|
||||
gdjs.dialogueTree.runner.variables.set(key, value);
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('Failed to load state from variable:', inputVariable, e);
|
||||
logger.error('Failed to load state from variable:', inputVariable, e);
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
GDevelop - Draggable Behavior Extension
|
||||
Copyright (c) 2013-2016 Florian Rival (Florian.Rival@gmail.com)
|
||||
Copyright (c) 2013-2021 Florian Rival (Florian.Rival@gmail.com)
|
||||
*/
|
||||
|
||||
namespace gdjs {
|
||||
@@ -9,11 +9,11 @@ namespace gdjs {
|
||||
* moved using the mouse.
|
||||
*/
|
||||
export class DraggableRuntimeBehavior extends gdjs.RuntimeBehavior {
|
||||
_dragged: boolean = false;
|
||||
_touchId: any = null;
|
||||
_mouse: boolean = false;
|
||||
_xOffset: number = 0;
|
||||
_yOffset: number = 0;
|
||||
/**
|
||||
* The manager that currently handles the dragging of the owner if any.
|
||||
* When the owner is being dragged, no other manager can start dragging it.
|
||||
*/
|
||||
_draggedByDraggableManager: DraggableManager | null = null;
|
||||
|
||||
constructor(runtimeScene, behaviorData, owner) {
|
||||
super(runtimeScene, behaviorData, owner);
|
||||
@@ -33,59 +33,47 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
_endDrag() {
|
||||
if (this._dragged && this._mouse) {
|
||||
DraggableRuntimeBehavior.mouseDraggingSomething = false;
|
||||
if (this._draggedByDraggableManager) {
|
||||
this._draggedByDraggableManager.endDrag();
|
||||
}
|
||||
if (this._dragged && this._touchId !== null) {
|
||||
DraggableRuntimeBehavior.touchDraggingSomething[this._touchId] = false;
|
||||
}
|
||||
this._dragged = false;
|
||||
this._mouse = false;
|
||||
this._touchId = null;
|
||||
this._draggedByDraggableManager = null;
|
||||
}
|
||||
|
||||
_dismissDrag() {
|
||||
this._draggedByDraggableManager = null;
|
||||
}
|
||||
|
||||
_tryBeginDrag(runtimeScene) {
|
||||
if (this._dragged) {
|
||||
if (this._draggedByDraggableManager) {
|
||||
return false;
|
||||
}
|
||||
const inputManager = runtimeScene.getGame().getInputManager();
|
||||
|
||||
//Try mouse
|
||||
const mouseDraggableManager = DraggableManager.getMouseManager(
|
||||
runtimeScene
|
||||
);
|
||||
if (
|
||||
inputManager.isMouseButtonPressed(0) &&
|
||||
!DraggableRuntimeBehavior.leftPressedLastFrame &&
|
||||
!DraggableRuntimeBehavior.mouseDraggingSomething
|
||||
!mouseDraggableManager.isDragging(this)
|
||||
) {
|
||||
const mousePos = runtimeScene
|
||||
.getLayer(this.owner.getLayer())
|
||||
.convertCoords(inputManager.getMouseX(), inputManager.getMouseY());
|
||||
if (this.owner.insideObject(mousePos[0], mousePos[1])) {
|
||||
this._dragged = true;
|
||||
this._mouse = true;
|
||||
this._xOffset = mousePos[0] - this.owner.getX();
|
||||
this._yOffset = mousePos[1] - this.owner.getY();
|
||||
DraggableRuntimeBehavior.mouseDraggingSomething = true;
|
||||
if (mouseDraggableManager.tryAndTakeDragging(runtimeScene, this)) {
|
||||
this._draggedByDraggableManager = mouseDraggableManager;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
//Try touches
|
||||
const touchIds = inputManager.getStartedTouchIdentifiers();
|
||||
for (let i = 0; i < touchIds.length; ++i) {
|
||||
if (DraggableRuntimeBehavior.touchDraggingSomething[touchIds[i]]) {
|
||||
const touchDraggableManager = DraggableManager.getTouchManager(
|
||||
runtimeScene,
|
||||
touchIds[i]
|
||||
);
|
||||
if (touchDraggableManager.isDragging(this)) {
|
||||
continue;
|
||||
}
|
||||
const touchPos = runtimeScene
|
||||
.getLayer(this.owner.getLayer())
|
||||
.convertCoords(
|
||||
inputManager.getTouchX(touchIds[i]),
|
||||
inputManager.getTouchY(touchIds[i])
|
||||
);
|
||||
if (this.owner.insideObject(touchPos[0], touchPos[1])) {
|
||||
this._dragged = true;
|
||||
this._touchId = touchIds[i];
|
||||
this._xOffset = touchPos[0] - this.owner.getX();
|
||||
this._yOffset = touchPos[1] - this.owner.getY();
|
||||
DraggableRuntimeBehavior.touchDraggingSomething[touchIds[i]] = true;
|
||||
if (touchDraggableManager.tryAndTakeDragging(runtimeScene, this)) {
|
||||
this._draggedByDraggableManager = touchDraggableManager;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -94,45 +82,17 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
_shouldEndDrag(runtimeScene) {
|
||||
if (!this._dragged) {
|
||||
if (!this._draggedByDraggableManager) {
|
||||
return false;
|
||||
}
|
||||
const inputManager = runtimeScene.getGame().getInputManager();
|
||||
if (this._mouse) {
|
||||
return !inputManager.isMouseButtonPressed(0);
|
||||
} else {
|
||||
if (this._touchId !== null) {
|
||||
return (
|
||||
inputManager.getAllTouchIdentifiers().indexOf(this._touchId) === -1
|
||||
);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return this._draggedByDraggableManager.shouldEndDrag(runtimeScene, this);
|
||||
}
|
||||
|
||||
_updateObjectPosition(runtimeScene) {
|
||||
if (!this._dragged) {
|
||||
if (!this._draggedByDraggableManager) {
|
||||
return false;
|
||||
}
|
||||
const inputManager = runtimeScene.getGame().getInputManager();
|
||||
if (this._mouse) {
|
||||
const mousePos = runtimeScene
|
||||
.getLayer(this.owner.getLayer())
|
||||
.convertCoords(inputManager.getMouseX(), inputManager.getMouseY());
|
||||
this.owner.setX(mousePos[0] - this._xOffset);
|
||||
this.owner.setY(mousePos[1] - this._yOffset);
|
||||
} else {
|
||||
if (this._touchId !== null) {
|
||||
const touchPos = runtimeScene
|
||||
.getLayer(this.owner.getLayer())
|
||||
.convertCoords(
|
||||
inputManager.getTouchX(this._touchId),
|
||||
inputManager.getTouchY(this._touchId)
|
||||
);
|
||||
this.owner.setX(touchPos[0] - this._xOffset);
|
||||
this.owner.setY(touchPos[1] - this._yOffset);
|
||||
}
|
||||
}
|
||||
this._draggedByDraggableManager.updateObjectPosition(runtimeScene, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -145,25 +105,214 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
doStepPostEvents(runtimeScene) {
|
||||
DraggableRuntimeBehavior.leftPressedLastFrame = runtimeScene
|
||||
const mouseDraggableManager = DraggableManager.getMouseManager(
|
||||
runtimeScene
|
||||
);
|
||||
mouseDraggableManager.leftPressedLastFrame = runtimeScene
|
||||
.getGame()
|
||||
.getInputManager()
|
||||
.isMouseButtonPressed(0);
|
||||
}
|
||||
|
||||
isDragged(runtimeScene): boolean {
|
||||
return this._dragged;
|
||||
return !!this._draggedByDraggableManager;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the dragging
|
||||
*/
|
||||
abstract class DraggableManager {
|
||||
/**
|
||||
* The object has left its original position.
|
||||
* When true, the search for the best object to drag has ended.
|
||||
*/
|
||||
protected _draggingSomething = false;
|
||||
/**
|
||||
* The behavior of the object that is being dragged and that is the best one (i.e: highest Z order) found.
|
||||
*/
|
||||
protected _draggableBehavior: gdjs.DraggableRuntimeBehavior | null = null;
|
||||
protected _xOffset: number = 0;
|
||||
protected _yOffset: number = 0;
|
||||
|
||||
constructor(runtimeScene: gdjs.RuntimeScene) {}
|
||||
|
||||
/**
|
||||
* Get the platforms manager of a scene.
|
||||
*/
|
||||
static getMouseManager(
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): MouseDraggableManager {
|
||||
// @ts-ignore
|
||||
if (!runtimeScene.mouseDraggableManager) {
|
||||
//Create the shared manager if necessary.
|
||||
// @ts-ignore
|
||||
runtimeScene.mouseDraggableManager = new MouseDraggableManager(
|
||||
runtimeScene
|
||||
);
|
||||
}
|
||||
// @ts-ignore
|
||||
return runtimeScene.mouseDraggableManager;
|
||||
}
|
||||
|
||||
//Static property used to avoid start dragging an object while another is dragged.
|
||||
static mouseDraggingSomething = false;
|
||||
/**
|
||||
* Get the platforms manager of a scene.
|
||||
*/
|
||||
static getTouchManager(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
touchId: integer
|
||||
): DraggableManager {
|
||||
// @ts-ignore
|
||||
if (!runtimeScene.touchDraggableManagers) {
|
||||
//Create the shared manager if necessary.
|
||||
// @ts-ignore
|
||||
runtimeScene.touchDraggableManagers = [];
|
||||
}
|
||||
// @ts-ignore
|
||||
if (!runtimeScene.touchDraggableManagers[touchId]) {
|
||||
//Create the shared manager if necessary.
|
||||
// @ts-ignore
|
||||
runtimeScene.touchDraggableManagers[
|
||||
touchId
|
||||
] = new TouchDraggableManager(runtimeScene, touchId);
|
||||
}
|
||||
// @ts-ignore
|
||||
return runtimeScene.touchDraggableManagers[touchId];
|
||||
}
|
||||
|
||||
//Static property used to avoid start dragging an object while another is dragged by the same touch.
|
||||
static touchDraggingSomething: Array<boolean> = [];
|
||||
tryAndTakeDragging(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
draggableRuntimeBehavior: DraggableRuntimeBehavior
|
||||
) {
|
||||
if (
|
||||
this._draggableBehavior &&
|
||||
draggableRuntimeBehavior.owner.getZOrder() <=
|
||||
this._draggableBehavior.owner.getZOrder()
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
const position = this.getPosition(runtimeScene, draggableRuntimeBehavior);
|
||||
if (
|
||||
!draggableRuntimeBehavior.owner.insideObject(position[0], position[1])
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (this._draggableBehavior) {
|
||||
// The previous best object to drag will not be dragged.
|
||||
this._draggableBehavior._dismissDrag();
|
||||
}
|
||||
this._draggableBehavior = draggableRuntimeBehavior;
|
||||
this._xOffset = position[0] - draggableRuntimeBehavior.owner.getX();
|
||||
this._yOffset = position[1] - draggableRuntimeBehavior.owner.getY();
|
||||
return true;
|
||||
}
|
||||
|
||||
//Static property used to only start dragging when clicking.
|
||||
static leftPressedLastFrame = false;
|
||||
updateObjectPosition(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
draggableRuntimeBehavior: DraggableRuntimeBehavior
|
||||
) {
|
||||
const position = this.getPosition(runtimeScene, draggableRuntimeBehavior);
|
||||
if (
|
||||
draggableRuntimeBehavior.owner.getX() != position[0] - this._xOffset ||
|
||||
draggableRuntimeBehavior.owner.getY() != position[1] - this._yOffset
|
||||
) {
|
||||
draggableRuntimeBehavior.owner.setX(position[0] - this._xOffset);
|
||||
draggableRuntimeBehavior.owner.setY(position[1] - this._yOffset);
|
||||
this._draggingSomething = true;
|
||||
}
|
||||
}
|
||||
|
||||
endDrag() {
|
||||
this._draggingSomething = false;
|
||||
this._draggableBehavior = null;
|
||||
}
|
||||
|
||||
abstract isDragging(
|
||||
draggableRuntimeBehavior: DraggableRuntimeBehavior
|
||||
): boolean;
|
||||
abstract shouldEndDrag(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
draggableRuntimeBehavior: DraggableRuntimeBehavior
|
||||
): boolean;
|
||||
abstract getPosition(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
draggableRuntimeBehavior: DraggableRuntimeBehavior
|
||||
): FloatPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the dragging by mouse
|
||||
*/
|
||||
class MouseDraggableManager extends DraggableManager {
|
||||
/** Used to only start dragging when clicking. */
|
||||
leftPressedLastFrame = false;
|
||||
|
||||
constructor(runtimeScene: gdjs.RuntimeScene) {
|
||||
super(runtimeScene);
|
||||
}
|
||||
|
||||
isDragging(draggableRuntimeBehavior: DraggableRuntimeBehavior): boolean {
|
||||
return this.leftPressedLastFrame || this._draggingSomething;
|
||||
}
|
||||
|
||||
getPosition(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
draggableRuntimeBehavior: DraggableRuntimeBehavior
|
||||
): FloatPoint {
|
||||
const inputManager = runtimeScene.getGame().getInputManager();
|
||||
return runtimeScene
|
||||
.getLayer(draggableRuntimeBehavior.owner.getLayer())
|
||||
.convertCoords(inputManager.getMouseX(), inputManager.getMouseY());
|
||||
}
|
||||
|
||||
shouldEndDrag(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
draggableRuntimeBehavior: DraggableRuntimeBehavior
|
||||
): boolean {
|
||||
const inputManager = runtimeScene.getGame().getInputManager();
|
||||
return !inputManager.isMouseButtonPressed(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the dragging by touch
|
||||
*/
|
||||
class TouchDraggableManager extends DraggableManager {
|
||||
private _touchId: integer;
|
||||
|
||||
constructor(runtimeScene: gdjs.RuntimeScene, touchId: integer) {
|
||||
super(runtimeScene);
|
||||
this._touchId = touchId;
|
||||
}
|
||||
|
||||
isDragging(draggableRuntimeBehavior: DraggableRuntimeBehavior): boolean {
|
||||
return this._draggingSomething;
|
||||
}
|
||||
|
||||
getPosition(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
draggableRuntimeBehavior: DraggableRuntimeBehavior
|
||||
): FloatPoint {
|
||||
const inputManager = runtimeScene.getGame().getInputManager();
|
||||
return runtimeScene
|
||||
.getLayer(draggableRuntimeBehavior.owner.getLayer())
|
||||
.convertCoords(
|
||||
inputManager.getTouchX(this._touchId),
|
||||
inputManager.getTouchY(this._touchId)
|
||||
);
|
||||
}
|
||||
|
||||
shouldEndDrag(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
draggableRuntimeBehavior: DraggableRuntimeBehavior
|
||||
): boolean {
|
||||
const inputManager = runtimeScene.getGame().getInputManager();
|
||||
return (
|
||||
inputManager.getAllTouchIdentifiers().indexOf(this._touchId) === -1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
gdjs.registerBehavior(
|
||||
'DraggableBehavior::Draggable',
|
||||
gdjs.DraggableRuntimeBehavior
|
||||
|
@@ -51,112 +51,210 @@ describe('gdjs.DraggableRuntimeBehavior', function () {
|
||||
runtimeScene.addObject(object);
|
||||
runtimeScene.addObject(object2);
|
||||
|
||||
it('should handle mouse', function () {
|
||||
object.setPosition(450, 500);
|
||||
describe('(mouse)', function () {
|
||||
it('can drag an object', function () {
|
||||
object.setPosition(450, 500);
|
||||
|
||||
//Drag'n'drop
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onMouseMove(450, 500);
|
||||
runtimeGame
|
||||
.getInputManager()
|
||||
.onMouseButtonPressed(gdjs.InputManager.MOUSE_LEFT_BUTTON);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onMouseMove(750, 600);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame
|
||||
.getInputManager()
|
||||
.onMouseButtonReleased(gdjs.InputManager.MOUSE_LEFT_BUTTON);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
// Drag'n'drop
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onMouseMove(450, 500);
|
||||
runtimeGame
|
||||
.getInputManager()
|
||||
.onMouseButtonPressed(gdjs.InputManager.MOUSE_LEFT_BUTTON);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onMouseMove(750, 600);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame
|
||||
.getInputManager()
|
||||
.onMouseButtonReleased(gdjs.InputManager.MOUSE_LEFT_BUTTON);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
expect(object.getX()).to.be(750);
|
||||
expect(object.getY()).to.be(600);
|
||||
expect(object.getX()).to.be(750);
|
||||
expect(object.getY()).to.be(600);
|
||||
|
||||
//Mouse move with dragging
|
||||
runtimeGame.getInputManager().onMouseMove(600, 600);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
// Mouse move without dragging
|
||||
runtimeGame.getInputManager().onMouseMove(600, 600);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
expect(object.getX()).to.be(750);
|
||||
expect(object.getY()).to.be(600);
|
||||
expect(object.getX()).to.be(750);
|
||||
expect(object.getY()).to.be(600);
|
||||
|
||||
//Start dragging again
|
||||
runtimeGame.getInputManager().onMouseMove(750, 600);
|
||||
runtimeGame
|
||||
.getInputManager()
|
||||
.onMouseButtonPressed(gdjs.InputManager.MOUSE_LEFT_BUTTON);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onMouseMove(850, 700);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame
|
||||
.getInputManager()
|
||||
.onMouseButtonReleased(gdjs.InputManager.MOUSE_LEFT_BUTTON);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
// Start dragging again
|
||||
runtimeGame.getInputManager().onMouseMove(750, 600);
|
||||
runtimeGame
|
||||
.getInputManager()
|
||||
.onMouseButtonPressed(gdjs.InputManager.MOUSE_LEFT_BUTTON);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onMouseMove(850, 700);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame
|
||||
.getInputManager()
|
||||
.onMouseButtonReleased(gdjs.InputManager.MOUSE_LEFT_BUTTON);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
expect(object.getX()).to.be(850);
|
||||
expect(object.getY()).to.be(700);
|
||||
expect(object.getX()).to.be(850);
|
||||
expect(object.getY()).to.be(700);
|
||||
});
|
||||
|
||||
[false, true].forEach((firstInFront) => {
|
||||
it(`must drag the object in front (${
|
||||
firstInFront ? '1st object' : '2nd object'
|
||||
} in front)`, function () {
|
||||
object.setPosition(450, 500);
|
||||
object2.setPosition(450, 500);
|
||||
if (firstInFront) {
|
||||
object.setZOrder(2);
|
||||
object2.setZOrder(1);
|
||||
} else {
|
||||
object.setZOrder(1);
|
||||
object2.setZOrder(2);
|
||||
}
|
||||
|
||||
// Drag'n'drop
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onMouseMove(450, 500);
|
||||
runtimeGame
|
||||
.getInputManager()
|
||||
.onMouseButtonPressed(gdjs.InputManager.MOUSE_LEFT_BUTTON);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onMouseMove(750, 600);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame
|
||||
.getInputManager()
|
||||
.onMouseButtonReleased(gdjs.InputManager.MOUSE_LEFT_BUTTON);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
if (firstInFront) {
|
||||
// The 1st object moved
|
||||
expect(object.getX()).to.be(750);
|
||||
expect(object.getY()).to.be(600);
|
||||
expect(object2.getX()).to.be(450);
|
||||
expect(object2.getY()).to.be(500);
|
||||
} else {
|
||||
// The 2nd object moved
|
||||
expect(object.getX()).to.be(450);
|
||||
expect(object.getY()).to.be(500);
|
||||
expect(object2.getX()).to.be(750);
|
||||
expect(object2.getY()).to.be(600);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
it('should handle touches', function () {
|
||||
runtimeGame.getInputManager().touchSimulateMouse(false);
|
||||
object.setPosition(450, 500);
|
||||
describe('(touch)', function () {
|
||||
it('can drag an object', function () {
|
||||
runtimeGame.getInputManager().touchSimulateMouse(false);
|
||||
object.setPosition(450, 500);
|
||||
|
||||
//Drag'n'drop
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onTouchStart(1, 10, 20);
|
||||
runtimeGame.getInputManager().onTouchStart(0, 450, 500);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
runtimeGame.getInputManager().onTouchMove(0, 750, 600);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
runtimeGame.getInputManager().onTouchEnd(0);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
// Drag'n'drop
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onTouchStart(1, 10, 20);
|
||||
runtimeGame.getInputManager().onTouchStart(0, 450, 500);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
runtimeGame.getInputManager().onTouchMove(0, 750, 600);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
runtimeGame.getInputManager().onTouchEnd(0);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
|
||||
expect(object.getX()).to.be(750);
|
||||
expect(object.getY()).to.be(600);
|
||||
expect(object.getX()).to.be(750);
|
||||
expect(object.getY()).to.be(600);
|
||||
|
||||
//Move another unrelated touch
|
||||
runtimeGame.getInputManager().onTouchMove(1, 750, 600);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onTouchMove(1, 850, 700);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
// Move another unrelated touch
|
||||
runtimeGame.getInputManager().onTouchMove(1, 750, 600);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onTouchMove(1, 850, 700);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
expect(object.getX()).to.be(750);
|
||||
expect(object.getY()).to.be(600);
|
||||
expect(object.getX()).to.be(750);
|
||||
expect(object.getY()).to.be(600);
|
||||
|
||||
//Start drag'n'drop with another touch
|
||||
runtimeGame.getInputManager().onTouchEnd(1);
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onTouchStart(1, 750, 600);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onTouchMove(1, 850, 700);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onTouchEnd(1);
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
// Start drag'n'drop with another touch
|
||||
runtimeGame.getInputManager().onTouchEnd(1);
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onTouchStart(1, 750, 600);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onTouchMove(1, 850, 700);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onTouchEnd(1);
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
|
||||
expect(object.getX()).to.be(850);
|
||||
expect(object.getY()).to.be(700);
|
||||
});
|
||||
it('should handle multitouch', function () {
|
||||
runtimeGame.getInputManager().touchSimulateMouse(false);
|
||||
object.setPosition(450, 500);
|
||||
object2.setPosition(650, 600);
|
||||
expect(object.getX()).to.be(850);
|
||||
expect(object.getY()).to.be(700);
|
||||
});
|
||||
it('can drag 2 objects with multitouch', function () {
|
||||
runtimeGame.getInputManager().touchSimulateMouse(false);
|
||||
object.setPosition(450, 500);
|
||||
object2.setPosition(650, 600);
|
||||
|
||||
//Drag'n'drop
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onTouchStart(2, 450, 500);
|
||||
runtimeGame.getInputManager().onTouchStart(1, 650, 600);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
runtimeGame.getInputManager().onTouchMove(2, 750, 700);
|
||||
runtimeGame.getInputManager().onTouchMove(1, 100, 200);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
runtimeGame.getInputManager().onTouchEnd(2);
|
||||
// Drag'n'drop
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onTouchStart(2, 450, 500);
|
||||
runtimeGame.getInputManager().onTouchStart(1, 650, 600);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
runtimeGame.getInputManager().onTouchMove(2, 750, 700);
|
||||
runtimeGame.getInputManager().onTouchMove(1, 100, 200);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
runtimeGame.getInputManager().onTouchEnd(1);
|
||||
runtimeGame.getInputManager().onTouchEnd(2);
|
||||
|
||||
expect(object.getX()).to.be(750);
|
||||
expect(object.getY()).to.be(700);
|
||||
expect(object2.getX()).to.be(100);
|
||||
expect(object2.getY()).to.be(200);
|
||||
expect(object.getX()).to.be(750);
|
||||
expect(object.getY()).to.be(700);
|
||||
expect(object2.getX()).to.be(100);
|
||||
expect(object2.getY()).to.be(200);
|
||||
|
||||
// Avoid side effects on the following test cases
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
});
|
||||
|
||||
[false, true].forEach((firstInFront) => {
|
||||
it(`must drag the object in front (${
|
||||
firstInFront ? '1st object' : '2nd object'
|
||||
} in front)`, function () {
|
||||
object.setPosition(450, 500);
|
||||
object2.setPosition(450, 500);
|
||||
if (firstInFront) {
|
||||
object.setZOrder(2);
|
||||
object2.setZOrder(1);
|
||||
} else {
|
||||
object.setZOrder(1);
|
||||
object2.setZOrder(2);
|
||||
}
|
||||
|
||||
// Drag'n'drop
|
||||
runtimeGame.getInputManager().touchSimulateMouse(false);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onTouchStart(1, 10, 20);
|
||||
runtimeGame.getInputManager().onTouchStart(0, 450, 500);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
runtimeGame.getInputManager().onTouchMove(0, 750, 600);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
runtimeGame.getInputManager().onTouchEnd(0);
|
||||
runtimeGame.getInputManager().onTouchEnd(1);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
runtimeGame.getInputManager().onFrameEnded();
|
||||
|
||||
if (firstInFront) {
|
||||
// The 1st object moved
|
||||
expect(object.getX()).to.be(750);
|
||||
expect(object.getY()).to.be(600);
|
||||
expect(object2.getX()).to.be(450);
|
||||
expect(object2.getY()).to.be(500);
|
||||
} else {
|
||||
// The 2nd object moved
|
||||
expect(object.getX()).to.be(450);
|
||||
expect(object.getY()).to.be(500);
|
||||
expect(object2.getX()).to.be(750);
|
||||
expect(object2.getY()).to.be(600);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -1,5 +1,6 @@
|
||||
//A simple PIXI filter doing some color changes
|
||||
namespace gdjs {
|
||||
const logger = new gdjs.Logger('Dummy effect');
|
||||
import PIXI = GlobalPIXIModule.PIXI;
|
||||
|
||||
const DummyPixiFilter = function () {
|
||||
@@ -46,7 +47,7 @@ namespace gdjs {
|
||||
// `effectData.stringParameters.someImage`
|
||||
// `effectData.stringParameters.someColor`
|
||||
// `effectData.booleanParameters.someBoolean`
|
||||
console.info(
|
||||
logger.info(
|
||||
'The PIXI texture found for the Dummy Effect (not actually used):',
|
||||
(layer
|
||||
.getRuntimeScene()
|
||||
|
@@ -1,4 +1,6 @@
|
||||
namespace gdjs {
|
||||
const logger = new gdjs.Logger('Dummy behavior');
|
||||
|
||||
/**
|
||||
* The DummyRuntimeBehavior changes a variable in the object that is owning
|
||||
* it, at every tick before events are run, to set it to the string that was
|
||||
@@ -20,7 +22,7 @@ namespace gdjs {
|
||||
this._textToSet = behaviorData.property1;
|
||||
|
||||
// You can also run arbitrary code at the creation of the behavior:
|
||||
console.log('DummyRuntimeBehavior was created for object:', owner);
|
||||
logger.log('DummyRuntimeBehavior was created for object:', owner);
|
||||
}
|
||||
|
||||
updateFromBehaviorData(oldBehaviorData, newBehaviorData): boolean {
|
||||
|
@@ -1,4 +1,6 @@
|
||||
namespace gdjs {
|
||||
const logger = new gdjs.Logger('Dummy object');
|
||||
|
||||
/**
|
||||
* A dummy object doing showing a text on screen.
|
||||
* @ignore
|
||||
@@ -126,9 +128,9 @@ namespace gdjs {
|
||||
* A dummy method that can be called from events
|
||||
*/
|
||||
myMethod(number1: float, text1: string) {
|
||||
console.log('Congrats, this method was called on a DummyRuntimeObject');
|
||||
console.log('Here is the object:', this);
|
||||
console.log('Here are the arguments passed from events:', number1, text1);
|
||||
logger.log('Congrats, this method was called on a DummyRuntimeObject');
|
||||
logger.log('Here is the object:', this);
|
||||
logger.log('Here are the arguments passed from events:', number1, text1);
|
||||
}
|
||||
}
|
||||
gdjs.registerObject(
|
||||
|
@@ -1,4 +1,5 @@
|
||||
namespace gdjs {
|
||||
const logger = new gdjs.Logger('Dummy behavior (with shared data)');
|
||||
export class DummyWithSharedDataRuntimeBehavior extends gdjs.RuntimeBehavior {
|
||||
_textToSet: string;
|
||||
|
||||
@@ -20,11 +21,11 @@ namespace gdjs {
|
||||
this._textToSet = (sharedData as any).sharedProperty1;
|
||||
|
||||
// You can also run arbitrary code at the creation of the behavior:
|
||||
console.log(
|
||||
logger.log(
|
||||
'DummyWithSharedDataRuntimeBehavior was created for object:',
|
||||
owner
|
||||
);
|
||||
console.log('The shared data are:', sharedData);
|
||||
logger.log('The shared data are:', sharedData);
|
||||
}
|
||||
|
||||
updateFromBehaviorData(oldBehaviorData, newBehaviorData): boolean {
|
||||
|
@@ -1,4 +1,6 @@
|
||||
namespace gdjs {
|
||||
const logger = new gdjs.Logger('Example extension');
|
||||
|
||||
export namespace evtTools {
|
||||
/**
|
||||
* This is an example of some functions that can be used through events.
|
||||
@@ -24,7 +26,7 @@ namespace gdjs {
|
||||
* that will be called at this moment.
|
||||
*/
|
||||
gdjs.registerRuntimeSceneLoadedCallback(function (runtimeScene) {
|
||||
console.log('A gdjs.RuntimeScene was loaded:', runtimeScene);
|
||||
logger.log('A gdjs.RuntimeScene was loaded:', runtimeScene);
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -32,7 +34,7 @@ namespace gdjs {
|
||||
* that will be called at this moment.
|
||||
*/
|
||||
gdjs.registerRuntimeSceneUnloadedCallback(function (runtimeScene) {
|
||||
console.log('A gdjs.RuntimeScene was unloaded:', runtimeScene);
|
||||
logger.log('A gdjs.RuntimeScene was unloaded:', runtimeScene);
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -42,7 +44,7 @@ namespace gdjs {
|
||||
runtimeScene,
|
||||
runtimeObject
|
||||
) {
|
||||
console.log(
|
||||
logger.log(
|
||||
'A gdjs.RuntimeObject was deleted from a gdjs.RuntimeScene:',
|
||||
runtimeScene,
|
||||
runtimeObject
|
||||
@@ -50,7 +52,7 @@ namespace gdjs {
|
||||
});
|
||||
|
||||
// Finally, note that you can also simply run code here. Most of the time you shouldn't need it though.
|
||||
console.log(
|
||||
logger.log(
|
||||
'gdjs.exampleJsExtension was created, with myGlobalString containing:' +
|
||||
myGlobalString
|
||||
);
|
||||
|
@@ -1,4 +1,5 @@
|
||||
namespace gdjs {
|
||||
const logger = new gdjs.Logger('Facebook instant games');
|
||||
export namespace evtTools {
|
||||
export namespace facebookInstantGames {
|
||||
export let _preloadedInterstitial: any = null;
|
||||
@@ -153,12 +154,12 @@ namespace gdjs {
|
||||
.then(function () {
|
||||
gdjs.evtTools.facebookInstantGames._preloadedInterstitialLoading = false;
|
||||
gdjs.evtTools.facebookInstantGames._preloadedInterstitialLoaded = true;
|
||||
console.info('Facebook Instant Games interstitial preloaded.');
|
||||
logger.info('Facebook Instant Games interstitial preloaded.');
|
||||
})
|
||||
.catch(function (err) {
|
||||
gdjs.evtTools.facebookInstantGames._preloadedInterstitialLoading = false;
|
||||
gdjs.evtTools.facebookInstantGames._preloadedInterstitialLoaded = false;
|
||||
console.error('Interstitial failed to preload: ' + err.message);
|
||||
logger.error('Interstitial failed to preload: ' + err.message);
|
||||
errorVariable.setString(err.message || 'Unknown error');
|
||||
});
|
||||
};
|
||||
@@ -173,10 +174,10 @@ namespace gdjs {
|
||||
gdjs.evtTools.facebookInstantGames._preloadedInterstitial
|
||||
.showAsync()
|
||||
.then(function () {
|
||||
console.info('Facebook Instant Games interstitial shown.');
|
||||
logger.info('Facebook Instant Games interstitial shown.');
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error('Interstitial failed to show: ' + err.message);
|
||||
logger.error('Interstitial failed to show: ' + err.message);
|
||||
errorVariable.setString(err.message || 'Unknown error');
|
||||
})
|
||||
.then(function () {
|
||||
@@ -207,12 +208,12 @@ namespace gdjs {
|
||||
.then(function () {
|
||||
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoading = false;
|
||||
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoaded = true;
|
||||
console.info('Facebook Instant Games rewarded video preloaded.');
|
||||
logger.info('Facebook Instant Games rewarded video preloaded.');
|
||||
})
|
||||
.catch(function (err) {
|
||||
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoading = false;
|
||||
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoaded = false;
|
||||
console.error('Rewarded video failed to preload: ' + err.message);
|
||||
logger.error('Rewarded video failed to preload: ' + err.message);
|
||||
errorVariable.setString(err.message || 'Unknown error');
|
||||
});
|
||||
};
|
||||
@@ -227,10 +228,10 @@ namespace gdjs {
|
||||
gdjs.evtTools.facebookInstantGames._preloadedRewardedVideo
|
||||
.showAsync()
|
||||
.then(function () {
|
||||
console.info('Facebook Instant Games rewarded video shown.');
|
||||
logger.info('Facebook Instant Games rewarded video shown.');
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error('Rewarded video failed to show: ' + err.message);
|
||||
logger.error('Rewarded video failed to show: ' + err.message);
|
||||
errorVariable.setString(err.message || 'Unknown error');
|
||||
})
|
||||
.then(function () {
|
||||
@@ -242,7 +243,7 @@ namespace gdjs {
|
||||
return gdjs.evtTools.facebookInstantGames._preloadedRewardedVideoLoaded;
|
||||
};
|
||||
if (typeof FBInstant === 'undefined' && typeof window !== 'undefined') {
|
||||
console.log('Creating a mocked version of Facebook Instant Games.');
|
||||
logger.log('Creating a mocked version of Facebook Instant Games.');
|
||||
|
||||
/**
|
||||
* A mocked Leaderboard, part of the mock of FBInstant.
|
||||
@@ -295,7 +296,7 @@ namespace gdjs {
|
||||
|
||||
showAsync(): Promise<void> {
|
||||
if (this._isLoaded) {
|
||||
console.info(
|
||||
logger.info(
|
||||
'In a real Instant Game, a video reward should have been shown to the user.'
|
||||
);
|
||||
return Promise.resolve();
|
||||
@@ -318,7 +319,7 @@ namespace gdjs {
|
||||
|
||||
showAsync(): Promise<void> {
|
||||
if (this._isLoaded) {
|
||||
console.info(
|
||||
logger.info(
|
||||
'In a real Instant Game, an interstitial should have been shown to the user.'
|
||||
);
|
||||
return Promise.resolve();
|
||||
|
@@ -1,4 +1,5 @@
|
||||
namespace gdjs {
|
||||
const logger = new gdjs.Logger('Filesystem');
|
||||
export namespace fileSystem {
|
||||
// The Node.js path module, or null if it can't be loaded.
|
||||
export let _path: any = null;
|
||||
@@ -203,7 +204,7 @@ namespace gdjs {
|
||||
fileSystem.mkdirSync(directory);
|
||||
result = 'ok';
|
||||
} catch (err) {
|
||||
console.error(
|
||||
logger.error(
|
||||
"Unable to create directory at: '" + directory + "': ",
|
||||
err
|
||||
);
|
||||
@@ -228,7 +229,7 @@ namespace gdjs {
|
||||
fileSystem.writeFile(savePath, text, 'utf8', (err) => {
|
||||
resultVar.setString('ok');
|
||||
if (err) {
|
||||
console.error(
|
||||
logger.error(
|
||||
"Unable to save the text to path: '" + savePath + "': ",
|
||||
err
|
||||
);
|
||||
@@ -256,7 +257,7 @@ namespace gdjs {
|
||||
fileSystem.writeFileSync(savePath, text, 'utf8');
|
||||
result = 'ok';
|
||||
} catch (err) {
|
||||
console.error(
|
||||
logger.error(
|
||||
"Unable to save the text to path: '" + savePath + "': ",
|
||||
err
|
||||
);
|
||||
@@ -287,7 +288,7 @@ namespace gdjs {
|
||||
);
|
||||
result = 'ok';
|
||||
} catch (err) {
|
||||
console.error(
|
||||
logger.error(
|
||||
"Unable to save the variable to path: '" + savePath + "': ",
|
||||
err
|
||||
);
|
||||
@@ -316,7 +317,7 @@ namespace gdjs {
|
||||
(err) => {
|
||||
resultVar.setString('ok');
|
||||
if (err) {
|
||||
console.error(
|
||||
logger.error(
|
||||
"Unable to save the variable to path: '" + savePath + "': ",
|
||||
err
|
||||
);
|
||||
@@ -348,7 +349,7 @@ namespace gdjs {
|
||||
result = 'ok';
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(
|
||||
logger.error(
|
||||
"Unable to load the file at path: '" + loadPath + "': ",
|
||||
err
|
||||
);
|
||||
@@ -378,7 +379,7 @@ namespace gdjs {
|
||||
result = 'ok';
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(
|
||||
logger.error(
|
||||
"Unable to load variable from the file at path: '" +
|
||||
loadPath +
|
||||
"': ",
|
||||
@@ -408,7 +409,7 @@ namespace gdjs {
|
||||
resultVar.setString('ok');
|
||||
}
|
||||
if (err) {
|
||||
console.error(
|
||||
logger.error(
|
||||
"Unable to load variable from the file at path: '" +
|
||||
loadPath +
|
||||
"': ",
|
||||
@@ -439,7 +440,7 @@ namespace gdjs {
|
||||
resultVar.setString('ok');
|
||||
}
|
||||
if (err) {
|
||||
console.error(
|
||||
logger.error(
|
||||
"Unable to load the file at path: '" + loadPath + "': ",
|
||||
err
|
||||
);
|
||||
@@ -465,7 +466,7 @@ namespace gdjs {
|
||||
fileSystem.unlinkSync(filePath);
|
||||
result = 'ok';
|
||||
} catch (err) {
|
||||
console.error("Unable to delete the file: '" + filePath + "': ", err);
|
||||
logger.error("Unable to delete the file: '" + filePath + "': ", err);
|
||||
result = 'error';
|
||||
}
|
||||
}
|
||||
@@ -486,7 +487,7 @@ namespace gdjs {
|
||||
fileSystem.unlink(filePath, (err) => {
|
||||
resultVar.setString('ok');
|
||||
if (err) {
|
||||
console.error(
|
||||
logger.error(
|
||||
"Unable to delete the file: '" + filePath + "': ",
|
||||
err
|
||||
);
|
||||
|
@@ -1,4 +1,5 @@
|
||||
namespace gdjs {
|
||||
const logger = new gdjs.Logger('Firebase (setup)');
|
||||
export namespace evtTools {
|
||||
/**
|
||||
* Firebase Event Tools
|
||||
@@ -23,7 +24,7 @@ namespace gdjs {
|
||||
.getExtensionProperty('Firebase', 'FirebaseConfig')
|
||||
);
|
||||
} catch (e) {
|
||||
console.error('The Firebase configuration is invalid! Error: ' + e);
|
||||
logger.error('The Firebase configuration is invalid! Error: ' + e);
|
||||
return;
|
||||
}
|
||||
if (typeof firebaseConfig !== 'object') return;
|
||||
|
@@ -5,12 +5,7 @@ namespace gdjs {
|
||||
_obstacleRBush: any;
|
||||
|
||||
constructor(runtimeScene: gdjs.RuntimeScene) {
|
||||
this._obstacleRBush = new rbush(9, [
|
||||
'.owner.getAABB().min[0]',
|
||||
'.owner.getAABB().min[1]',
|
||||
'.owner.getAABB().max[0]',
|
||||
'.owner.getAABB().max[1]',
|
||||
]);
|
||||
this._obstacleRBush = new rbush();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35,7 +30,10 @@ namespace gdjs {
|
||||
* Add a light obstacle to the list of existing obstacles.
|
||||
*/
|
||||
addObstacle(obstacle: gdjs.LightObstacleRuntimeBehavior) {
|
||||
this._obstacleRBush.insert(obstacle);
|
||||
if (obstacle.currentRBushAABB)
|
||||
obstacle.currentRBushAABB.updateAABBFromOwner();
|
||||
else obstacle.currentRBushAABB = new gdjs.BehaviorRBushAABB(obstacle);
|
||||
this._obstacleRBush.insert(obstacle.currentRBushAABB);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,7 +41,7 @@ namespace gdjs {
|
||||
* added before.
|
||||
*/
|
||||
removeObstacle(obstacle: gdjs.LightObstacleRuntimeBehavior) {
|
||||
this._obstacleRBush.remove(obstacle);
|
||||
this._obstacleRBush.remove(obstacle.currentRBushAABB);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,7 +53,7 @@ namespace gdjs {
|
||||
getAllObstaclesAround(
|
||||
object: gdjs.RuntimeObject,
|
||||
radius: number,
|
||||
result: gdjs.LightObstacleRuntimeBehavior[]
|
||||
result: gdjs.BehaviorRBushAABB<gdjs.LightObstacleRuntimeBehavior>[]
|
||||
) {
|
||||
// TODO: This would better be done using the object AABB (getAABB), as (`getCenterX`;`getCenterY`) point
|
||||
// is not necessarily in the middle of the object (for sprites for example).
|
||||
@@ -83,6 +81,9 @@ namespace gdjs {
|
||||
_oldY: float = 0;
|
||||
_oldWidth: float = 0;
|
||||
_oldHeight: float = 0;
|
||||
currentRBushAABB: gdjs.BehaviorRBushAABB<
|
||||
LightObstacleRuntimeBehavior
|
||||
> | null = null;
|
||||
_manager: any;
|
||||
_registeredInManager: boolean = false;
|
||||
|
||||
|
@@ -1,4 +1,5 @@
|
||||
namespace gdjs {
|
||||
const logger = new gdjs.Logger('Light object');
|
||||
import PIXI = GlobalPIXIModule.PIXI;
|
||||
|
||||
/**
|
||||
@@ -134,7 +135,7 @@ namespace gdjs {
|
||||
|
||||
updateMesh(): void {
|
||||
if (!PIXI.utils.isWebGLSupported()) {
|
||||
console.warn(
|
||||
logger.warn(
|
||||
'This device does not support webgl, which is required for Lighting Extension.'
|
||||
);
|
||||
return;
|
||||
@@ -368,7 +369,9 @@ namespace gdjs {
|
||||
* @returns the vertices of mesh.
|
||||
*/
|
||||
_computeLightVertices(): Array<any> {
|
||||
const lightObstacles: Array<gdjs.LightObstacleRuntimeBehavior> = [];
|
||||
const lightObstacles: gdjs.BehaviorRBushAABB<
|
||||
LightObstacleRuntimeBehavior
|
||||
>[] = [];
|
||||
if (this._manager) {
|
||||
this._manager.getAllObstaclesAround(
|
||||
this._object,
|
||||
@@ -393,7 +396,7 @@ namespace gdjs {
|
||||
const obstaclesCount = lightObstacles.length;
|
||||
const obstacleHitBoxes = new Array(obstaclesCount);
|
||||
for (let i = 0; i < obstaclesCount; i++) {
|
||||
obstacleHitBoxes[i] = lightObstacles[i].owner.getHitBoxes();
|
||||
obstacleHitBoxes[i] = lightObstacles[i].behavior.owner.getHitBoxes();
|
||||
}
|
||||
const obstaclePolygons: Array<any> = [];
|
||||
obstaclePolygons.push(this._lightBoundingPoly);
|
||||
|
@@ -89,6 +89,7 @@ void DeclareLinkedObjectsExtension(gd::PlatformExtension& extension) {
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("objectList", _("Pick these objects..."))
|
||||
.AddParameter("objectPtr", _("...if they are linked to this object"))
|
||||
.AddCodeOnlyParameter("eventsFunctionContext", "")
|
||||
|
||||
.SetFunctionName("GDpriv::LinkedObjects::PickObjectsLinkedTo")
|
||||
.SetIncludeFile("LinkedObjects/LinkedObjectsTools.h");
|
||||
@@ -106,6 +107,7 @@ void DeclareLinkedObjectsExtension(gd::PlatformExtension& extension) {
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("objectList", _("Pick these objects..."))
|
||||
.AddParameter("objectPtr", _("...if they are linked to this object"))
|
||||
.AddCodeOnlyParameter("eventsFunctionContext", "")
|
||||
|
||||
.SetFunctionName("GDpriv::LinkedObjects::PickObjectsLinkedTo")
|
||||
.SetIncludeFile("LinkedObjects/LinkedObjectsTools.h");
|
||||
|
@@ -7,7 +7,7 @@ namespace gdjs {
|
||||
* Manages the links between objects.
|
||||
*/
|
||||
export class LinksManager {
|
||||
private links: { [objectId: number]: Hashtable<gdjs.RuntimeObject[]> } = {};
|
||||
private _links = new Map<integer, IterableLinkedObjects>();
|
||||
|
||||
/**
|
||||
* Get the links manager of a scene.
|
||||
@@ -23,76 +23,124 @@ namespace gdjs {
|
||||
return runtimeScene.linkedObjectsManager;
|
||||
}
|
||||
|
||||
_getObjectsLinkedWith(objA: gdjs.RuntimeObject) {
|
||||
if (!this.links.hasOwnProperty(objA.id)) {
|
||||
this.links[objA.id] = new Hashtable<gdjs.RuntimeObject[]>();
|
||||
/**
|
||||
* This function is for internal use and could disappear in next versions.
|
||||
* Prefer using:
|
||||
* * {@link LinksManager.getObjectsLinkedWithAndNamed}
|
||||
* * {@link LinksManager.getObjectsLinkedWith}
|
||||
* * {@link evtTools.linkedObjects.quickPickObjectsLinkedTo}
|
||||
*
|
||||
* @param objA
|
||||
* @returns the linked objects by name
|
||||
*/
|
||||
_getMapOfObjectsLinkedWith(
|
||||
objA: gdjs.RuntimeObject
|
||||
): Map<string, gdjs.RuntimeObject[]> {
|
||||
if (!this._links.has(objA.id)) {
|
||||
this._links.set(objA.id, new IterableLinkedObjects());
|
||||
}
|
||||
return this.links[objA.id];
|
||||
return this._links.get(objA.id)!.linkedObjectMap;
|
||||
}
|
||||
|
||||
// These 2 following functions give JS extensions an implementation dependent access to links.
|
||||
|
||||
/**
|
||||
* @returns an iterable on every object linked with objA.
|
||||
*/
|
||||
getObjectsLinkedWith(
|
||||
objA: gdjs.RuntimeObject
|
||||
): Iterable<gdjs.RuntimeObject> {
|
||||
if (!this._links.has(objA.id)) {
|
||||
this._links.set(objA.id, new IterableLinkedObjects());
|
||||
}
|
||||
return this._links.get(objA.id)!;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns an iterable of the objects with the given name that are linked with objA.
|
||||
*/
|
||||
getObjectsLinkedWithAndNamed(
|
||||
objA: gdjs.RuntimeObject,
|
||||
objectName: string
|
||||
): Iterable<gdjs.RuntimeObject> {
|
||||
let objects = this._getMapOfObjectsLinkedWith(objA).get(objectName);
|
||||
if (!objects) {
|
||||
// Give an empty Array
|
||||
objects = gdjs.staticArray(
|
||||
LinksManager.prototype.getObjectsLinkedWithAndNamed
|
||||
);
|
||||
}
|
||||
return objects;
|
||||
}
|
||||
|
||||
linkObjects(objA: gdjs.RuntimeObject, objB: gdjs.RuntimeObject) {
|
||||
const objALinkedObjectMap = this._getObjectsLinkedWith(objA);
|
||||
if (!objALinkedObjectMap.containsKey(objB.getName())) {
|
||||
objALinkedObjectMap.put(objB.getName(), []);
|
||||
const objALinkedObjectMap = this._getMapOfObjectsLinkedWith(objA);
|
||||
if (!objALinkedObjectMap.has(objB.getName())) {
|
||||
objALinkedObjectMap.set(objB.getName(), []);
|
||||
}
|
||||
const objALinkedObjects = objALinkedObjectMap.get(objB.getName());
|
||||
const objALinkedObjects = objALinkedObjectMap.get(objB.getName())!;
|
||||
if (objALinkedObjects.indexOf(objB) === -1) {
|
||||
objALinkedObjects.push(objB);
|
||||
}
|
||||
const objBLinkedObjectMap = this._getObjectsLinkedWith(objB);
|
||||
if (!objBLinkedObjectMap.containsKey(objA.getName())) {
|
||||
objBLinkedObjectMap.put(objA.getName(), []);
|
||||
const objBLinkedObjectMap = this._getMapOfObjectsLinkedWith(objB);
|
||||
if (!objBLinkedObjectMap.has(objA.getName())) {
|
||||
objBLinkedObjectMap.set(objA.getName(), []);
|
||||
}
|
||||
const objBLinkedObjects = objBLinkedObjectMap.get(objA.getName());
|
||||
const objBLinkedObjects = objBLinkedObjectMap.get(objA.getName())!;
|
||||
if (objBLinkedObjects.indexOf(objA) === -1) {
|
||||
objBLinkedObjects.push(objA);
|
||||
}
|
||||
}
|
||||
|
||||
removeAllLinksOf(obj: gdjs.RuntimeObject) {
|
||||
removeAllLinksOf(removedObject: gdjs.RuntimeObject) {
|
||||
// Remove the other side of the links
|
||||
const linkedObjectMap = this._getObjectsLinkedWith(obj);
|
||||
for (const linkedObjectName in linkedObjectMap.items) {
|
||||
if (linkedObjectMap.containsKey(linkedObjectName)) {
|
||||
const linkedObjects = linkedObjectMap.get(linkedObjectName);
|
||||
// Note: don't use `this._getMapOfObjectsLinkedWith` as this would
|
||||
// create an empty map of linked objects if not existing already.
|
||||
const links = this._links.get(removedObject.id);
|
||||
if (!links) {
|
||||
// No existing links to other objects.
|
||||
// This also means no links to the object from other objects.
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < linkedObjects.length; i++) {
|
||||
// This is the object on the other side of the link
|
||||
// We find obj in its list of linked objects and remove it.
|
||||
const linkedObject = linkedObjects[i];
|
||||
if (this.links.hasOwnProperty(linkedObject.id)) {
|
||||
const otherObjList = this.links[linkedObject.id].get(
|
||||
obj.getName()
|
||||
);
|
||||
const index = otherObjList.indexOf(obj);
|
||||
if (index !== -1) {
|
||||
otherObjList.splice(index, 1);
|
||||
}
|
||||
for (const linkedObjects of links.linkedObjectMap.values()) {
|
||||
for (let i = 0; i < linkedObjects.length; i++) {
|
||||
// This is the object on the other side of the link.
|
||||
// We find the removed object in its list of linked objects and remove it.
|
||||
const linkedObject = linkedObjects[i];
|
||||
|
||||
if (this._links.has(linkedObject.id)) {
|
||||
const otherObjList = this._links
|
||||
.get(linkedObject.id)!
|
||||
.linkedObjectMap.get(removedObject.getName())!;
|
||||
|
||||
const index = otherObjList.indexOf(removedObject);
|
||||
if (index !== -1) {
|
||||
otherObjList.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove the links on obj side
|
||||
if (this.links.hasOwnProperty(obj.id)) {
|
||||
delete this.links[obj.id];
|
||||
}
|
||||
|
||||
// Remove the links on the removedObject side.
|
||||
this._links.delete(removedObject.id);
|
||||
}
|
||||
|
||||
removeLinkBetween(objA: gdjs.RuntimeObject, objB: gdjs.RuntimeObject) {
|
||||
if (this.links.hasOwnProperty(objA.id)) {
|
||||
const map = this.links[objA.id];
|
||||
if (map.containsKey(objB.getName())) {
|
||||
const list = map.get(objB.getName());
|
||||
if (this._links.has(objA.id)) {
|
||||
const map = this._links.get(objA.id)!.linkedObjectMap;
|
||||
if (map.has(objB.getName())) {
|
||||
const list = map.get(objB.getName())!;
|
||||
const index = list.indexOf(objB);
|
||||
if (index !== -1) {
|
||||
list.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.links.hasOwnProperty(objB.id)) {
|
||||
const map = this.links[objB.id];
|
||||
if (map.containsKey(objA.getName())) {
|
||||
const list = map.get(objA.getName());
|
||||
if (this._links.has(objB.id)) {
|
||||
const map = this._links.get(objB.id)!.linkedObjectMap;
|
||||
if (map.has(objA.getName())) {
|
||||
const list = map.get(objA.getName())!;
|
||||
const index = list.indexOf(objA);
|
||||
if (index !== -1) {
|
||||
list.splice(index, 1);
|
||||
@@ -102,11 +150,44 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
|
||||
class IterableLinkedObjects implements Iterable<gdjs.RuntimeObject> {
|
||||
linkedObjectMap: Map<string, gdjs.RuntimeObject[]>;
|
||||
static emptyItr: Iterator<gdjs.RuntimeObject> = {
|
||||
next: () => ({ value: undefined, done: true }),
|
||||
};
|
||||
|
||||
constructor() {
|
||||
this.linkedObjectMap = new Map<string, gdjs.RuntimeObject[]>();
|
||||
}
|
||||
|
||||
[Symbol.iterator]() {
|
||||
let mapItr = this.linkedObjectMap.values();
|
||||
let listItr: Iterator<gdjs.RuntimeObject> =
|
||||
IterableLinkedObjects.emptyItr;
|
||||
|
||||
return {
|
||||
next: () => {
|
||||
let listNext = listItr.next();
|
||||
while (listNext.done) {
|
||||
const mapNext = mapItr.next();
|
||||
if (mapNext.done) {
|
||||
return listNext;
|
||||
}
|
||||
listItr = mapNext.value[Symbol.iterator]();
|
||||
listNext = listItr.next();
|
||||
}
|
||||
return listNext;
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export namespace evtTools {
|
||||
export namespace linkedObjects {
|
||||
gdjs.registerObjectDeletedFromSceneCallback(function (runtimeScene, obj) {
|
||||
LinksManager.getManager(runtimeScene).removeAllLinksOf(obj);
|
||||
});
|
||||
|
||||
export const linkObjects = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
objA: gdjs.RuntimeObject,
|
||||
@@ -142,50 +223,105 @@ namespace gdjs {
|
||||
export const pickObjectsLinkedTo = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
objectsLists: Hashtable<gdjs.RuntimeObject[]>,
|
||||
obj: gdjs.RuntimeObject
|
||||
obj: gdjs.RuntimeObject,
|
||||
eventsFunctionContext: EventsFunctionContext | undefined
|
||||
) {
|
||||
if (obj === null) {
|
||||
return false;
|
||||
}
|
||||
const linkedObjectMap = LinksManager.getManager(
|
||||
runtimeScene
|
||||
)._getObjectsLinkedWith(obj);
|
||||
)._getMapOfObjectsLinkedWith(obj);
|
||||
|
||||
let pickedSomething = false;
|
||||
for (const objectName in objectsLists.items) {
|
||||
if (objectsLists.containsKey(objectName)) {
|
||||
const pickedObjects = objectsLists.items[objectName];
|
||||
for (const contextObjectName in objectsLists.items) {
|
||||
if (objectsLists.containsKey(contextObjectName)) {
|
||||
const parentEventPickedObjects =
|
||||
objectsLists.items[contextObjectName];
|
||||
|
||||
if (linkedObjectMap.containsKey(objectName)) {
|
||||
const linkedObjects = linkedObjectMap.get(objectName);
|
||||
if (
|
||||
pickedObjects.length ===
|
||||
runtimeScene.getObjects(objectName).length
|
||||
) {
|
||||
// All the objects were picked, there is no need to make an intersection.
|
||||
pickedSomething = pickedSomething || linkedObjects.length > 0;
|
||||
pickedObjects.length = 0;
|
||||
pickedObjects.push.apply(pickedObjects, linkedObjects);
|
||||
} else {
|
||||
const temporaryObjects = gdjs.staticArray(
|
||||
gdjs.evtTools.linkedObjects.pickObjectsLinkedTo
|
||||
);
|
||||
temporaryObjects.length = 0;
|
||||
for (const otherObject of linkedObjects) {
|
||||
if (pickedObjects.indexOf(otherObject) >= 0) {
|
||||
temporaryObjects.push(otherObject);
|
||||
}
|
||||
if (parentEventPickedObjects.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find the object names in the scene
|
||||
const parentEventPickedObjectNames = gdjs.staticArray2(
|
||||
gdjs.evtTools.linkedObjects.pickObjectsLinkedTo
|
||||
);
|
||||
parentEventPickedObjectNames.length = 0;
|
||||
if (eventsFunctionContext) {
|
||||
// For functions, objects lists may contain objects with different names
|
||||
// indexed not by their name, but by the parameter name representing them.
|
||||
// This means that each object can have a different name,
|
||||
// so we iterate on them to get all the names.
|
||||
for (const pickedObject of parentEventPickedObjects) {
|
||||
if (
|
||||
parentEventPickedObjectNames.indexOf(pickedObject.getName()) <
|
||||
0
|
||||
) {
|
||||
parentEventPickedObjectNames.push(pickedObject.getName());
|
||||
}
|
||||
pickedSomething =
|
||||
pickedSomething || temporaryObjects.length > 0;
|
||||
pickedObjects.length = 0;
|
||||
pickedObjects.push.apply(pickedObjects, temporaryObjects);
|
||||
temporaryObjects.length = 0;
|
||||
}
|
||||
} else {
|
||||
// No object is linked for this name
|
||||
pickedObjects.length = 0;
|
||||
// In the case of a scene, the list of objects are guaranteed
|
||||
// to be indexed by the object name (no mix of objects with
|
||||
// different names in a list).
|
||||
parentEventPickedObjectNames.push(contextObjectName);
|
||||
}
|
||||
|
||||
// Sum the number of instances in the scene for each objects found
|
||||
// previously in parentEventPickedObjects, so that we know if we can
|
||||
// avoid running an intersection with the picked objects later.
|
||||
let objectCount = 0;
|
||||
for (const objectName of parentEventPickedObjectNames) {
|
||||
objectCount += runtimeScene.getObjects(objectName).length;
|
||||
}
|
||||
|
||||
if (parentEventPickedObjects.length === objectCount) {
|
||||
// The parent event didn't make any selection on the current object,
|
||||
// (because the number of picked objects is the total object count on the scene).
|
||||
// There is no need to make an intersection.
|
||||
// We will only replace the picked list with the linked object list.
|
||||
parentEventPickedObjects.length = 0;
|
||||
for (const objectName of parentEventPickedObjectNames) {
|
||||
if (linkedObjectMap.has(objectName)) {
|
||||
const linkedObjects = linkedObjectMap.get(objectName)!;
|
||||
|
||||
pickedSomething = pickedSomething || linkedObjects.length > 0;
|
||||
parentEventPickedObjects.push.apply(
|
||||
parentEventPickedObjects,
|
||||
linkedObjects
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Run an intersection between objects picked by parent events
|
||||
// and the linked ones.
|
||||
const pickedAndLinkedObjects = gdjs.staticArray(
|
||||
gdjs.evtTools.linkedObjects.pickObjectsLinkedTo
|
||||
);
|
||||
pickedAndLinkedObjects.length = 0;
|
||||
|
||||
for (const objectName of parentEventPickedObjectNames) {
|
||||
if (linkedObjectMap.has(objectName)) {
|
||||
const linkedObjects = linkedObjectMap.get(objectName)!;
|
||||
|
||||
for (const otherObject of linkedObjects) {
|
||||
if (parentEventPickedObjects.indexOf(otherObject) >= 0) {
|
||||
pickedAndLinkedObjects.push(otherObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pickedSomething =
|
||||
pickedSomething || pickedAndLinkedObjects.length > 0;
|
||||
parentEventPickedObjects.length = 0;
|
||||
parentEventPickedObjects.push.apply(
|
||||
parentEventPickedObjects,
|
||||
pickedAndLinkedObjects
|
||||
);
|
||||
pickedAndLinkedObjects.length = 0;
|
||||
}
|
||||
parentEventPickedObjectNames.length = 0;
|
||||
}
|
||||
}
|
||||
return pickedSomething;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user