mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
89 Commits
fix/thumbn
...
v5.0.134
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1ab023e211 | ||
![]() |
aa4e9e25bf | ||
![]() |
bc235ef492 | ||
![]() |
eabd1a4f23 | ||
![]() |
62ef3e729b | ||
![]() |
802ee0c03f | ||
![]() |
7ef2050de7 | ||
![]() |
eeea1b99f4 | ||
![]() |
e75d49ea51 | ||
![]() |
048674a7d0 | ||
![]() |
0502bd1f7a | ||
![]() |
66b84441ea | ||
![]() |
d9e27dc4f3 | ||
![]() |
a3c3ffc3bb | ||
![]() |
dc33b6cc01 | ||
![]() |
4a0c1c5ad2 | ||
![]() |
5820c5dd3e | ||
![]() |
606f5aff1b | ||
![]() |
1f42374417 | ||
![]() |
3356400026 | ||
![]() |
b811b1e873 | ||
![]() |
e985b11971 | ||
![]() |
aefc5e2fed | ||
![]() |
0ccb7c3216 | ||
![]() |
33c2c9c6cf | ||
![]() |
55a6306f05 | ||
![]() |
d766e32a18 | ||
![]() |
7cdf4e1184 | ||
![]() |
2540bf3c3e | ||
![]() |
6adec363d5 | ||
![]() |
91a02d132f | ||
![]() |
67718a364b | ||
![]() |
e9b600d885 | ||
![]() |
696dfcb746 | ||
![]() |
437edd1fe7 | ||
![]() |
48599ae9ca | ||
![]() |
c288700f2d | ||
![]() |
fbfb5dbaa6 | ||
![]() |
dfa27df64b | ||
![]() |
1ef404b9a9 | ||
![]() |
785dd6f08b | ||
![]() |
59bc76e144 | ||
![]() |
d873d9747a | ||
![]() |
a7fe36f351 | ||
![]() |
252eeb86b1 | ||
![]() |
66145ce506 | ||
![]() |
0dd10d2fce | ||
![]() |
5d35241c4c | ||
![]() |
ba368d9eed | ||
![]() |
fbeeb589a2 | ||
![]() |
3ec4e3b6dd | ||
![]() |
11ccaf2ea4 | ||
![]() |
274d31f563 | ||
![]() |
c37049cd72 | ||
![]() |
7cdc92c776 | ||
![]() |
471cd61d82 | ||
![]() |
afb66f213d | ||
![]() |
8ad70e57cc | ||
![]() |
d9ea04e059 | ||
![]() |
bb3abdb1fa | ||
![]() |
cdddcafa68 | ||
![]() |
14175c334e | ||
![]() |
6bd4dff03e | ||
![]() |
ceec39f6a2 | ||
![]() |
5abf80a0c9 | ||
![]() |
7f955d8703 | ||
![]() |
781dd42ccb | ||
![]() |
e584fa952d | ||
![]() |
5681667dde | ||
![]() |
d16f04f4a2 | ||
![]() |
e9b464beba | ||
![]() |
7597dbe0d1 | ||
![]() |
4777f0a824 | ||
![]() |
5b2532f8f3 | ||
![]() |
2c43de5120 | ||
![]() |
124ce1101d | ||
![]() |
eb3d6c2670 | ||
![]() |
f737fa479f | ||
![]() |
f93b3bc3b4 | ||
![]() |
5c6eb2dadb | ||
![]() |
3e6ca186f8 | ||
![]() |
860e9d36e4 | ||
![]() |
c8b461cc5f | ||
![]() |
36cdc5720a | ||
![]() |
a7cd53b921 | ||
![]() |
01a25400ff | ||
![]() |
2b484c0cf1 | ||
![]() |
13204e4b53 | ||
![]() |
c6d6466d54 |
@@ -2,10 +2,17 @@
|
||||
# on the Electron runtime (newIDE/electron-app) for macOS and Linux.
|
||||
# For Windows, see the appveyor.yml file.
|
||||
|
||||
# This also builds GDevelop.js and store it on a S3 so it can be used to run
|
||||
# GDevelop without building it from scratch.
|
||||
|
||||
# Note that these CircleCI builds/tests are not launched on Pull Requests from forks,
|
||||
# to avoid sharing secrets.
|
||||
|
||||
version: 2.1
|
||||
orbs:
|
||||
aws-cli: circleci/aws-cli@2.0.6
|
||||
jobs:
|
||||
# Build the **entire** app for macOS.
|
||||
build-macos:
|
||||
macos:
|
||||
xcode: 12.5.1
|
||||
@@ -75,6 +82,7 @@ jobs:
|
||||
name: Deploy to S3 (latest)
|
||||
command: export PATH=~/.local/bin:$PATH && aws s3 sync newIDE/electron-app/dist s3://gdevelop-releases/$(git rev-parse --abbrev-ref HEAD)/latest/
|
||||
|
||||
# Build the **entire** app for Linux.
|
||||
build-linux:
|
||||
# CircleCI docker workers are failing if they don't have enough memory (no swap)
|
||||
resource_class: xlarge
|
||||
@@ -153,10 +161,67 @@ jobs:
|
||||
name: Deploy to S3 (latest)
|
||||
command: aws s3 sync newIDE/electron-app/dist s3://gdevelop-releases/$(git rev-parse --abbrev-ref HEAD)/latest/
|
||||
|
||||
# Build the WebAssembly library only (so that it's cached on a S3 and easy to re-use).
|
||||
build-gdevelop_js-wasm-only:
|
||||
docker:
|
||||
- image: cimg/node:16.13
|
||||
|
||||
working_directory: ~/GDevelop
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
- aws-cli/setup
|
||||
|
||||
# System dependencies (for Emscripten)
|
||||
- run:
|
||||
name: Install dependencies for Emscripten
|
||||
command: sudo apt-get update && sudo apt install cmake
|
||||
|
||||
- run:
|
||||
name: Install Python3 dependencies for Emscripten
|
||||
command: sudo apt install python-is-python3 python3-distutils -y
|
||||
|
||||
- run:
|
||||
name: Install Emscripten (for GDevelop.js)
|
||||
command: git clone https://github.com/juj/emsdk.git && cd emsdk && ./emsdk install 1.39.6 && ./emsdk activate 1.39.6 && cd ..
|
||||
|
||||
# GDevelop.js dependencies
|
||||
- restore_cache:
|
||||
keys:
|
||||
- gdevelop.js-linux-nodejs-dependencies-{{ checksum "GDevelop.js/package-lock.json" }}
|
||||
# fallback to using the latest cache if no exact match is found
|
||||
- gdevelop.js-linux-nodejs-dependencies-
|
||||
|
||||
- run:
|
||||
name: Install GDevelop.js dependencies and build it
|
||||
command: cd GDevelop.js && npm install && cd ..
|
||||
|
||||
# Build GDevelop.js (and run tests to ensure it works)
|
||||
- run:
|
||||
name: Build GDevelop.js
|
||||
command: cd GDevelop.js && source ../emsdk/emsdk_env.sh && npm run build && npm test && cd ..
|
||||
|
||||
- save_cache:
|
||||
paths:
|
||||
- GDevelop.js/node_modules
|
||||
key: gdevelop.js-linux-nodejs-dependencies-{{ checksum "GDevelop.js/package-lock.json" }}
|
||||
|
||||
# Upload artifacts (CircleCI)
|
||||
- store_artifacts:
|
||||
path: Binaries/embuild/GDevelop.js
|
||||
|
||||
# Upload artifacts (AWS)
|
||||
- run:
|
||||
name: Deploy to S3 (specific commit)
|
||||
command: aws s3 sync Binaries/embuild/GDevelop.js s3://gdevelop-gdevelop.js/$(git rev-parse --abbrev-ref HEAD)/commit/$(git rev-parse HEAD)/
|
||||
- run:
|
||||
name: Deploy to S3 (latest)
|
||||
command: aws s3 sync Binaries/embuild/GDevelop.js s3://gdevelop-gdevelop.js/$(git rev-parse --abbrev-ref HEAD)/latest/
|
||||
|
||||
workflows:
|
||||
builds:
|
||||
jobs:
|
||||
- build-gdevelop_js-wasm-only
|
||||
- build-macos:
|
||||
filters:
|
||||
branches:
|
||||
|
2
.github/workflows/issues.yml
vendored
2
.github/workflows/issues.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
type: "body"
|
||||
regex: ".*Scroll down to '\\.\\.\\.\\.'.*"
|
||||
message: "Hi @${issue.user.login}! 👋 This issue was automatically closed because it seems that you have not included any steps to reproduce the bug.\n\nGitHub is a place for the technical development of GDevelop itself - you may want to go on the [forum](https://forum.gdevelop-app.com/), the Discord chat or [read the documentation](http://wiki.compilgames.net/doku.php/gdevelop5/start) to learn more about GDevelop. Thanks!"
|
||||
message: "Hi @${issue.user.login}! 👋 This issue was automatically closed because it seems that you have not included any steps to reproduce the bug.\n\nGitHub is a place for the technical development of GDevelop itself - you may want to go on the [forum](https://forum.gdevelop-app.com/), the Discord chat or [read the documentation](https://wiki.gdevelop.io/gdevelop5/start) to learn more about GDevelop. Thanks!"
|
||||
- name: Autoclose known beta 105 web-app update bug
|
||||
uses: arkon/issue-closer-action@v1.1
|
||||
with:
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -8,6 +8,7 @@
|
||||
/Binaries/.embuild*
|
||||
/Binaries/build*
|
||||
/Binaries/embuild*
|
||||
/emsdk
|
||||
*.dll
|
||||
*.exe
|
||||
*.a
|
||||
|
25
.gitpod.yml
Normal file
25
.gitpod.yml
Normal file
@@ -0,0 +1,25 @@
|
||||
# This is a configuration file allowing to quickly set up a development environment
|
||||
# on GitPod (https://www.gitpod.io/).
|
||||
# Also check GitHub codespaces if you're interested in working
|
||||
# on a remote development server.
|
||||
|
||||
# This works well for:
|
||||
# - The editor web-app, including the C++ classes.
|
||||
# This is not yet adapted for:
|
||||
# - Working on the game engine or extensions, as they can't be easily tested on the web-app.
|
||||
# - Working on the desktop app (Electron).
|
||||
|
||||
tasks:
|
||||
- name: Install dependencies for Emscripten and build GDevelop.js
|
||||
init: |
|
||||
sudo apt-get update
|
||||
sudo apt install cmake python-is-python3 python3-distutils -y
|
||||
git clone https://github.com/juj/emsdk.git && cd emsdk && ./emsdk install 1.39.6 && ./emsdk activate 1.39.6 && cd ..
|
||||
cd GDevelop.js
|
||||
npm install
|
||||
source ../emsdk/emsdk_env.sh && npm run build -- --dev
|
||||
cd ..
|
||||
- name: Install GDevelop IDE dependencies
|
||||
init: cd newIDE/app && npm install && cd ../electron-app && npm install
|
||||
|
||||
|
26
.travis.yml
26
.travis.yml
@@ -1,9 +1,6 @@
|
||||
# Travis CI configuration to build and run all tests
|
||||
# (and typing/formatting) for the Core, newIDE, GDJS.
|
||||
#
|
||||
# This builds GDevelop.js and store it on a S3 so it can be used to run
|
||||
# GDevelop without building it.
|
||||
#
|
||||
# See also Semaphore CI for quick tests (not building GDevelop.js, so
|
||||
# faster but not always reliable).
|
||||
|
||||
@@ -17,18 +14,7 @@ cache:
|
||||
directories:
|
||||
- $HOME/.npm
|
||||
|
||||
services:
|
||||
# Virtual Framebuffer 'fake' X server for SFML
|
||||
- xvfb
|
||||
|
||||
addons:
|
||||
artifacts:
|
||||
s3_region: "us-east-1"
|
||||
target_paths:
|
||||
- /$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then echo $TRAVIS_BRANCH; else echo $TRAVIS_PULL_REQUEST_BRANCH; fi)/commit/$(git rev-parse HEAD)
|
||||
- /$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then echo $TRAVIS_BRANCH; else echo $TRAVIS_PULL_REQUEST_BRANCH; fi)/latest
|
||||
paths:
|
||||
- Binaries/embuild/GDevelop.js
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
@@ -36,20 +22,8 @@ addons:
|
||||
# Build dependencies:
|
||||
- cmake
|
||||
- p7zip-full
|
||||
# SFML dependencies:
|
||||
- libopenal-dev
|
||||
- libjpeg-dev
|
||||
- libglew-dev
|
||||
- libudev-dev
|
||||
- libxrandr-dev
|
||||
- libsndfile1-dev
|
||||
- libglu1-mesa-dev
|
||||
- libfreetype6-dev
|
||||
|
||||
before_install:
|
||||
#Activate X Virtual Framebuffer to allow tests to
|
||||
#use SFML.
|
||||
- "export DISPLAY=:99.0"
|
||||
# This workaround is required to avoid libstdc++ errors (Emscripten requires a recent version of libstdc++)
|
||||
- wget -q -O libstdc++6 http://security.ubuntu.com/ubuntu/pool/main/g/gcc-5/libstdc++6_5.4.0-6ubuntu1~16.04.12_amd64.deb
|
||||
- sudo dpkg --force-all -i libstdc++6
|
||||
|
7
.vscode/c_cpp_properties.json
vendored
7
.vscode/c_cpp_properties.json
vendored
@@ -7,11 +7,9 @@
|
||||
"${workspaceRoot}/GDJS",
|
||||
"${workspaceRoot}/Extensions",
|
||||
"${workspaceRoot}/Core",
|
||||
"${workspaceRoot}/ExtLibs/SFML/include",
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1",
|
||||
"/usr/local/include",
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include",
|
||||
"/usr/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"defines": [
|
||||
@@ -27,7 +25,6 @@
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1",
|
||||
"/usr/local/include",
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include",
|
||||
"/usr/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
@@ -48,7 +45,6 @@
|
||||
"${workspaceRoot}/GDJS",
|
||||
"${workspaceRoot}/Extensions",
|
||||
"${workspaceRoot}/Core",
|
||||
"${workspaceRoot}/ExtLibs/SFML/include",
|
||||
"/usr/include",
|
||||
"/usr/local/include",
|
||||
"${workspaceRoot}"
|
||||
@@ -78,7 +74,6 @@
|
||||
"${workspaceRoot}/GDJS",
|
||||
"${workspaceRoot}/Extensions",
|
||||
"${workspaceRoot}/Core",
|
||||
"${workspaceRoot}/ExtLibs/SFML/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"defines": [
|
||||
@@ -101,4 +96,4 @@
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
}
|
||||
|
14
.vscode/launch.json
vendored
14
.vscode/launch.json
vendored
@@ -15,6 +15,20 @@
|
||||
"disableOptimisticBPs": true,
|
||||
"cwd": "${workspaceFolder}/GDevelop.js"
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "newIDE/app Jest tests (current file)",
|
||||
"program": "${workspaceFolder}/newIDE/app/node_modules/.bin/react-scripts",
|
||||
"args": [
|
||||
"test", "--env=node",
|
||||
"${fileBasenameNoExtension}"
|
||||
],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen",
|
||||
"disableOptimisticBPs": true,
|
||||
"cwd": "${workspaceFolder}/newIDE/app"
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
|
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@@ -115,7 +115,6 @@
|
||||
"files.exclude": {
|
||||
"Binaries/*build*": true,
|
||||
"Binaries/Output": true,
|
||||
"ExtLibs/SFML": true,
|
||||
"GDJS/Runtime-dist": true,
|
||||
"docs": true,
|
||||
"newIDE/electron-app/dist": true,
|
||||
|
@@ -17,7 +17,7 @@ endmacro()
|
||||
gd_set_option(BUILD_CORE TRUE BOOL "TRUE to build GDevelop Core library")
|
||||
gd_set_option(BUILD_GDJS TRUE BOOL "TRUE to build GDevelop JS Platform")
|
||||
gd_set_option(BUILD_EXTENSIONS TRUE BOOL "TRUE to build the extensions")
|
||||
gd_set_option(BUILD_TESTS FALSE BOOL "TRUE to build the tests")
|
||||
gd_set_option(BUILD_TESTS TRUE BOOL "TRUE to build the tests")
|
||||
|
||||
# Disable deprecated code
|
||||
set(NO_GUI TRUE CACHE BOOL "" FORCE) #Force disable old GUI related code.
|
||||
|
@@ -14,7 +14,6 @@ set(GDCORE_lib_dir ${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMAKE_SY
|
||||
|
||||
#Dependencies on external libraries:
|
||||
###
|
||||
include_directories(${sfml_include_dir})
|
||||
|
||||
#Defines
|
||||
###
|
||||
@@ -68,14 +67,6 @@ set(LIBRARY_OUTPUT_PATH ${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMA
|
||||
set(ARCHIVE_OUTPUT_PATH ${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME})
|
||||
set(RUNTIME_OUTPUT_PATH ${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME})
|
||||
|
||||
#Linker files
|
||||
###
|
||||
IF(EMSCRIPTEN)
|
||||
#Nothing.
|
||||
ELSE()
|
||||
target_link_libraries(GDCore ${sfml_LIBRARIES})
|
||||
ENDIF()
|
||||
|
||||
#Tests
|
||||
###
|
||||
if(BUILD_TESTS)
|
||||
@@ -88,5 +79,5 @@ if(BUILD_TESTS)
|
||||
add_executable(GDCore_tests ${test_source_files})
|
||||
set_target_properties(GDCore_tests PROPERTIES BUILD_WITH_INSTALL_RPATH FALSE) #Allow finding dependencies directly from build path on Mac OS X.
|
||||
target_link_libraries(GDCore_tests GDCore)
|
||||
target_link_libraries(GDCore_tests ${sfml_LIBRARIES})
|
||||
target_link_libraries(GDCore_tests ${CMAKE_DL_LIBS})
|
||||
endif()
|
||||
|
@@ -13,7 +13,6 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "Utf8/utf8.h"
|
||||
#include <SFML/System/String.hpp>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define GD_DEPRECATED __attribute__((deprecated))
|
||||
|
36
Core/GDCore/Events/Builtin/AsyncEvent.cpp
Normal file
36
Core/GDCore/Events/Builtin/AsyncEvent.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#include "AsyncEvent.h"
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
|
||||
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
|
||||
#include "GDCore/Events/Serialization.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace gd {
|
||||
|
||||
AsyncEvent::AsyncEvent() : BaseEvent() {}
|
||||
|
||||
AsyncEvent::~AsyncEvent(){};
|
||||
|
||||
vector<const gd::InstructionsList *> AsyncEvent::GetAllActionsVectors() const {
|
||||
vector<const gd::InstructionsList *> allActions;
|
||||
allActions.push_back(&actions);
|
||||
|
||||
return allActions;
|
||||
}
|
||||
|
||||
vector<gd::InstructionsList *> AsyncEvent::GetAllActionsVectors() {
|
||||
vector<gd::InstructionsList *> allActions;
|
||||
allActions.push_back(&actions);
|
||||
|
||||
return allActions;
|
||||
}
|
||||
|
||||
} // namespace gd
|
61
Core/GDCore/Events/Builtin/AsyncEvent.h
Normal file
61
Core/GDCore/Events/Builtin/AsyncEvent.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef GDCORE_ASYNCEVENT_H
|
||||
#define GDCORE_ASYNCEVENT_H
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Events/Instruction.h"
|
||||
#include "GDCore/Events/InstructionsList.h"
|
||||
namespace gd {
|
||||
class Instruction;
|
||||
class Project;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Internal event for asynchronous actions.
|
||||
* This event gets added internally to the events tree when an
|
||||
* asynchronous action is used.
|
||||
*/
|
||||
class GD_CORE_API AsyncEvent : public gd::BaseEvent {
|
||||
public:
|
||||
AsyncEvent();
|
||||
AsyncEvent(const gd::Instruction &asyncAction_,
|
||||
const gd::InstructionsList &actions_,
|
||||
const gd::EventsList &subEvents_)
|
||||
: asyncAction(asyncAction_), actions(actions_), subEvents(subEvents_) {
|
||||
SetType("BuiltinAsync::Async");
|
||||
};
|
||||
virtual ~AsyncEvent();
|
||||
virtual gd::AsyncEvent *Clone() const { return new AsyncEvent(*this); }
|
||||
|
||||
virtual bool IsExecutable() const { return true; }
|
||||
|
||||
virtual bool CanHaveSubEvents() const { return true; }
|
||||
virtual const gd::EventsList &GetSubEvents() const { return subEvents; };
|
||||
virtual gd::EventsList &GetSubEvents() { return subEvents; };
|
||||
|
||||
const gd::InstructionsList &GetActions() const { return actions; };
|
||||
gd::InstructionsList &GetActions() { return actions; };
|
||||
|
||||
const gd::Instruction &GetInstruction() const { return asyncAction; };
|
||||
gd::Instruction &GetInstruction() { return asyncAction; };
|
||||
|
||||
virtual std::vector<const gd::InstructionsList *>
|
||||
GetAllActionsVectors() const;
|
||||
virtual std::vector<gd::InstructionsList *> GetAllActionsVectors();
|
||||
|
||||
private:
|
||||
gd::Instruction asyncAction;
|
||||
gd::InstructionsList actions;
|
||||
EventsList subEvents;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_STANDARDEVENT_H
|
@@ -63,8 +63,12 @@ void StandardEvent::UnserializeFrom(gd::Project& project,
|
||||
project, conditions, element.GetChild("conditions", 0, "Conditions"));
|
||||
gd::EventsListSerialization::UnserializeInstructionsFrom(
|
||||
project, actions, element.GetChild("actions", 0, "Actions"));
|
||||
gd::EventsListSerialization::UnserializeEventsFrom(
|
||||
project, events, element.GetChild("events", 0, "Events"));
|
||||
|
||||
events.Clear();
|
||||
if (element.HasChild("events", "Events")) {
|
||||
gd::EventsListSerialization::UnserializeEventsFrom(
|
||||
project, events, element.GetChild("events", 0, "Events"));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -4,7 +4,9 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
|
||||
#include "GDCore/Events/Tools/EventsCodeNameMangler.h"
|
||||
@@ -14,7 +16,7 @@ using namespace std;
|
||||
namespace gd {
|
||||
|
||||
void EventsCodeGenerationContext::InheritsFrom(
|
||||
const EventsCodeGenerationContext& parent_) {
|
||||
EventsCodeGenerationContext& parent_) {
|
||||
parent = &parent_;
|
||||
|
||||
// Objects lists declared by parent became "already declared" in the child
|
||||
@@ -24,8 +26,8 @@ void EventsCodeGenerationContext::InheritsFrom(
|
||||
parent_.objectsListsToBeDeclared.end(),
|
||||
std::inserter(alreadyDeclaredObjectsLists,
|
||||
alreadyDeclaredObjectsLists.begin()));
|
||||
std::copy(parent_.objectsListsWithoutPickingToBeDeclared.begin(),
|
||||
parent_.objectsListsWithoutPickingToBeDeclared.end(),
|
||||
std::copy(parent_.objectsListsOrEmptyToBeDeclared.begin(),
|
||||
parent_.objectsListsOrEmptyToBeDeclared.end(),
|
||||
std::inserter(alreadyDeclaredObjectsLists,
|
||||
alreadyDeclaredObjectsLists.begin()));
|
||||
std::copy(parent_.emptyObjectsListsToBeDeclared.begin(),
|
||||
@@ -33,6 +35,8 @@ void EventsCodeGenerationContext::InheritsFrom(
|
||||
std::inserter(alreadyDeclaredObjectsLists,
|
||||
alreadyDeclaredObjectsLists.begin()));
|
||||
|
||||
nearestAsyncParent = parent_.IsAsyncCallback() ? &parent_ : parent_.nearestAsyncParent;
|
||||
asyncDepth = parent_.asyncDepth;
|
||||
depthOfLastUse = parent_.depthOfLastUse;
|
||||
customConditionDepth = parent_.customConditionDepth;
|
||||
contextDepth = parent_.GetContextDepth() + 1;
|
||||
@@ -42,33 +46,59 @@ void EventsCodeGenerationContext::InheritsFrom(
|
||||
}
|
||||
}
|
||||
|
||||
void EventsCodeGenerationContext::InheritsAsAsyncCallbackFrom(
|
||||
EventsCodeGenerationContext& parent_) {
|
||||
// Increasing the async depth is enough to mark the context as an async callback.
|
||||
InheritsFrom(parent_);
|
||||
asyncDepth = parent_.asyncDepth + 1;
|
||||
}
|
||||
|
||||
void EventsCodeGenerationContext::Reuse(
|
||||
const EventsCodeGenerationContext& parent_) {
|
||||
EventsCodeGenerationContext& parent_) {
|
||||
InheritsFrom(parent_);
|
||||
if (parent_.CanReuse())
|
||||
contextDepth = parent_.GetContextDepth(); // Keep same context depth
|
||||
}
|
||||
|
||||
void EventsCodeGenerationContext::NotifyAsyncParentsAboutDeclaredObject(const gd::String& objectName) {
|
||||
gd::EventsCodeGenerationContext* asyncContext = IsAsyncCallback() ? this : nearestAsyncParent;
|
||||
for (;
|
||||
asyncContext != nullptr;
|
||||
asyncContext = asyncContext->parent->nearestAsyncParent)
|
||||
asyncContext->allObjectsListToBeDeclaredAcrossChildren.insert(objectName);
|
||||
}
|
||||
|
||||
void EventsCodeGenerationContext::ObjectsListNeeded(
|
||||
const gd::String& objectName) {
|
||||
if (!IsToBeDeclared(objectName))
|
||||
if (!IsToBeDeclared(objectName)) {
|
||||
objectsListsToBeDeclared.insert(objectName);
|
||||
|
||||
if (IsInsideAsync()) {
|
||||
NotifyAsyncParentsAboutDeclaredObject(objectName);
|
||||
}
|
||||
}
|
||||
|
||||
depthOfLastUse[objectName] = GetContextDepth();
|
||||
}
|
||||
|
||||
void EventsCodeGenerationContext::ObjectsListWithoutPickingNeeded(
|
||||
void EventsCodeGenerationContext::ObjectsListNeededOrEmptyIfJustDeclared(
|
||||
const gd::String& objectName) {
|
||||
if (!IsToBeDeclared(objectName))
|
||||
objectsListsWithoutPickingToBeDeclared.insert(objectName);
|
||||
if (!IsToBeDeclared(objectName)) {
|
||||
objectsListsOrEmptyToBeDeclared.insert(objectName);
|
||||
|
||||
if (IsInsideAsync()) {
|
||||
NotifyAsyncParentsAboutDeclaredObject(objectName);
|
||||
}
|
||||
}
|
||||
|
||||
depthOfLastUse[objectName] = GetContextDepth();
|
||||
}
|
||||
|
||||
void EventsCodeGenerationContext::EmptyObjectsListNeeded(
|
||||
const gd::String& objectName) {
|
||||
if (!IsToBeDeclared(objectName))
|
||||
if (!IsToBeDeclared(objectName)) {
|
||||
emptyObjectsListsToBeDeclared.insert(objectName);
|
||||
}
|
||||
|
||||
depthOfLastUse[objectName] = GetContextDepth();
|
||||
}
|
||||
@@ -77,8 +107,8 @@ std::set<gd::String> EventsCodeGenerationContext::GetAllObjectsToBeDeclared()
|
||||
const {
|
||||
std::set<gd::String> allObjectListsToBeDeclared(
|
||||
objectsListsToBeDeclared.begin(), objectsListsToBeDeclared.end());
|
||||
allObjectListsToBeDeclared.insert(objectsListsWithoutPickingToBeDeclared.begin(),
|
||||
objectsListsWithoutPickingToBeDeclared.end());
|
||||
allObjectListsToBeDeclared.insert(objectsListsOrEmptyToBeDeclared.begin(),
|
||||
objectsListsOrEmptyToBeDeclared.end());
|
||||
allObjectListsToBeDeclared.insert(emptyObjectsListsToBeDeclared.begin(),
|
||||
emptyObjectsListsToBeDeclared.end());
|
||||
|
||||
@@ -102,4 +132,21 @@ bool EventsCodeGenerationContext::IsSameObjectsList(
|
||||
otherContext.GetLastDepthObjectListWasNeeded(objectName);
|
||||
}
|
||||
|
||||
bool EventsCodeGenerationContext::ShouldUseAsyncObjectsList(
|
||||
const gd::String& objectName) const {
|
||||
if (!IsInsideAsync()) return false;
|
||||
|
||||
// Check if the objects list was used after (or in) the nearest async callback context.
|
||||
const gd::EventsCodeGenerationContext* asyncContext = IsAsyncCallback() ? this : nearestAsyncParent;
|
||||
if (parent->GetLastDepthObjectListWasNeeded(objectName) >= asyncContext->GetContextDepth()) {
|
||||
// The object was used in a context after (or in) the nearest async parent context, so we're not getting it from the
|
||||
// async object lists (it was already gotten from there in this previous context).
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the objects list is declared in a parent of the nearest async context, it means
|
||||
// the async context had to use an async objects list to access it.
|
||||
return asyncContext->ObjectAlreadyDeclaredByParents(objectName);
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
@@ -33,11 +34,7 @@ class GD_CORE_API EventsCodeGenerationContext {
|
||||
* updated to contain the maximal scope depth reached.
|
||||
*/
|
||||
EventsCodeGenerationContext(unsigned int* maxDepthLevel_ = nullptr)
|
||||
: contextDepth(0),
|
||||
customConditionDepth(0),
|
||||
maxDepthLevel(maxDepthLevel_),
|
||||
parent(NULL),
|
||||
reuseExplicitlyForbidden(false){};
|
||||
: maxDepthLevel(maxDepthLevel_){};
|
||||
virtual ~EventsCodeGenerationContext(){};
|
||||
|
||||
/**
|
||||
@@ -45,7 +42,13 @@ class GD_CORE_API EventsCodeGenerationContext {
|
||||
* another one. The child will then for example not declare again objects
|
||||
* already declared by its parent.
|
||||
*/
|
||||
void InheritsFrom(const EventsCodeGenerationContext& parent);
|
||||
void InheritsFrom(EventsCodeGenerationContext& parent);
|
||||
|
||||
/**
|
||||
* Call this method to make an EventsCodeGenerationContext as a "child" of
|
||||
* another one, but in the context of an async function.
|
||||
*/
|
||||
void InheritsAsAsyncCallbackFrom(EventsCodeGenerationContext& parent);
|
||||
|
||||
/**
|
||||
* \brief As InheritsFrom, mark the context as being the child of another one,
|
||||
@@ -53,7 +56,7 @@ class GD_CORE_API EventsCodeGenerationContext {
|
||||
*
|
||||
* Used for example for optimizing the last event of a list.
|
||||
*/
|
||||
void Reuse(const EventsCodeGenerationContext& parent);
|
||||
void Reuse(EventsCodeGenerationContext& parent);
|
||||
|
||||
/**
|
||||
* \brief Forbid any optimization that would reuse and modify the object list
|
||||
@@ -88,19 +91,19 @@ class GD_CORE_API EventsCodeGenerationContext {
|
||||
const EventsCodeGenerationContext* GetParentContext() const { return parent; }
|
||||
|
||||
/**
|
||||
* Mark the object has being the object being handled by the instruction
|
||||
* Mark the object as being the object being handled by the instruction.
|
||||
*/
|
||||
void SetCurrentObject(const gd::String& objectName) {
|
||||
currentObject = objectName;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set that no particular object is being handled by an instruction
|
||||
* Set that no particular object is being handled by an instruction.
|
||||
*/
|
||||
void SetNoCurrentObject() { currentObject = ""; };
|
||||
|
||||
/**
|
||||
* Get the object being handled by the instruction
|
||||
* Get the object being handled by the instruction.
|
||||
*/
|
||||
const gd::String& GetCurrentObject() const { return currentObject; };
|
||||
|
||||
@@ -109,7 +112,7 @@ class GD_CORE_API EventsCodeGenerationContext {
|
||||
*
|
||||
* The list will be filled with objects from the scene if it is the first time
|
||||
* it is requested, unless there is already an object list with this name
|
||||
* (i.e. `ObjectAlreadyDeclared(objectName)` returns true).
|
||||
* (i.e. `ObjectAlreadyDeclaredByParents(objectName)` returns true).
|
||||
*/
|
||||
void ObjectsListNeeded(const gd::String& objectName);
|
||||
|
||||
@@ -121,7 +124,7 @@ class GD_CORE_API EventsCodeGenerationContext {
|
||||
* from the scene. If there is already an objects list with this name, no new
|
||||
* list will be declared again.
|
||||
*/
|
||||
void ObjectsListWithoutPickingNeeded(const gd::String& objectName);
|
||||
void ObjectsListNeededOrEmptyIfJustDeclared(const gd::String& objectName);
|
||||
|
||||
/**
|
||||
* Call this when an instruction in the event needs an empty object list,
|
||||
@@ -134,29 +137,21 @@ class GD_CORE_API EventsCodeGenerationContext {
|
||||
void EmptyObjectsListNeeded(const gd::String& objectName);
|
||||
|
||||
/**
|
||||
* Return true if an object list has already been declared (or is going to be
|
||||
* declared).
|
||||
* Return true if an object list has already been declared by the parent contexts.
|
||||
*/
|
||||
bool ObjectAlreadyDeclared(const gd::String& objectName) const {
|
||||
bool ObjectAlreadyDeclaredByParents(const gd::String& objectName) const {
|
||||
return (alreadyDeclaredObjectsLists.find(objectName) !=
|
||||
alreadyDeclaredObjectsLists.end());
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Consider that \a objectName is now declared in the context.
|
||||
*/
|
||||
void SetObjectDeclared(const gd::String& objectName) {
|
||||
alreadyDeclaredObjectsLists.insert(objectName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the objects lists which will be declared by the current context
|
||||
* ( the non empty as well as the empty objects lists )
|
||||
* (normal, potentially empty or empty).
|
||||
*/
|
||||
std::set<gd::String> GetAllObjectsToBeDeclared() const;
|
||||
|
||||
/**
|
||||
* Return the objects lists which will be declared by the current context
|
||||
* Return the objects lists which will be declared by the current context.
|
||||
*/
|
||||
const std::set<gd::String>& GetObjectsListsToBeDeclared() const {
|
||||
return objectsListsToBeDeclared;
|
||||
@@ -166,9 +161,9 @@ class GD_CORE_API EventsCodeGenerationContext {
|
||||
* Return the objects lists which will be will be declared, without filling
|
||||
* them with objects from the scene.
|
||||
*/
|
||||
const std::set<gd::String>& GetObjectsListsToBeDeclaredWithoutPicking()
|
||||
const std::set<gd::String>& GetObjectsListsToBeEmptyIfJustDeclared()
|
||||
const {
|
||||
return objectsListsWithoutPickingToBeDeclared;
|
||||
return objectsListsOrEmptyToBeDeclared;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -184,7 +179,7 @@ class GD_CORE_API EventsCodeGenerationContext {
|
||||
* Return the objects lists which are already declared and can be used in the
|
||||
* current context without declaration.
|
||||
*/
|
||||
const std::set<gd::String>& GetObjectsListsAlreadyDeclared() const {
|
||||
const std::set<gd::String>& GetObjectsListsAlreadyDeclaredByParents() const {
|
||||
return alreadyDeclaredObjectsLists;
|
||||
};
|
||||
|
||||
@@ -227,22 +222,55 @@ class GD_CORE_API EventsCodeGenerationContext {
|
||||
*/
|
||||
size_t GetCurrentConditionDepth() const { return customConditionDepth; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* \brief Returns the list of all objects declared in this context
|
||||
* and subcontexts.
|
||||
* \warning Only works on an async callback's context.
|
||||
*
|
||||
* It is to be used by the Async event code generator to know what objects
|
||||
* lists to backup for the async callback and async callbacks after it.
|
||||
*/
|
||||
const std::set<gd::String>& GetAllDeclaredObjectsAcrossChildren() {
|
||||
return allObjectsListToBeDeclaredAcrossChildren;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if an object list should be gotten from a backed up
|
||||
* objects list instead of the parent context. This can happen inside an
|
||||
* asynchronous callback or a child context of an asynchronous callback (i.e:
|
||||
* the `asyncDepth` is not 0).
|
||||
*/
|
||||
bool ShouldUseAsyncObjectsList(const gd::String& objectName) const;
|
||||
|
||||
/**
|
||||
* Returns true if the code currently being generated is inside an
|
||||
* asynchronous context (either in an asynchronous callback, or in a children of
|
||||
* an asynchronous callback).
|
||||
*/
|
||||
bool IsInsideAsync() const { return asyncDepth != 0; };
|
||||
|
||||
/**
|
||||
* Returns true if the code currently being generated is an asynchronous
|
||||
* callback (but not a child of an asynchronous callback).
|
||||
*/
|
||||
bool IsAsyncCallback() const { return parent != nullptr && parent->asyncDepth != asyncDepth; }
|
||||
|
||||
/**
|
||||
* \brief Returns true if the given object is already going to be declared
|
||||
* (either as a traditional objects list, or one without picking, or one
|
||||
* empty).
|
||||
*
|
||||
* in this context (either as a traditional objects list, or an empty one).
|
||||
*/
|
||||
bool IsToBeDeclared(const gd::String& objectName) {
|
||||
return objectsListsToBeDeclared.find(objectName) !=
|
||||
objectsListsToBeDeclared.end() ||
|
||||
objectsListsWithoutPickingToBeDeclared.find(objectName) !=
|
||||
objectsListsWithoutPickingToBeDeclared.end() ||
|
||||
objectsListsOrEmptyToBeDeclared.find(objectName) !=
|
||||
objectsListsOrEmptyToBeDeclared.end() ||
|
||||
emptyObjectsListsToBeDeclared.find(objectName) !=
|
||||
emptyObjectsListsToBeDeclared.end();
|
||||
};
|
||||
|
||||
private:
|
||||
void NotifyAsyncParentsAboutDeclaredObject(const gd::String& objectName);
|
||||
|
||||
std::set<gd::String>
|
||||
alreadyDeclaredObjectsLists; ///< Objects lists already needed in a
|
||||
///< parent context.
|
||||
@@ -250,7 +278,7 @@ class GD_CORE_API EventsCodeGenerationContext {
|
||||
objectsListsToBeDeclared; ///< Objects lists that will be declared in
|
||||
///< this context.
|
||||
std::set<gd::String>
|
||||
objectsListsWithoutPickingToBeDeclared; ///< Objects lists that will be
|
||||
objectsListsOrEmptyToBeDeclared; ///< Objects lists that will be
|
||||
///< declared in this context,
|
||||
///< but not filled with scene's
|
||||
///< objects.
|
||||
@@ -260,21 +288,40 @@ class GD_CORE_API EventsCodeGenerationContext {
|
||||
///< but not filled with scene's
|
||||
///< objects and not filled with any
|
||||
///< previously existing objects list.
|
||||
std::set<gd::String>
|
||||
allObjectsListToBeDeclaredAcrossChildren; ///< This is only to be used by
|
||||
///< the async callback
|
||||
///< contexts to know all
|
||||
///< objects declared across
|
||||
///< all children, so that the
|
||||
///< necessary objects can be
|
||||
///< backed up.
|
||||
|
||||
std::map<gd::String, unsigned int>
|
||||
depthOfLastUse; ///< The context depth when an object was last used.
|
||||
gd::String
|
||||
currentObject; ///< The object being used by an action or condition.
|
||||
unsigned int contextDepth; ///< The depth of the context : 0 for a newly
|
||||
///< created context, n+1 for any context
|
||||
///< inheriting from context with depth n.
|
||||
unsigned int
|
||||
customConditionDepth; ///< The depth of the conditions being generated.
|
||||
unsigned int contextDepth = 0; ///< The depth of the context: 0 for a newly
|
||||
///< created context, n+1 for any context
|
||||
///< inheriting from context with depth n.
|
||||
unsigned int customConditionDepth =
|
||||
0; ///< The depth of the conditions being generated.
|
||||
unsigned int asyncDepth =
|
||||
0; ///< If higher than 0, the current context is an asynchronous callback,
|
||||
///< or a child context of an asynchronous callback:
|
||||
///< - If the parent's async depth != the current context async depth,
|
||||
///< then the current context is an asynchronous callback context.
|
||||
///< - Otherwise, it's a child of an asynchronous callback.
|
||||
unsigned int* maxDepthLevel; ///< A pointer to a unsigned int updated with
|
||||
///< the maximum depth reached.
|
||||
const EventsCodeGenerationContext*
|
||||
parent; ///< The parent of the current context. Can be NULL.
|
||||
bool reuseExplicitlyForbidden; ///< If set to true, forbid children context
|
||||
///< to reuse this one without inheriting.
|
||||
const EventsCodeGenerationContext* parent =
|
||||
nullptr; ///< The parent of the current context. Can be NULL.
|
||||
EventsCodeGenerationContext* nearestAsyncParent =
|
||||
nullptr; ///< The nearest parent context that is an async callback
|
||||
///< context.
|
||||
bool reuseExplicitlyForbidden =
|
||||
false; ///< If set to true, forbid children contexts
|
||||
///< to reuse this one without inheriting.
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -450,7 +450,9 @@ gd::String EventsCodeGenerator::GenerateConditionsListCode(
|
||||
* Generate code for an action.
|
||||
*/
|
||||
gd::String EventsCodeGenerator::GenerateActionCode(
|
||||
gd::Instruction& action, EventsCodeGenerationContext& context) {
|
||||
gd::Instruction& action,
|
||||
EventsCodeGenerationContext& context,
|
||||
const gd::String& optionalAsyncCallbackName) {
|
||||
gd::String actionCode;
|
||||
|
||||
const gd::InstructionMetadata& instrInfos =
|
||||
@@ -518,8 +520,12 @@ gd::String EventsCodeGenerator::GenerateActionCode(
|
||||
// Prepare arguments and generate the whole action code
|
||||
vector<gd::String> arguments = GenerateParametersCodes(
|
||||
action.GetParameters(), instrInfos.parameters, context);
|
||||
actionCode += GenerateObjectAction(
|
||||
realObjects[i], objInfo, arguments, instrInfos, context);
|
||||
actionCode += GenerateObjectAction(realObjects[i],
|
||||
objInfo,
|
||||
arguments,
|
||||
instrInfos,
|
||||
context,
|
||||
optionalAsyncCallbackName);
|
||||
|
||||
context.SetNoCurrentObject();
|
||||
}
|
||||
@@ -552,7 +558,8 @@ gd::String EventsCodeGenerator::GenerateActionCode(
|
||||
autoInfo,
|
||||
arguments,
|
||||
instrInfos,
|
||||
context);
|
||||
context,
|
||||
optionalAsyncCallbackName);
|
||||
|
||||
context.SetNoCurrentObject();
|
||||
}
|
||||
@@ -560,12 +567,72 @@ gd::String EventsCodeGenerator::GenerateActionCode(
|
||||
} else {
|
||||
vector<gd::String> arguments = GenerateParametersCodes(
|
||||
action.GetParameters(), instrInfos.parameters, context);
|
||||
actionCode += GenerateFreeAction(arguments, instrInfos, context);
|
||||
actionCode +=
|
||||
GenerateFreeAction(arguments, instrInfos, context, optionalAsyncCallbackName);
|
||||
}
|
||||
|
||||
return actionCode;
|
||||
}
|
||||
|
||||
const EventsCodeGenerator::CallbackDescriptor
|
||||
EventsCodeGenerator::GenerateCallback(
|
||||
const gd::String& callbackID,
|
||||
gd::EventsCodeGenerationContext& parentContext,
|
||||
gd::InstructionsList& actions,
|
||||
gd::EventsList* subEvents) {
|
||||
gd::EventsCodeGenerationContext callbackContext;
|
||||
callbackContext.InheritsAsAsyncCallbackFrom(parentContext);
|
||||
const gd::String callbackFunctionName =
|
||||
GetCodeNamespaceAccessor() + "asyncCallback" + callbackID;
|
||||
const gd::String callbackFunctionArguments =
|
||||
GenerateEventsParameters(callbackContext);
|
||||
|
||||
// Generate actions
|
||||
gd::String actionsCode = GenerateActionsListCode(actions, callbackContext);
|
||||
|
||||
// Generate subevents
|
||||
if (subEvents != nullptr) // Sub events
|
||||
{
|
||||
actionsCode += "\n{ //Subevents\n";
|
||||
actionsCode += GenerateEventsListCode(*subEvents, callbackContext);
|
||||
actionsCode += "} //End of subevents\n";
|
||||
}
|
||||
|
||||
// Compose the callback function and add outside main
|
||||
const gd::String actionsDeclarationsCode =
|
||||
GenerateObjectsDeclarationCode(callbackContext);
|
||||
|
||||
const gd::String callbackCode = callbackFunctionName + " = function (" +
|
||||
GenerateEventsParameters(callbackContext) +
|
||||
") {\n" + actionsDeclarationsCode +
|
||||
actionsCode + "}\n";
|
||||
|
||||
AddCustomCodeOutsideMain(callbackCode);
|
||||
|
||||
std::set<gd::String> requiredObjects;
|
||||
// Build the list of all objects required by the callback. Any object that has
|
||||
// already been declared could have gone through previous object picking, so
|
||||
// if such an object is used by the actions or subevents of this callback, we
|
||||
// must ask the caller to pass the already existing objects lists through a
|
||||
// `LongLivedObjectsList` to the callback function.
|
||||
for (const auto& objectUsedInSubTree :
|
||||
callbackContext.GetAllDeclaredObjectsAcrossChildren()) {
|
||||
if (callbackContext.ObjectAlreadyDeclaredByParents(objectUsedInSubTree))
|
||||
requiredObjects.insert(objectUsedInSubTree);
|
||||
};
|
||||
|
||||
return CallbackDescriptor(
|
||||
callbackFunctionName, callbackFunctionArguments, requiredObjects);
|
||||
};
|
||||
|
||||
const gd::String EventsCodeGenerator::GenerateEventsParameters(
|
||||
const gd::EventsCodeGenerationContext& context) {
|
||||
gd::String parameters = "runtimeScene";
|
||||
if (!HasProjectAndLayout()) parameters += ", eventsFunctionContext";
|
||||
if (context.IsInsideAsync()) parameters += ", asyncObjectsList";
|
||||
return parameters;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate actions code.
|
||||
*/
|
||||
@@ -743,23 +810,21 @@ gd::String EventsCodeGenerator::GenerateObjectsDeclarationCode(
|
||||
gd::String declarationsCode;
|
||||
for (auto object : context.GetObjectsListsToBeDeclared()) {
|
||||
gd::String objectListDeclaration = "";
|
||||
if (!context.ObjectAlreadyDeclared(object)) {
|
||||
if (!context.ObjectAlreadyDeclaredByParents(object)) {
|
||||
objectListDeclaration = "std::vector<RuntimeObject*> " +
|
||||
GetObjectListName(object, context) +
|
||||
" = runtimeContext->GetObjectsRawPointers(\"" +
|
||||
ConvertToString(object) + "\");\n";
|
||||
context.SetObjectDeclared(object);
|
||||
} else
|
||||
objectListDeclaration = declareObjectList(object, context);
|
||||
|
||||
declarationsCode += objectListDeclaration + "\n";
|
||||
}
|
||||
for (auto object : context.GetObjectsListsToBeDeclaredWithoutPicking()) {
|
||||
for (auto object : context.GetObjectsListsToBeEmptyIfJustDeclared()) {
|
||||
gd::String objectListDeclaration = "";
|
||||
if (!context.ObjectAlreadyDeclared(object)) {
|
||||
if (!context.ObjectAlreadyDeclaredByParents(object)) {
|
||||
objectListDeclaration = "std::vector<RuntimeObject*> " +
|
||||
GetObjectListName(object, context) + ";\n";
|
||||
context.SetObjectDeclared(object);
|
||||
} else
|
||||
objectListDeclaration = declareObjectList(object, context);
|
||||
|
||||
@@ -767,10 +832,9 @@ gd::String EventsCodeGenerator::GenerateObjectsDeclarationCode(
|
||||
}
|
||||
for (auto object : context.GetObjectsListsToBeDeclaredEmpty()) {
|
||||
gd::String objectListDeclaration = "";
|
||||
if (!context.ObjectAlreadyDeclared(object)) {
|
||||
if (!context.ObjectAlreadyDeclaredByParents(object)) {
|
||||
objectListDeclaration = "std::vector<RuntimeObject*> " +
|
||||
GetObjectListName(object, context) + ";\n";
|
||||
context.SetObjectDeclared(object);
|
||||
} else
|
||||
objectListDeclaration = "std::vector<RuntimeObject*> " +
|
||||
GetObjectListName(object, context) + ";\n";
|
||||
@@ -785,7 +849,7 @@ gd::String EventsCodeGenerator::GenerateObjectsDeclarationCode(
|
||||
* Generate events list code.
|
||||
*/
|
||||
gd::String EventsCodeGenerator::GenerateEventsListCode(
|
||||
gd::EventsList& events, const EventsCodeGenerationContext& parentContext) {
|
||||
gd::EventsList& events, EventsCodeGenerationContext& parentContext) {
|
||||
gd::String output;
|
||||
for (std::size_t eId = 0; eId < events.size(); ++eId) {
|
||||
// Each event has its own context : Objects picked in an event are totally
|
||||
@@ -801,6 +865,8 @@ gd::String EventsCodeGenerator::GenerateEventsListCode(
|
||||
// operation.
|
||||
bool reuseParentContext =
|
||||
parentContext.CanReuse() && eId == events.size() - 1;
|
||||
|
||||
// TODO: avoid creating if useless.
|
||||
gd::EventsCodeGenerationContext reusedContext;
|
||||
reusedContext.Reuse(parentContext);
|
||||
|
||||
@@ -1015,7 +1081,8 @@ gd::String EventsCodeGenerator::GenerateBehaviorCondition(
|
||||
gd::String EventsCodeGenerator::GenerateFreeAction(
|
||||
const std::vector<gd::String>& arguments,
|
||||
const gd::InstructionMetadata& instrInfos,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
gd::EventsCodeGenerationContext& context,
|
||||
const gd::String& optionalAsyncCallbackName) {
|
||||
// Generate call
|
||||
gd::String call;
|
||||
if (instrInfos.codeExtraInformation.type == "number" ||
|
||||
@@ -1042,6 +1109,11 @@ gd::String EventsCodeGenerator::GenerateFreeAction(
|
||||
call = instrInfos.codeExtraInformation.functionCallName + "(" +
|
||||
GenerateArgumentsList(arguments) + ")";
|
||||
}
|
||||
|
||||
if (!optionalAsyncCallbackName.empty())
|
||||
call = "runtimeScene.getAsyncTasksManager().addTask(" + call + ", " +
|
||||
optionalAsyncCallbackName + ")";
|
||||
|
||||
return call + ";\n";
|
||||
}
|
||||
|
||||
@@ -1050,7 +1122,8 @@ gd::String EventsCodeGenerator::GenerateObjectAction(
|
||||
const gd::ObjectMetadata& objInfo,
|
||||
const std::vector<gd::String>& arguments,
|
||||
const gd::InstructionMetadata& instrInfos,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
gd::EventsCodeGenerationContext& context,
|
||||
const gd::String& optionalAsyncCallbackName) {
|
||||
// Create call
|
||||
gd::String call;
|
||||
if ((instrInfos.codeExtraInformation.type == "number" ||
|
||||
@@ -1077,8 +1150,11 @@ gd::String EventsCodeGenerator::GenerateObjectAction(
|
||||
|
||||
call = instrInfos.codeExtraInformation.functionCallName + "(" +
|
||||
argumentsStr + ")";
|
||||
|
||||
return "For each picked object \"" + objectName + "\", call " + call + "(" +
|
||||
argumentsStr + ").\n";
|
||||
argumentsStr + ")" +
|
||||
(optionalAsyncCallbackName.empty() ? "" : (", then call" + optionalAsyncCallbackName)) +
|
||||
".\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1088,7 +1164,8 @@ gd::String EventsCodeGenerator::GenerateBehaviorAction(
|
||||
const gd::BehaviorMetadata& autoInfo,
|
||||
const std::vector<gd::String>& arguments,
|
||||
const gd::InstructionMetadata& instrInfos,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
gd::EventsCodeGenerationContext& context,
|
||||
const gd::String& optionalAsyncCallbackName) {
|
||||
// Create call
|
||||
gd::String call;
|
||||
if ((instrInfos.codeExtraInformation.type == "number" ||
|
||||
@@ -1114,8 +1191,11 @@ gd::String EventsCodeGenerator::GenerateBehaviorAction(
|
||||
|
||||
call = instrInfos.codeExtraInformation.functionCallName + "(" +
|
||||
argumentsStr + ")";
|
||||
|
||||
return "For each picked object \"" + objectName + "\", call " + call + "(" +
|
||||
argumentsStr + ")" + " for behavior \"" + behaviorName + "\".\n";
|
||||
argumentsStr + ")" + " for behavior \"" + behaviorName + "\"" +
|
||||
(optionalAsyncCallbackName.empty() ? "" : (", then call" + optionalAsyncCallbackName)) +
|
||||
".\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -77,7 +77,7 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
* \return Code
|
||||
*/
|
||||
virtual gd::String GenerateEventsListCode(
|
||||
gd::EventsList& events, const EventsCodeGenerationContext& context);
|
||||
gd::EventsList& events, EventsCodeGenerationContext& context);
|
||||
|
||||
/**
|
||||
* \brief Generate code for executing a condition list
|
||||
@@ -155,7 +155,51 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
* \return Code
|
||||
*/
|
||||
gd::String GenerateActionCode(gd::Instruction& action,
|
||||
EventsCodeGenerationContext& context);
|
||||
EventsCodeGenerationContext& context,
|
||||
const gd::String& optionalAsyncCallbackName = "");
|
||||
|
||||
struct CallbackDescriptor {
|
||||
CallbackDescriptor(const gd::String functionName_,
|
||||
const gd::String argumentsList_,
|
||||
const std::set<gd::String> requiredObjects_)
|
||||
: functionName(functionName_),
|
||||
argumentsList(argumentsList_),
|
||||
requiredObjects(requiredObjects_){};
|
||||
/**
|
||||
* The name by which the function can be invoked.
|
||||
*/
|
||||
const gd::String functionName;
|
||||
/**
|
||||
* The comma separated list of arguments that the function takes.
|
||||
*/
|
||||
const gd::String argumentsList;
|
||||
/**
|
||||
* A set of all objects that need to be backed up to be passed to the callback code.
|
||||
*/
|
||||
const std::set<gd::String> requiredObjects;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Generates actions and events as a callback.
|
||||
*
|
||||
* This is used by asynchronous functions to run the code out of the normal
|
||||
* events flow.
|
||||
*
|
||||
* \returns A set with all objects required by the callback code.
|
||||
* The caller must take care of backing them up in a LongLivedObjectsList,
|
||||
* and to pass it to the callback function as the last argument.
|
||||
*/
|
||||
virtual const CallbackDescriptor GenerateCallback(
|
||||
const gd::String& callbackFunctionName,
|
||||
gd::EventsCodeGenerationContext& parentContext,
|
||||
gd::InstructionsList& actions,
|
||||
gd::EventsList* subEvents = nullptr);
|
||||
|
||||
/**
|
||||
* \brief Generates the parameters list of an event's generated function.
|
||||
*/
|
||||
const gd::String GenerateEventsParameters(
|
||||
const gd::EventsCodeGenerationContext& context);
|
||||
|
||||
/**
|
||||
* \brief Generate code for declaring objects lists.
|
||||
@@ -462,17 +506,10 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
* Other standard parameters type that should be implemented by platforms:
|
||||
* - currentScene: Reference to the current runtime scene.
|
||||
* - objectList : a map containing lists of objects which are specified by the
|
||||
object name in another parameter. Example:
|
||||
* \code
|
||||
AddExpression("Count", _("Object count"), _("Count the number of picked
|
||||
objects"), _("Objects"), "res/conditions/nbObjet.png")
|
||||
.AddParameter("objectList", _("Object"))
|
||||
.SetFunctionName("getPickedObjectsCount");
|
||||
|
||||
* \endcode
|
||||
* - objectListWithoutPicking : Same as objectList but do not pick object if
|
||||
object name in another parameter.
|
||||
* - objectListOrEmptyIfJustDeclared : Same as `objectList` but do not pick object if
|
||||
they are not already picked.
|
||||
* - objectPtr : Return a reference to the object specified by the object name in
|
||||
* - objectPtr: Return a reference to the object specified by the object name in
|
||||
another parameter. Example:
|
||||
* \code
|
||||
.AddParameter("object", _("Object"))
|
||||
@@ -665,14 +702,16 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
virtual gd::String GenerateFreeAction(
|
||||
const std::vector<gd::String>& arguments,
|
||||
const gd::InstructionMetadata& instrInfos,
|
||||
gd::EventsCodeGenerationContext& context);
|
||||
gd::EventsCodeGenerationContext& context,
|
||||
const gd::String& optionalAsyncCallbackName = "");
|
||||
|
||||
virtual gd::String GenerateObjectAction(
|
||||
const gd::String& objectName,
|
||||
const gd::ObjectMetadata& objInfo,
|
||||
const std::vector<gd::String>& arguments,
|
||||
const gd::InstructionMetadata& instrInfos,
|
||||
gd::EventsCodeGenerationContext& context);
|
||||
gd::EventsCodeGenerationContext& context,
|
||||
const gd::String& optionalAsyncCallbackName = "");
|
||||
|
||||
virtual gd::String GenerateBehaviorAction(
|
||||
const gd::String& objectName,
|
||||
@@ -680,7 +719,8 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
const gd::BehaviorMetadata& autoInfo,
|
||||
const std::vector<gd::String>& arguments,
|
||||
const gd::InstructionMetadata& instrInfos,
|
||||
gd::EventsCodeGenerationContext& context);
|
||||
gd::EventsCodeGenerationContext& context,
|
||||
const gd::String& optionalAsyncCallbackName = "");
|
||||
|
||||
gd::String GenerateRelationalOperatorCall(
|
||||
const gd::InstructionMetadata& instrInfos,
|
||||
|
@@ -5,8 +5,11 @@
|
||||
*/
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
|
||||
#include "GDCore/Events/Builtin/AsyncEvent.h"
|
||||
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
|
||||
@@ -65,10 +68,40 @@ gd::String BaseEvent::GenerateEventCode(
|
||||
return "";
|
||||
}
|
||||
|
||||
void BaseEvent::PreprocessAsyncActions(const gd::Platform& platform) {
|
||||
if (!CanHaveSubEvents()) return;
|
||||
for (const auto& actionsList : GetAllActionsVectors())
|
||||
for (std::size_t aId = 0; aId < actionsList->size(); ++aId) {
|
||||
const auto& action = actionsList->at(aId);
|
||||
const gd::InstructionMetadata& actionMetadata =
|
||||
gd::MetadataProvider::GetActionMetadata(platform, action.GetType());
|
||||
if (actionMetadata.IsAsync()) {
|
||||
gd::InstructionsList remainingActions;
|
||||
remainingActions.InsertInstructions(
|
||||
*actionsList, aId + 1, actionsList->size() - 1);
|
||||
gd::AsyncEvent asyncEvent(action, remainingActions, GetSubEvents());
|
||||
|
||||
// Ensure that the local event no longer has any of the actions/subevent
|
||||
// after the async function
|
||||
actionsList->RemoveAfter(aId);
|
||||
GetSubEvents().Clear();
|
||||
|
||||
GetSubEvents().InsertEvent(asyncEvent);
|
||||
|
||||
// We just moved all the rest, there's nothing left to do in this event.
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void BaseEvent::Preprocess(gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsList& eventList,
|
||||
std::size_t indexOfTheEventInThisList) {
|
||||
if (IsDisabled() || !MustBePreprocessed()) return;
|
||||
if (IsDisabled()) return;
|
||||
|
||||
PreprocessAsyncActions(codeGenerator.GetPlatform());
|
||||
|
||||
if (!MustBePreprocessed()) return;
|
||||
|
||||
try {
|
||||
if (type.empty()) return;
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Instruction.h"
|
||||
#include "GDCore/Events/InstructionsList.h"
|
||||
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
|
||||
@@ -23,7 +24,7 @@ class EventsCodeGenerationContext;
|
||||
class Platform;
|
||||
class SerializerElement;
|
||||
class Instruction;
|
||||
}
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
@@ -136,13 +137,15 @@ class GD_CORE_API BaseEvent {
|
||||
* \note Used to preprocess or search in the expressions of the event.
|
||||
*/
|
||||
virtual std::vector<std::pair<gd::Expression*, gd::ParameterMetadata> >
|
||||
GetAllExpressionsWithMetadata() {
|
||||
GetAllExpressionsWithMetadata() {
|
||||
std::vector<std::pair<gd::Expression*, gd::ParameterMetadata> > noExpr;
|
||||
return noExpr;
|
||||
};
|
||||
virtual std::vector<std::pair<const gd::Expression*, const gd::ParameterMetadata> >
|
||||
GetAllExpressionsWithMetadata() const {
|
||||
std::vector<std::pair<const gd::Expression*, const gd::ParameterMetadata> > noExpr;
|
||||
virtual std::vector<
|
||||
std::pair<const gd::Expression*, const gd::ParameterMetadata> >
|
||||
GetAllExpressionsWithMetadata() const {
|
||||
std::vector<std::pair<const gd::Expression*, const gd::ParameterMetadata> >
|
||||
noExpr;
|
||||
return noExpr;
|
||||
};
|
||||
|
||||
@@ -206,6 +209,11 @@ class GD_CORE_API BaseEvent {
|
||||
gd::EventsList& eventList,
|
||||
std::size_t indexOfTheEventInThisList);
|
||||
|
||||
/**
|
||||
* A function that turns all async member actions into an Async subevent for code generation.
|
||||
*/
|
||||
void PreprocessAsyncActions(const gd::Platform& platform);
|
||||
|
||||
/**
|
||||
* \brief If MustBePreprocessed is redefined to return true, the
|
||||
* gd::EventMetadata::preprocessing associated to the event will be called to
|
||||
|
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "InstructionsList.h"
|
||||
|
||||
#include "GDCore/Events/Instruction.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "Serialization.h"
|
||||
@@ -31,6 +32,10 @@ void InstructionsList::InsertInstructions(const InstructionsList& list,
|
||||
}
|
||||
}
|
||||
|
||||
void InstructionsList::RemoveAfter(const size_t position) {
|
||||
elements.resize(position);
|
||||
}
|
||||
|
||||
void InstructionsList::SerializeTo(SerializerElement& element) const {
|
||||
EventsListSerialization::SerializeInstructionsTo(*this, element);
|
||||
}
|
||||
|
@@ -6,9 +6,10 @@
|
||||
|
||||
#ifndef GDCORE_INSTRUCTIONSLIST_H
|
||||
#define GDCORE_INSTRUCTIONSLIST_H
|
||||
#include "GDCore/Tools/SPtrList.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "GDCore/Tools/SPtrList.h"
|
||||
|
||||
namespace gd {
|
||||
class Instruction;
|
||||
}
|
||||
@@ -22,11 +23,11 @@ class SerializerElement;
|
||||
namespace gd {
|
||||
|
||||
class InstructionsList : public SPtrList<gd::Instruction> {
|
||||
public:
|
||||
void InsertInstructions(const InstructionsList& list,
|
||||
size_t begin,
|
||||
size_t end,
|
||||
size_t position = (size_t)-1);
|
||||
public:
|
||||
void InsertInstructions(const InstructionsList &list, size_t begin,
|
||||
size_t end, size_t position = (size_t)-1);
|
||||
|
||||
void RemoveAfter(size_t position);
|
||||
|
||||
/** \name Serialization
|
||||
*/
|
||||
@@ -35,17 +36,17 @@ class InstructionsList : public SPtrList<gd::Instruction> {
|
||||
* \brief Serialize the instructions to the specified element
|
||||
* \see EventsListSerialization
|
||||
*/
|
||||
void SerializeTo(gd::SerializerElement& element) const;
|
||||
void SerializeTo(gd::SerializerElement &element) const;
|
||||
|
||||
/**
|
||||
* \brief Load the instructions from the specified element
|
||||
* \see EventsListSerialization
|
||||
*/
|
||||
void UnserializeFrom(gd::Project& project,
|
||||
const gd::SerializerElement& element);
|
||||
void UnserializeFrom(gd::Project &project,
|
||||
const gd::SerializerElement &element);
|
||||
///@}
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
} // namespace gd
|
||||
|
||||
#endif
|
||||
|
@@ -218,8 +218,8 @@ void EventsListSerialization::UnserializeEventsFrom(
|
||||
event = std::make_shared<EmptyEvent>();
|
||||
}
|
||||
|
||||
event->SetDisabled(eventElem.GetBoolAttribute("disabled"));
|
||||
event->SetFolded(eventElem.GetBoolAttribute("folded"));
|
||||
event->SetDisabled(eventElem.GetBoolAttribute("disabled", false));
|
||||
event->SetFolded(eventElem.GetBoolAttribute("folded", false));
|
||||
|
||||
list.InsertEvent(event, list.GetEventsCount());
|
||||
}
|
||||
@@ -232,8 +232,8 @@ void EventsListSerialization::SerializeEventsTo(const EventsList& list,
|
||||
const gd::BaseEvent& event = list.GetEvent(j);
|
||||
SerializerElement& eventElem = events.AddChild("event");
|
||||
|
||||
eventElem.SetAttribute("disabled", event.IsDisabled());
|
||||
eventElem.SetAttribute("folded", event.IsFolded());
|
||||
if (event.IsDisabled()) eventElem.SetAttribute("disabled", event.IsDisabled());
|
||||
if (event.IsFolded()) eventElem.SetAttribute("folded", event.IsFolded());
|
||||
eventElem.AddChild("type").SetValue(event.GetType());
|
||||
|
||||
event.SerializeTo(eventElem);
|
||||
|
@@ -42,6 +42,7 @@ class GD_CORE_API BuiltinExtensionsImplementer {
|
||||
static void ImplementsTimeExtension(gd::PlatformExtension& extension);
|
||||
static void ImplementsVariablesExtension(gd::PlatformExtension& extension);
|
||||
static void ImplementsWindowExtension(gd::PlatformExtension& extension);
|
||||
static void ImplementsAsyncExtension(gd::PlatformExtension& extension);
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
32
Core/GDCore/Extensions/Builtin/AsyncExtension.cpp
Normal file
32
Core/GDCore/Extensions/Builtin/AsyncExtension.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "AllBuiltinExtensions.h"
|
||||
#include "GDCore/Events/Builtin/AsyncEvent.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
|
||||
using namespace std;
|
||||
namespace gd {
|
||||
|
||||
void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAsyncExtension(
|
||||
gd::PlatformExtension &extension) {
|
||||
extension
|
||||
.SetExtensionInformation(
|
||||
"BuiltinAsync",
|
||||
_("Async functions"),
|
||||
_("Functions that defer the execution of the events after it."),
|
||||
"Arthur Pacaud (arthuro555)",
|
||||
"Open source (MIT License)")
|
||||
.SetCategory("Advanced");
|
||||
|
||||
extension.AddEvent("Async",
|
||||
_("Async event"),
|
||||
_("Internal event for asynchronous actions"),
|
||||
"",
|
||||
"res/eventaddicon.png",
|
||||
std::make_shared<gd::AsyncEvent>());
|
||||
}
|
||||
|
||||
} // namespace gd
|
@@ -343,6 +343,34 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
|
||||
"res/actions/music.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.MarkAsComplex();
|
||||
extension
|
||||
.AddAction(
|
||||
"FadeSoundVolume",
|
||||
_("Fade the volume of a sound played on a channel."),
|
||||
_("Fade the volume of a sound played on a channel to the specified volume within the specified duration."),
|
||||
_("Fade the sound on channel _PARAM1_ to volume _PARAM2_ within _PARAM3_ seconds"),
|
||||
_("Sounds on channels"),
|
||||
"res/actions/son24.png",
|
||||
"res/actions/son.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Channel identifier"))
|
||||
.AddParameter("expression", _("Final volume (0-100)"))
|
||||
.AddParameter("expression", _("Fading time in seconds"))
|
||||
.MarkAsAdvanced();
|
||||
extension
|
||||
.AddAction(
|
||||
"FadeMusicVolume",
|
||||
_("Fade the volume of a music played on a channel."),
|
||||
_("Fade the volume of a music played on a channel to the specified volume within the specified duration."),
|
||||
_("Fade the music on channel _PARAM1_ to volume _PARAM2_ within _PARAM3_ seconds"),
|
||||
_("Music on channels"),
|
||||
"res/actions/music24.png",
|
||||
"res/actions/music.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Channel identifier"))
|
||||
.AddParameter("expression", _("Final volume (0-100)"))
|
||||
.AddParameter("expression", _("Fading time in seconds"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddCondition("MusicPlaying",
|
||||
|
@@ -1252,7 +1252,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"res/actions/create24.png",
|
||||
"res/actions/create24.png")
|
||||
.AddCodeOnlyParameter("objectsContext", "")
|
||||
.AddParameter("objectListWithoutPicking", _("Object to create"))
|
||||
.AddParameter("objectListOrEmptyIfJustDeclared", _("Object to create"))
|
||||
.AddParameter("expression", _("X position"))
|
||||
.AddParameter("expression", _("Y position"))
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
@@ -1270,7 +1270,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"res/actions/create24.png",
|
||||
"res/actions/create24.png")
|
||||
.AddCodeOnlyParameter("objectsContext", "")
|
||||
.AddParameter("objectListWithoutPicking", _("Group of potential objects"))
|
||||
.AddParameter("objectListOrEmptyIfJustDeclared", _("Group of potential objects"))
|
||||
.SetParameterLongDescription(
|
||||
_("Group containing objects that can be created by the action."))
|
||||
.AddParameter("string", _("Name of the object to create"))
|
||||
@@ -1418,7 +1418,33 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"res/conditions/nbObjet.png")
|
||||
.AddParameter("objectList", _("Object"))
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsSimple();
|
||||
.MarkAsSimple()
|
||||
.SetHidden();
|
||||
|
||||
extension.AddExpressionAndCondition(
|
||||
"number",
|
||||
"SceneInstancesCount",
|
||||
_("Number of object instances on the scene"),
|
||||
_("the number of instances of the specified objects living on the scene"),
|
||||
_("the number of _PARAM1_ living on the scene"),
|
||||
_("Objects"),
|
||||
"res/conditions/nbObjet24.png")
|
||||
.AddCodeOnlyParameter("objectsContext", "")
|
||||
.AddParameter("objectListOrEmptyWithoutPicking", _("Object"))
|
||||
.UseStandardParameters("number")
|
||||
.MarkAsSimple();
|
||||
|
||||
extension.AddExpressionAndCondition(
|
||||
"number",
|
||||
"PickedInstancesCount",
|
||||
_("Number of object instances currently picked"),
|
||||
_("the number of instances picked by the previous conditions (or actions)"),
|
||||
_("the number of _PARAM0_ currently picked"),
|
||||
_("Objects"),
|
||||
"res/conditions/nbObjet24.png")
|
||||
.AddParameter("objectListOrEmptyWithoutPicking", _("Object"))
|
||||
.UseStandardParameters("number")
|
||||
.MarkAsSimple();
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
@@ -1526,7 +1552,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"currently picked in the event"),
|
||||
"",
|
||||
"res/conditions/nbObjet.png")
|
||||
.AddParameter("objectList", _("Object"));
|
||||
.AddParameter("objectList", _("Object"))
|
||||
.SetHidden(); // Deprecated
|
||||
|
||||
obj.AddStrExpression("ObjectName",
|
||||
_("Object name"),
|
||||
|
@@ -229,6 +229,15 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
"res/mathfunction.png")
|
||||
.AddParameter("expression", _("Expression"));
|
||||
|
||||
extension
|
||||
.AddExpression("ceilTo",
|
||||
_("Ceil (round up) to a decimal point"),
|
||||
_("Round number up to the Nth decimal place"),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddParameter("expression", _("Expression"))
|
||||
.AddParameter("expression", _("Expression"), "", true);
|
||||
|
||||
extension
|
||||
.AddExpression("floor",
|
||||
_("Floor (round down)"),
|
||||
@@ -237,6 +246,15 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
"res/mathfunction.png")
|
||||
.AddParameter("expression", _("Expression"));
|
||||
|
||||
extension
|
||||
.AddExpression("floorTo",
|
||||
_("Floor (round down) to a decimal point"),
|
||||
_("Round number down to the Nth decimal place"),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddParameter("expression", _("Expression"))
|
||||
.AddParameter("expression", _("Expression"), "", true);
|
||||
|
||||
extension
|
||||
.AddExpression("cos",
|
||||
_("Cosine"),
|
||||
@@ -295,6 +313,15 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
"res/mathfunction.png")
|
||||
.AddParameter("expression", _("Expression"));
|
||||
|
||||
extension
|
||||
.AddExpression("roundTo",
|
||||
_("Round to a decimal point"),
|
||||
_("Round a number to the Nth decimal place"),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddParameter("expression", _("Expression"))
|
||||
.AddParameter("expression", _("Expression"), "", true);
|
||||
|
||||
extension
|
||||
.AddExpression("exp",
|
||||
_("Exponential"),
|
||||
|
@@ -311,7 +311,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
|
||||
_("Multitouch"),
|
||||
"res/conditions/touch24.png",
|
||||
"res/conditions/touch.png")
|
||||
.AddCodeOnlyParameter("currentScene", "");
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.SetHidden();
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
@@ -326,8 +327,54 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
|
||||
_("Multitouch"),
|
||||
"res/conditions/touch24.png",
|
||||
"res/conditions/touch.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.SetHidden();
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
"HasAnyTouchStarted",
|
||||
_("A new touch has started"),
|
||||
_("Check if a touch has just started on this frame. The touch identifiers can be "
|
||||
"accessed using StartedTouchId() and StartedTouchCount()."),
|
||||
_("A new touch has started"),
|
||||
_("Multitouch"),
|
||||
"res/conditions/touch24.png",
|
||||
"res/conditions/touch.png")
|
||||
.AddCodeOnlyParameter("currentScene", "");
|
||||
|
||||
extension
|
||||
.AddExpression(
|
||||
"StartedTouchCount",
|
||||
_("Started touch count"),
|
||||
_("The number of touches that have just started on this frame. The touch identifiers can be "
|
||||
"accessed using StartedTouchId()."),
|
||||
_("Multitouch"),
|
||||
"res/conditions/touch.png")
|
||||
.AddCodeOnlyParameter("currentScene", "");
|
||||
|
||||
extension
|
||||
.AddExpression(
|
||||
"StartedTouchId",
|
||||
_("Started touch identifier"),
|
||||
_("The identifier of the touch that has just started on this frame. The touch number of touches can be "
|
||||
"accessed using StartedTouchCount()."),
|
||||
_("Multitouch"),
|
||||
"res/conditions/touch.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Touch index"));
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
"HasTouchEnded",
|
||||
_("A touch has ended"),
|
||||
_("Check if a touch has ended."),
|
||||
_("The touch with identifier _PARAM1_ has ended"),
|
||||
_("Multitouch"),
|
||||
"res/conditions/touch24.png",
|
||||
"res/conditions/touch.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Touch identifier"));
|
||||
|
||||
extension
|
||||
.AddExpression("MouseWheelDelta",
|
||||
_("Mouse wheel: Displacement"),
|
||||
@@ -342,7 +389,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
|
||||
_("Identifier of the last touch"),
|
||||
_("Multitouch"),
|
||||
"res/conditions/touch.png")
|
||||
.AddCodeOnlyParameter("currentScene", "");
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.SetHidden();
|
||||
|
||||
extension
|
||||
.AddExpression("LastEndedTouchId",
|
||||
@@ -350,7 +398,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
|
||||
_("Identifier of the last ended touch"),
|
||||
_("Multitouch"),
|
||||
"res/conditions/touch.png")
|
||||
.AddCodeOnlyParameter("currentScene", "");
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.SetHidden();
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -121,7 +121,7 @@ void Direction::UnserializeFrom(const gd::SerializerElement& element) {
|
||||
polygonElement.GetChild(k);
|
||||
|
||||
polygon.vertices.push_back(
|
||||
sf::Vector2f(verticeElement.GetDoubleAttribute("x"),
|
||||
gd::Vector2f(verticeElement.GetDoubleAttribute("x"),
|
||||
verticeElement.GetDoubleAttribute("y")));
|
||||
}
|
||||
|
||||
|
@@ -4,7 +4,7 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "Polygon2d.h"
|
||||
#include <SFML/System/Vector2.hpp>
|
||||
#include "GDCore/Vector2.h"
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
|
||||
@@ -28,7 +28,7 @@ void Polygon2d::Move(float x, float y) {
|
||||
}
|
||||
|
||||
void Polygon2d::ComputeEdges() const {
|
||||
sf::Vector2f v1, v2;
|
||||
gd::Vector2f v1, v2;
|
||||
edges.clear();
|
||||
|
||||
for (std::size_t i = 0; i < vertices.size(); i++) {
|
||||
@@ -62,8 +62,8 @@ bool Polygon2d::IsConvex() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
sf::Vector2f Polygon2d::ComputeCenter() const {
|
||||
sf::Vector2f center;
|
||||
gd::Vector2f Polygon2d::ComputeCenter() const {
|
||||
gd::Vector2f center;
|
||||
|
||||
for (std::size_t i = 0; i < vertices.size(); i++) {
|
||||
center.x += vertices[i].x;
|
||||
@@ -77,10 +77,10 @@ sf::Vector2f Polygon2d::ComputeCenter() const {
|
||||
|
||||
Polygon2d Polygon2d::CreateRectangle(float width, float height) {
|
||||
Polygon2d rect;
|
||||
rect.vertices.push_back(sf::Vector2f(-width / 2.0f, -height / 2.0f));
|
||||
rect.vertices.push_back(sf::Vector2f(+width / 2.0f, -height / 2.0f));
|
||||
rect.vertices.push_back(sf::Vector2f(+width / 2.0f, +height / 2.0f));
|
||||
rect.vertices.push_back(sf::Vector2f(-width / 2.0f, +height / 2.0f));
|
||||
rect.vertices.push_back(gd::Vector2f(-width / 2.0f, -height / 2.0f));
|
||||
rect.vertices.push_back(gd::Vector2f(+width / 2.0f, -height / 2.0f));
|
||||
rect.vertices.push_back(gd::Vector2f(+width / 2.0f, +height / 2.0f));
|
||||
rect.vertices.push_back(gd::Vector2f(-width / 2.0f, +height / 2.0f));
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
#ifndef GDCORE_POLYGON_H
|
||||
#define GDCORE_POLYGON_H
|
||||
#include <SFML/System/Vector2.hpp>
|
||||
#include "GDCore/Vector2.h"
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
@@ -22,19 +22,19 @@ class GD_CORE_API Polygon2d {
|
||||
Polygon2d(){};
|
||||
virtual ~Polygon2d(){};
|
||||
|
||||
std::vector<sf::Vector2f> vertices; ///< The vertices composing the polygon
|
||||
mutable std::vector<sf::Vector2f>
|
||||
std::vector<gd::Vector2f> vertices; ///< The vertices composing the polygon
|
||||
mutable std::vector<gd::Vector2f>
|
||||
edges; ///< Edges. Can be computed from vertices using ComputeEdges()
|
||||
|
||||
/**
|
||||
* \brief Get the vertices composing the polygon.
|
||||
*/
|
||||
std::vector<sf::Vector2f>& GetVertices() { return vertices; }
|
||||
std::vector<gd::Vector2f>& GetVertices() { return vertices; }
|
||||
|
||||
/**
|
||||
* \brief Get the vertices composing the polygon.
|
||||
*/
|
||||
const std::vector<sf::Vector2f>& GetVertices() const { return vertices; }
|
||||
const std::vector<gd::Vector2f>& GetVertices() const { return vertices; }
|
||||
|
||||
/**
|
||||
* \brief Moves each vertices from the given amount.
|
||||
@@ -68,7 +68,7 @@ class GD_CORE_API Polygon2d {
|
||||
/**
|
||||
* \brief Return the position of the center of the polygon
|
||||
*/
|
||||
sf::Vector2f ComputeCenter() const;
|
||||
gd::Vector2f ComputeCenter() const;
|
||||
|
||||
/** \name Tools
|
||||
* Tool functions
|
||||
|
@@ -4,7 +4,6 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/Sprite.h"
|
||||
#include <SFML/Graphics/Sprite.hpp>
|
||||
#include <iostream>
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/Polygon2d.h"
|
||||
|
||||
|
@@ -6,7 +6,6 @@
|
||||
|
||||
#ifndef SPRITE_H
|
||||
#define SPRITE_H
|
||||
#include <SFML/Graphics/Sprite.hpp>
|
||||
#include <memory>
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/Point.h"
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/Polygon2d.h"
|
||||
|
@@ -6,7 +6,6 @@
|
||||
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h"
|
||||
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
|
@@ -20,7 +20,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
|
||||
"for slow motion effects).",
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/all-features/timers");
|
||||
.SetExtensionHelpPath("/all-features/timers-and-time");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(
|
||||
_("Timers and time")
|
||||
)
|
||||
@@ -141,7 +141,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
|
||||
_("Change time scale"),
|
||||
_("Change the time scale of the scene."),
|
||||
_("Set the time scale of the scene to _PARAM1_"),
|
||||
|
||||
"",
|
||||
"res/actions/time24.png",
|
||||
"res/actions/time.png")
|
||||
@@ -149,6 +148,19 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
|
||||
.AddParameter("expression",
|
||||
_("Scale (1: Default, 2: 2x faster, 0.5: 2x slower...)"));
|
||||
|
||||
extension
|
||||
.AddAction("Wait",
|
||||
_("Wait X seconds (experimental)"),
|
||||
_("Waits a number of seconds before running "
|
||||
"the next actions (and sub-events)."),
|
||||
_("Wait _PARAM0_ seconds"),
|
||||
"",
|
||||
"res/timer.svg",
|
||||
"res/timer.svg")
|
||||
.AddParameter("expression", "Time to wait in seconds")
|
||||
.SetHelpPath("/all-features/timers-and-time/wait-action")
|
||||
.SetAsync();
|
||||
|
||||
extension
|
||||
.AddExpression("TimeDelta",
|
||||
_("Time elapsed since the last frame"),
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/String.h"
|
||||
|
@@ -22,6 +22,7 @@ InstructionMetadata::InstructionMetadata()
|
||||
canHaveSubInstructions(false),
|
||||
hidden(true),
|
||||
usageComplexity(5),
|
||||
isAsync(false),
|
||||
isPrivate(false),
|
||||
isObjectInstruction(false),
|
||||
isBehaviorInstruction(false) {}
|
||||
@@ -45,6 +46,7 @@ InstructionMetadata::InstructionMetadata(const gd::String& extensionNamespace_,
|
||||
extensionNamespace(extensionNamespace_),
|
||||
hidden(false),
|
||||
usageComplexity(5),
|
||||
isAsync(false),
|
||||
isPrivate(false),
|
||||
isObjectInstruction(false),
|
||||
isBehaviorInstruction(false) {}
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
|
||||
#include "GDCore/Events/Instruction.h"
|
||||
#include "GDCore/String.h"
|
||||
@@ -98,6 +99,23 @@ class GD_CORE_API InstructionMetadata {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the instruction is asynchronous - it will be running in the
|
||||
* background, executing the instructions following it before the frame after
|
||||
* it resolved.
|
||||
*/
|
||||
bool IsAsync() const { return isAsync; }
|
||||
|
||||
/**
|
||||
* Set that the instruction is asynchronous - it will be running in the
|
||||
* background, executing the instructions following it before the frame after
|
||||
* it resolved.
|
||||
*/
|
||||
InstructionMetadata &SetAsync() {
|
||||
isAsync = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify that the instruction can have sub instructions.
|
||||
*/
|
||||
@@ -461,6 +479,7 @@ class GD_CORE_API InstructionMetadata {
|
||||
int usageComplexity; ///< Evaluate the instruction from 0 (simple&easy to
|
||||
///< use) to 10 (complex to understand)
|
||||
bool isPrivate;
|
||||
bool isAsync;
|
||||
bool isObjectInstruction;
|
||||
bool isBehaviorInstruction;
|
||||
gd::String requiredBaseObjectCapability;
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class Project;
|
||||
@@ -151,15 +152,16 @@ class GD_CORE_API ParameterMetadata {
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the type of the parameter is "object", "objectPtr" or
|
||||
* "objectList".
|
||||
* \brief Return true if the type of the parameter is representing one object
|
||||
* (or more, i.e: an object group).
|
||||
*
|
||||
* \see gd::ParameterMetadata::GetType
|
||||
*/
|
||||
static bool IsObject(const gd::String ¶meterType) {
|
||||
return parameterType == "object" || parameterType == "objectPtr" ||
|
||||
parameterType == "objectList" ||
|
||||
parameterType == "objectListWithoutPicking";
|
||||
parameterType == "objectListOrEmptyIfJustDeclared" ||
|
||||
parameterType == "objectListOrEmptyWithoutPicking";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,7 +198,8 @@ class GD_CORE_API ParameterMetadata {
|
||||
parameterType == "objectPointName" ||
|
||||
parameterType == "objectAnimationName" ||
|
||||
parameterType == "functionParameterName" ||
|
||||
parameterType == "externalLayoutName";
|
||||
parameterType == "externalLayoutName" ||
|
||||
parameterType == "leaderboardId";
|
||||
} else if (type == "variable") {
|
||||
return parameterType == "objectvar" || parameterType == "globalvar" ||
|
||||
parameterType == "scenevar";
|
||||
|
@@ -117,6 +117,16 @@ void EffectsContainer::SwapEffects(std::size_t firstEffectIndex,
|
||||
effects[secondEffectIndex] = temp;
|
||||
}
|
||||
|
||||
void EffectsContainer::MoveEffect(std::size_t oldIndex, std::size_t newIndex) {
|
||||
if (oldIndex >= effects.size() || newIndex >= effects.size() ||
|
||||
newIndex == oldIndex)
|
||||
return;
|
||||
|
||||
auto effect = effects[oldIndex];
|
||||
effects.erase(effects.begin() + oldIndex);
|
||||
effects.insert(effects.begin() + newIndex, effect);
|
||||
}
|
||||
|
||||
void EffectsContainer::SerializeTo(SerializerElement& element) const {
|
||||
element.ConsiderAsArrayOf("effect");
|
||||
for (std::size_t i = 0; i < GetEffectsCount(); ++i) {
|
||||
|
@@ -7,6 +7,7 @@
|
||||
#define GDCORE_EFFECTS_CONTAINER_H
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "GDCore/String.h"
|
||||
|
||||
@@ -89,6 +90,11 @@ class GD_CORE_API EffectsContainer {
|
||||
*/
|
||||
void RemoveEffect(const gd::String& name);
|
||||
|
||||
/**
|
||||
* \brief Move the specified effect at a new position in the list.
|
||||
*/
|
||||
void MoveEffect(std::size_t oldIndex, std::size_t newIndex);
|
||||
|
||||
/**
|
||||
* Swap the position of two effects.
|
||||
*/
|
||||
|
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
#ifndef GDCORE_OBJECT_H
|
||||
#define GDCORE_OBJECT_H
|
||||
#include <SFML/System/Vector2.hpp>
|
||||
#include "GDCore/Vector2.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
@@ -7,6 +7,7 @@
|
||||
#ifndef GDCORE_OBJECTGROUPSCONTAINER_H
|
||||
#define GDCORE_OBJECTGROUPSCONTAINER_H
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include "GDCore/Project/ObjectGroup.h"
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
@@ -77,7 +78,6 @@ class GD_CORE_API ObjectGroupsContainer {
|
||||
*/
|
||||
bool IsEmpty() const { return objectGroups.empty(); };
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* \brief return the position of the group called "name" in the group list
|
||||
*/
|
||||
@@ -107,7 +107,6 @@ class GD_CORE_API ObjectGroupsContainer {
|
||||
* \brief Move the specified group at a new position in the list.
|
||||
*/
|
||||
void Move(std::size_t oldIndex, std::size_t newIndex);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Clear all groups of the container.
|
||||
|
@@ -9,7 +9,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <SFML/System/Utf.hpp>
|
||||
#include <cctype>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
@@ -66,6 +65,9 @@ Project::Project()
|
||||
projectUuid(""),
|
||||
useDeprecatedZeroAsDefaultZOrder(false),
|
||||
useExternalSourceFiles(false),
|
||||
isPlayableWithKeyboard(false),
|
||||
isPlayableWithGamepad(false),
|
||||
isPlayableWithMobile(false),
|
||||
currentPlatform(NULL),
|
||||
gdMajorVersion(gd::VersionWrapper::Major()),
|
||||
gdMinorVersion(gd::VersionWrapper::Minor()),
|
||||
|
@@ -92,7 +92,7 @@ double Variable::GetValue() const {
|
||||
return value;
|
||||
} else if (type == Type::String) {
|
||||
double retVal = str.empty() ? 0.0 : str.To<double>();
|
||||
if(std::isnan(retVal)) retVal = 0.0;
|
||||
if (std::isnan(retVal)) retVal = 0.0;
|
||||
return retVal;
|
||||
} else if (type == Type::Boolean) {
|
||||
return boolVal ? 1.0 : 0.0;
|
||||
@@ -188,6 +188,15 @@ const Variable& Variable::GetAtIndex(const size_t index) const {
|
||||
return *childrenArray.at(index);
|
||||
};
|
||||
|
||||
void Variable::MoveChildInArray(const size_t oldIndex, const size_t newIndex) {
|
||||
if (oldIndex >= childrenArray.size() || newIndex >= childrenArray.size())
|
||||
return;
|
||||
|
||||
std::shared_ptr<gd::Variable> object = std::move(childrenArray[oldIndex]);
|
||||
childrenArray.erase(childrenArray.begin() + oldIndex);
|
||||
childrenArray.insert(childrenArray.begin() + newIndex, std::move(object));
|
||||
}
|
||||
|
||||
Variable& Variable::PushNew() { return GetAtIndex(GetChildrenCount()); };
|
||||
|
||||
void Variable::RemoveAtIndex(const size_t index) {
|
||||
@@ -195,8 +204,29 @@ void Variable::RemoveAtIndex(const size_t index) {
|
||||
childrenArray.erase(childrenArray.begin() + index);
|
||||
};
|
||||
|
||||
bool Variable::InsertAtIndex(const gd::Variable& variable, const size_t index) {
|
||||
if (type != Type::Array) return false;
|
||||
auto newVariable = std::make_shared<gd::Variable>(variable);
|
||||
if (index < childrenArray.size()) {
|
||||
childrenArray.insert(childrenArray.begin() + index, newVariable);
|
||||
} else {
|
||||
childrenArray.push_back(newVariable);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
bool Variable::InsertChild(const gd::String& name,
|
||||
const gd::Variable& variable) {
|
||||
if (type != Type::Structure || HasChild(name)) {
|
||||
return false;
|
||||
}
|
||||
children[name] = std::make_shared<gd::Variable>(variable);
|
||||
return true;
|
||||
};
|
||||
|
||||
void Variable::SerializeTo(SerializerElement& element) const {
|
||||
element.SetStringAttribute("type", TypeAsString(GetType()));
|
||||
if (IsFolded()) element.SetBoolAttribute("folded", true);
|
||||
|
||||
if (type == Type::String) {
|
||||
element.SetStringAttribute("value", GetString());
|
||||
@@ -234,6 +264,7 @@ void Variable::UnserializeFrom(const SerializerElement& element) {
|
||||
if (element.HasChild("children", "Children") && IsPrimitive(type))
|
||||
type = Type::Structure;
|
||||
// end of compatibility code
|
||||
SetFolded(element.GetBoolAttribute("folded", false));
|
||||
|
||||
if (IsPrimitive(type)) {
|
||||
if (type == Type::String) {
|
||||
@@ -305,6 +336,7 @@ void Variable::RemoveRecursively(const gd::Variable& variableToRemove) {
|
||||
Variable::Variable(const Variable& other)
|
||||
: value(other.value),
|
||||
str(other.str),
|
||||
folded(other.folded),
|
||||
boolVal(other.boolVal),
|
||||
type(other.type) {
|
||||
CopyChildren(other);
|
||||
@@ -314,6 +346,7 @@ Variable& Variable::operator=(const Variable& other) {
|
||||
if (this != &other) {
|
||||
value = other.value;
|
||||
str = other.str;
|
||||
folded = other.folded;
|
||||
boolVal = other.boolVal;
|
||||
type = other.type;
|
||||
CopyChildren(other);
|
||||
|
@@ -6,10 +6,10 @@
|
||||
|
||||
#ifndef GDCORE_VARIABLE_H
|
||||
#define GDCORE_VARIABLE_H
|
||||
#include <cmath>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
@@ -98,7 +98,7 @@ class GD_CORE_API Variable {
|
||||
void SetValue(double val) {
|
||||
value = val;
|
||||
// NaN values are not supported by GDevelop nor the serializer.
|
||||
if(std::isnan(value)) value = 0.0;
|
||||
if (std::isnan(value)) value = 0.0;
|
||||
type = Type::Number;
|
||||
}
|
||||
|
||||
@@ -185,9 +185,9 @@ class GD_CORE_API Variable {
|
||||
* \brief Get the count of children that the variable has.
|
||||
*/
|
||||
size_t GetChildrenCount() const {
|
||||
return type == Type::Structure
|
||||
? children.size()
|
||||
: type == Type::Array ? childrenArray.size() : 0;
|
||||
return type == Type::Structure ? children.size()
|
||||
: type == Type::Array ? childrenArray.size()
|
||||
: 0;
|
||||
};
|
||||
|
||||
/** \name Structure
|
||||
@@ -290,12 +290,38 @@ class GD_CORE_API Variable {
|
||||
*/
|
||||
void RemoveAtIndex(const size_t index);
|
||||
|
||||
/**
|
||||
* \brief Move child in array.
|
||||
*/
|
||||
void MoveChildInArray(const size_t oldIndex, const size_t newIndex);
|
||||
|
||||
/**
|
||||
* \brief Insert child in array.
|
||||
*/
|
||||
bool InsertAtIndex(const gd::Variable& variable, const size_t index);
|
||||
|
||||
/**
|
||||
* \brief Insert a child in a structure.
|
||||
*/
|
||||
bool InsertChild(const gd::String& name, const gd::Variable& variable);
|
||||
|
||||
/**
|
||||
* \brief Get the vector containing all the children.
|
||||
*/
|
||||
const std::vector<std::shared_ptr<Variable>>& GetAllChildrenArray() const {
|
||||
return childrenArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set if the children must be folded.
|
||||
*/
|
||||
void SetFolded(bool fold = true) { folded = fold; }
|
||||
|
||||
/**
|
||||
* \brief True if the children should be folded in the variables editor.
|
||||
*/
|
||||
bool IsFolded() const { return folded; }
|
||||
|
||||
///@}
|
||||
///@}
|
||||
|
||||
@@ -325,6 +351,7 @@ class GD_CORE_API Variable {
|
||||
*/
|
||||
static Type StringAsType(const gd::String& str);
|
||||
|
||||
bool folded;
|
||||
mutable Type type;
|
||||
mutable gd::String str;
|
||||
mutable double value;
|
||||
|
@@ -4,8 +4,10 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/Project/VariablesContainer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
#include "GDCore/Project/Variable.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/String.h"
|
||||
@@ -88,7 +90,6 @@ Variable& VariablesContainer::Insert(const gd::String& name,
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
void VariablesContainer::Remove(const gd::String& varName) {
|
||||
variables.erase(
|
||||
std::remove_if(
|
||||
@@ -151,13 +152,14 @@ void VariablesContainer::Swap(std::size_t firstVariableIndex,
|
||||
}
|
||||
|
||||
void VariablesContainer::Move(std::size_t oldIndex, std::size_t newIndex) {
|
||||
if (oldIndex >= variables.size() || newIndex >= variables.size()) return;
|
||||
if (oldIndex >= variables.size() || newIndex >= variables.size() ||
|
||||
oldIndex == newIndex)
|
||||
return;
|
||||
|
||||
auto nameAndVariable = variables[oldIndex];
|
||||
variables.erase(variables.begin() + oldIndex);
|
||||
variables.insert(variables.begin() + newIndex, nameAndVariable);
|
||||
}
|
||||
#endif
|
||||
|
||||
void VariablesContainer::SerializeTo(SerializerElement& element) const {
|
||||
element.ConsiderAsArrayOf("variable");
|
||||
|
@@ -77,8 +77,6 @@ bool SerializerElement::GetBoolAttribute(const gd::String& name,
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Bool attribute \"" << name << "\" not found, returning "
|
||||
<< defaultValue;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
|
@@ -9,7 +9,6 @@
|
||||
#include <algorithm>
|
||||
#include <string.h>
|
||||
|
||||
#include <SFML/System/String.hpp>
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Utf8/utf8proc.h"
|
||||
|
||||
@@ -28,11 +27,6 @@ String::String(const char *characters) : m_string()
|
||||
*this = characters;
|
||||
}
|
||||
|
||||
String::String(const sf::String &string) : m_string()
|
||||
{
|
||||
*this = string;
|
||||
}
|
||||
|
||||
String::String(const std::u32string &string) : m_string()
|
||||
{
|
||||
*this = string;
|
||||
@@ -44,26 +38,6 @@ String& String::operator=(const char *characters)
|
||||
return *this;
|
||||
}
|
||||
|
||||
String& String::operator=(const sf::String &string)
|
||||
{
|
||||
m_string.clear();
|
||||
|
||||
//In theory, an UTF8 character can be up to 6 bytes (even if in the current Unicode standard,
|
||||
//the last character is 4 bytes long when encoded in UTF8).
|
||||
//So, reserve the maximum possible size to avoid reallocations.
|
||||
m_string.reserve( string.getSize() * 6 );
|
||||
|
||||
//Push_back all characters inside the string.
|
||||
for( sf::String::ConstIterator it = string.begin(); it != string.end(); ++it )
|
||||
{
|
||||
push_back( *it );
|
||||
}
|
||||
|
||||
m_string.shrink_to_fit();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
String& String::operator=(const std::u32string &string)
|
||||
{
|
||||
m_string.clear();
|
||||
@@ -112,7 +86,7 @@ String::const_iterator String::end() const
|
||||
String String::FromLocale( const std::string &localizedString )
|
||||
{
|
||||
#if defined(WINDOWS)
|
||||
return FromSfString(sf::String(localizedString)); //Don't need to use the current locale, on Windows, std::locale is always the C locale
|
||||
return FromUTF8(localizedString); //Don't need to use the current locale, on Windows, std::locale is always the C locale
|
||||
#elif defined(MACOS)
|
||||
return FromUTF8(localizedString); //Assume UTF8 is the current locale
|
||||
#elif defined(EMSCRIPTEN)
|
||||
@@ -124,7 +98,7 @@ String String::FromLocale( const std::string &localizedString )
|
||||
std::locale("").name().find("UTF8") != std::string::npos)
|
||||
return FromUTF8(localizedString); //UTF8 is already the current locale
|
||||
else
|
||||
return FromSfString(sf::String(localizedString, std::locale(""))); //Use the current locale (std::locale("")) for conversion
|
||||
return FromUTF8(localizedString); //Use the current locale (std::locale("")) for conversion
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -136,11 +110,6 @@ String String::FromUTF32( const std::u32string &string )
|
||||
return str;
|
||||
}
|
||||
|
||||
String String::FromSfString( const sf::String &sfString )
|
||||
{
|
||||
return String(sfString);
|
||||
}
|
||||
|
||||
String String::FromUTF8( const std::string &utf8Str )
|
||||
{
|
||||
String str(utf8Str.c_str());
|
||||
@@ -164,7 +133,7 @@ String String::FromWide( const std::wstring &wstr )
|
||||
std::string String::ToLocale() const
|
||||
{
|
||||
#if defined(WINDOWS)
|
||||
return ToSfString().toAnsiString();
|
||||
return m_string;
|
||||
#elif defined(MACOS)
|
||||
return m_string;
|
||||
#elif defined(EMSCRIPTEN)
|
||||
@@ -176,7 +145,7 @@ std::string String::ToLocale() const
|
||||
std::locale("").name().find("UTF8") != std::string::npos)
|
||||
return m_string; //UTF8 is already the current locale on Linux
|
||||
else
|
||||
return ToSfString().toAnsiString(std::locale("")); //Use the current locale for conversion
|
||||
return m_string; //Use the current locale for conversion
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -191,20 +160,6 @@ std::u32string String::ToUTF32() const
|
||||
return u32str;
|
||||
}
|
||||
|
||||
sf::String String::ToSfString() const
|
||||
{
|
||||
sf::String str;
|
||||
for(const_iterator it = begin(); it != end(); ++it)
|
||||
str += sf::String(static_cast<sf::Uint32>(*it));
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
String::operator sf::String() const
|
||||
{
|
||||
return ToSfString();
|
||||
}
|
||||
|
||||
std::string String::ToUTF8() const
|
||||
{
|
||||
return m_string;
|
||||
|
@@ -13,12 +13,9 @@
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <SFML/System/String.hpp>
|
||||
|
||||
#include "GDCore/Utf8/utf8.h"
|
||||
|
||||
namespace sf {class String;};
|
||||
|
||||
namespace gd
|
||||
{
|
||||
|
||||
@@ -121,11 +118,6 @@ public:
|
||||
*/
|
||||
String(const std::u32string &string);
|
||||
|
||||
/**
|
||||
* Constructs a string from an sf::String.
|
||||
*/
|
||||
String(const sf::String &string);
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
@@ -146,8 +138,6 @@ public:
|
||||
*/
|
||||
String& operator=(const char *characters);
|
||||
|
||||
String& operator=(const sf::String &string);
|
||||
|
||||
String& operator=(const std::u32string &string);
|
||||
|
||||
/**
|
||||
@@ -229,7 +219,6 @@ public:
|
||||
static String From(T value)
|
||||
{
|
||||
static_assert(!std::is_same<T, std::string>::value, "Can't use gd::String::From with std::string.");
|
||||
static_assert(!std::is_same<T, sf::String>::value, "Can't use gd::String::From with sf::String.");
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << value;
|
||||
@@ -244,7 +233,6 @@ public:
|
||||
T To() const
|
||||
{
|
||||
static_assert(!std::is_same<T, std::string>::value, "Can't use gd::String::To with std::string.");
|
||||
static_assert(!std::is_same<T, sf::String>::value, "Can't use gd::String::To with sf::String.");
|
||||
|
||||
T value;
|
||||
std::istringstream oss(m_string);
|
||||
@@ -274,13 +262,6 @@ public:
|
||||
*/
|
||||
static String FromUTF32( const std::u32string &string );
|
||||
|
||||
/**
|
||||
* \return a String created from a sf::String (UTF32).
|
||||
*
|
||||
* See \ref Conversions1 for more information.
|
||||
*/
|
||||
static String FromSfString( const sf::String &sfString );
|
||||
|
||||
/**
|
||||
* \return a String created an UTF8 encoded std::string.
|
||||
*/
|
||||
@@ -312,20 +293,6 @@ public:
|
||||
*/
|
||||
std::u32string ToUTF32() const;
|
||||
|
||||
/**
|
||||
* \return a sf::String from the current string.
|
||||
*
|
||||
* See \ref Conversions1 for more information.
|
||||
*/
|
||||
sf::String ToSfString() const;
|
||||
|
||||
/**
|
||||
* Implicit conversion operator to sf::String.
|
||||
*
|
||||
* See \ref Conversions1 for more information.
|
||||
*/
|
||||
operator sf::String() const;
|
||||
|
||||
/**
|
||||
* \return a UTF8 encoded std::string from the current string.
|
||||
*/
|
||||
@@ -885,7 +852,7 @@ namespace std
|
||||
* on the string size and so is the operator[]().
|
||||
*
|
||||
* \section Conversion Conversions from/to other string types
|
||||
* The String handles implicit conversion with sf::String (implicit constructor and implicit conversion
|
||||
* The String handles implicit conversion with std::String (implicit constructor and implicit conversion
|
||||
* operator).
|
||||
*
|
||||
* **However, this is not the case with std::string** as this conversion is not often lossless (mostly on Windows).
|
||||
@@ -894,16 +861,6 @@ namespace std
|
||||
* directly use the operator=() or the constructor as they are supporting const char* as argument (it assumes the string
|
||||
* literal is encoded in UTF8, so you'll need to put the u8 prefix).
|
||||
*
|
||||
* \subsection Conversions1 Implicit conversion from/to sf::String
|
||||
* \code
|
||||
* //Get a String from sf::String
|
||||
* sf::String sfmlStr("This is a test ! ");
|
||||
* gd::String str1(sfmlStr); //Now contains "This is a test ! " encoded in UTF8
|
||||
*
|
||||
* //Get a sf::String from String
|
||||
* sf::String anotherSfmlString = str; //anotherSfmlString now contains "Another test ! "
|
||||
* \endcode
|
||||
*
|
||||
* \subsection Conversions2 Conversion from/to std::string
|
||||
* \code
|
||||
* //Get a String from a std::string encoded in the current locale
|
||||
|
@@ -1,200 +0,0 @@
|
||||
#include "GDCore/Tools/FileStream.h"
|
||||
|
||||
#if defined(WINDOWS)
|
||||
#if __GLIBCXX__
|
||||
#include <ext/stdio_filebuf.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace gd {
|
||||
|
||||
namespace {
|
||||
|
||||
#if FSTREAM_WINDOWS_MINGW
|
||||
|
||||
#define MODE(in_val, out_val, trunc_val, app_val) \
|
||||
((((mode & std::ios_base::in) != 0) == in_val) && \
|
||||
(((mode & std::ios_base::out) != 0) == out_val) && \
|
||||
(((mode & std::ios_base::trunc) != 0) == trunc_val) && \
|
||||
(((mode & std::ios_base::app) != 0) == app_val))
|
||||
|
||||
std::wstring GetStdioMode(std::ios_base::openmode mode) {
|
||||
std::wstring strMode;
|
||||
|
||||
/// Thanks to https://gcc.gnu.org/ml/libstdc++/2007-06/msg00013.html
|
||||
if (MODE(false, true, false, false))
|
||||
strMode += L"w";
|
||||
else if (MODE(false, true, false, true))
|
||||
strMode += L"a";
|
||||
else if (MODE(true, true, false, true))
|
||||
strMode += L"a+";
|
||||
else if (MODE(false, true, true, false))
|
||||
strMode += L"w";
|
||||
else if (MODE(true, false, false, false))
|
||||
strMode += L"r";
|
||||
else if (MODE(true, true, false, false))
|
||||
strMode += L"r+";
|
||||
else if (MODE(true, true, true, false))
|
||||
strMode += L"w+";
|
||||
|
||||
if ((mode & std::ios_base::binary) != 0) strMode += L"b";
|
||||
|
||||
return strMode;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Open the given file into a filebuf and return it.
|
||||
* On Windows, return the associated FILE* inside the file argument.
|
||||
*/
|
||||
FileStream::InternalBufferType* OpenBuffer(const gd::String& path,
|
||||
std::ios_base::openmode mode,
|
||||
FILE** file) {
|
||||
#if FSTREAM_WINDOWS_MINGW
|
||||
*file = _wfopen(path.ToWide().c_str(), GetStdioMode(mode).c_str());
|
||||
if (!(*file)) return nullptr;
|
||||
return new __gnu_cxx::stdio_filebuf<char>(*file, mode);
|
||||
#else
|
||||
auto* filebuffer = new std::filebuf();
|
||||
return filebuffer->open(path.ToLocale().c_str(), mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
FileStream::FileStream() : std::iostream(nullptr) {}
|
||||
|
||||
FileStream::FileStream(const gd::String& path, std::ios_base::openmode mode)
|
||||
: std::iostream(nullptr),
|
||||
m_file(nullptr),
|
||||
m_buffer(OpenBuffer(path, mode, &m_file)) {
|
||||
setstate(ios_base::goodbit);
|
||||
if (m_buffer) {
|
||||
std::iostream::init(m_buffer.get());
|
||||
if ((mode & std::ios_base::ate) != 0) seekg(0, end);
|
||||
} else
|
||||
setstate(ios_base::badbit);
|
||||
}
|
||||
|
||||
FileStream::~FileStream() {
|
||||
if (is_open()) close();
|
||||
}
|
||||
|
||||
/*
|
||||
WILL WORK with GCC>=5 (not 4.9 used on Windows)
|
||||
FileStream::FileStream(FileStream && other) :
|
||||
std::iostream(std::move(other)),
|
||||
m_buffer(std::move(other.m_buffer))
|
||||
{
|
||||
|
||||
}*/
|
||||
|
||||
/*FileStream& FileStream::operator=(FileStream && other)
|
||||
{
|
||||
std::iostream::operator=(std::move(other));
|
||||
m_buffer = std::move(other.m_buffer);
|
||||
}*/
|
||||
|
||||
void FileStream::open(const gd::String& path, std::ios_base::openmode mode) {
|
||||
setstate(ios_base::goodbit);
|
||||
|
||||
if (is_open()) {
|
||||
setstate(ios_base::failbit);
|
||||
std::cout << "is_open true when trying to open!" << std::endl;
|
||||
} else {
|
||||
auto* newBuffer = OpenBuffer(path, mode, &m_file);
|
||||
if (newBuffer) {
|
||||
m_buffer.reset(newBuffer);
|
||||
std::iostream::init(m_buffer.get());
|
||||
if ((mode & std::ios_base::ate) != 0) seekg(0, end);
|
||||
} else {
|
||||
setstate(ios_base::badbit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FileStream::is_open() const {
|
||||
if (!m_buffer) return false;
|
||||
return m_buffer->is_open();
|
||||
}
|
||||
|
||||
void FileStream::close() {
|
||||
#if FSTREAM_WINDOWS_MINGW
|
||||
if (m_buffer) m_buffer->close();
|
||||
|
||||
if (m_file && fclose(m_file) != 0) {
|
||||
setstate(ios_base::failbit);
|
||||
}
|
||||
|
||||
m_buffer.reset(nullptr);
|
||||
m_file = nullptr;
|
||||
#else
|
||||
if (!m_buffer || m_buffer->close() == nullptr) {
|
||||
setstate(ios_base::failbit);
|
||||
} else {
|
||||
m_buffer.reset(nullptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*void FileStream::swap(FileStream & other) //WILL WORK with GCC>=5 (not 4.9
|
||||
used on Windows)
|
||||
{
|
||||
std::iostream::swap(other);
|
||||
std::swap(m_buffer, other.m_buffer);
|
||||
}*/
|
||||
|
||||
SFMLFileStream::SFMLFileStream() : m_file(nullptr) {}
|
||||
|
||||
SFMLFileStream::~SFMLFileStream() {
|
||||
if (m_file) fclose(m_file);
|
||||
}
|
||||
|
||||
bool SFMLFileStream::open(const gd::String& filename) {
|
||||
if (m_file) fclose(m_file);
|
||||
|
||||
#if FSTREAM_WINDOWS_MINGW
|
||||
m_file = _wfopen(filename.ToWide().c_str(), L"rb");
|
||||
#else
|
||||
m_file = fopen(filename.ToLocale().c_str(), "rb");
|
||||
#endif
|
||||
|
||||
return m_file != NULL;
|
||||
}
|
||||
|
||||
sf::Int64 SFMLFileStream::read(void* data, sf::Int64 size) {
|
||||
if (m_file)
|
||||
return fread(data, 1, static_cast<std::size_t>(size), m_file);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
sf::Int64 SFMLFileStream::seek(sf::Int64 position) {
|
||||
if (m_file) {
|
||||
fseek(m_file, static_cast<std::size_t>(position), SEEK_SET);
|
||||
return tell();
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
sf::Int64 SFMLFileStream::tell() {
|
||||
if (m_file)
|
||||
return ftell(m_file);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
sf::Int64 SFMLFileStream::getSize() {
|
||||
if (m_file) {
|
||||
sf::Int64 position = tell();
|
||||
fseek(m_file, 0, SEEK_END);
|
||||
sf::Int64 size = tell();
|
||||
seek(position);
|
||||
return size;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gd
|
@@ -1,82 +0,0 @@
|
||||
#ifndef GDCORE_FSTREAMTOOLS
|
||||
#define GDCORE_FSTREAMTOOLS
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include <SFML/System.hpp>
|
||||
|
||||
#include "GDCore/String.h"
|
||||
|
||||
#if defined(WINDOWS) && __GLIBCXX__
|
||||
#include <ext/stdio_filebuf.h>
|
||||
#else
|
||||
#include <fstream> //for std::filebuf
|
||||
#endif
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* Similar to std::i/ofstream except that it can open file with
|
||||
* gd::String paths (useful on Windows where fstream doesn't
|
||||
* support wide paths).
|
||||
*/
|
||||
class GD_CORE_API FileStream : public std::iostream {
|
||||
public:
|
||||
#if defined(WINDOWS) && __GLIBCXX__
|
||||
using InternalBufferType = std::basic_filebuf<char>;
|
||||
#else
|
||||
using InternalBufferType = std::filebuf;
|
||||
#endif
|
||||
|
||||
FileStream();
|
||||
FileStream(const gd::String& path, std::ios_base::openmode mode);
|
||||
~FileStream();
|
||||
|
||||
FileStream(const FileStream& other) = delete;
|
||||
FileStream(FileStream&& other) = delete; // HACK for GCC 4.9 (Windows)
|
||||
// FileStream(FileStream && other); WILL WORK with GCC>=5 (not 4.9 used on
|
||||
// Windows)
|
||||
|
||||
FileStream& operator=(const FileStream& other) = delete;
|
||||
FileStream& operator=(FileStream&& other) =
|
||||
delete; // HACK for GCC 4.9 (Windows)
|
||||
// FileStream& operator=(FileStream && other); WILL WORK with GCC>=5 (not 4.9
|
||||
// used on Windows)
|
||||
|
||||
void open(const gd::String& path, std::ios_base::openmode mode);
|
||||
|
||||
bool is_open() const;
|
||||
|
||||
void close();
|
||||
|
||||
// void swap(FileStream & other); //WILL WORK with GCC>=5 (not 4.9 used on
|
||||
// Windows)
|
||||
|
||||
private:
|
||||
FILE* m_file;
|
||||
std::unique_ptr<InternalBufferType> m_buffer;
|
||||
};
|
||||
|
||||
class GD_CORE_API SFMLFileStream : public sf::InputStream {
|
||||
public:
|
||||
SFMLFileStream();
|
||||
~SFMLFileStream();
|
||||
|
||||
bool open(const gd::String& filename);
|
||||
|
||||
virtual sf::Int64 read(void* data, sf::Int64 size);
|
||||
|
||||
virtual sf::Int64 seek(sf::Int64 position);
|
||||
|
||||
virtual sf::Int64 tell();
|
||||
|
||||
virtual sf::Int64 getSize();
|
||||
|
||||
private:
|
||||
FILE* m_file;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif
|
@@ -1,19 +0,0 @@
|
||||
#include <SFML/OpenGL.hpp>
|
||||
#include <cmath>
|
||||
|
||||
namespace OpenGLTools {
|
||||
|
||||
void GD_CORE_API PerspectiveGL(GLdouble fovY,
|
||||
GLdouble aspect,
|
||||
GLdouble zNear,
|
||||
GLdouble zFar) {
|
||||
const GLdouble pi = 3.1415926535897932384626433832795;
|
||||
GLdouble fW, fH;
|
||||
|
||||
fH = std::tan(fovY / 360 * pi) * zNear;
|
||||
fW = fH * aspect;
|
||||
|
||||
glFrustum(-fW, fW, -fH, fH, zNear, zFar);
|
||||
}
|
||||
|
||||
} // namespace OpenGLTools
|
@@ -1,9 +0,0 @@
|
||||
#include <SFML/OpenGL.hpp>
|
||||
|
||||
namespace OpenGLTools {
|
||||
|
||||
void GD_CORE_API PerspectiveGL(GLdouble fovY,
|
||||
GLdouble aspect,
|
||||
GLdouble zNear,
|
||||
GLdouble zFar);
|
||||
}
|
360
Core/GDCore/Vector2.h
Normal file
360
Core/GDCore/Vector2.h
Normal file
@@ -0,0 +1,360 @@
|
||||
// This is adapted from SFML (https://github.com/SFML/SFML).
|
||||
|
||||
#ifndef GDCORE_VECTOR2_H
|
||||
#define GDCORE_VECTOR2_H
|
||||
|
||||
namespace gd
|
||||
{
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Utility template class for manipulating
|
||||
/// 2-dimensional vectors
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
class Vector2
|
||||
{
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Default constructor
|
||||
///
|
||||
/// Creates a Vector2(0, 0).
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
inline Vector2() :
|
||||
x(0),
|
||||
y(0)
|
||||
{
|
||||
|
||||
}
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Construct the vector from its coordinates
|
||||
///
|
||||
/// \param X X coordinate
|
||||
/// \param Y Y coordinate
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
inline Vector2(T X, T Y) :
|
||||
x(X),
|
||||
y(Y)
|
||||
{
|
||||
|
||||
}
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Construct the vector from another type of vector
|
||||
///
|
||||
/// This constructor doesn't replace the copy constructor,
|
||||
/// it's called only when U != T.
|
||||
/// A call to this constructor will fail to compile if U
|
||||
/// is not convertible to T.
|
||||
///
|
||||
/// \param vector Vector to convert
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
template <typename U>
|
||||
inline explicit Vector2(const Vector2<U>& vector) :
|
||||
x(static_cast<T>(vector.x)),
|
||||
y(static_cast<T>(vector.y))
|
||||
{
|
||||
}
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
T x; ///< X coordinate of the vector
|
||||
T y; ///< Y coordinate of the vector
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \relates Vector2
|
||||
/// \brief Overload of unary operator -
|
||||
///
|
||||
/// \param right Vector to negate
|
||||
///
|
||||
/// \return Memberwise opposite of the vector
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
inline Vector2<T> operator -(const Vector2<T>& right)
|
||||
{
|
||||
return Vector2<T>(-right.x, -right.y);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \relates Vector2
|
||||
/// \brief Overload of binary operator +=
|
||||
///
|
||||
/// This operator performs a memberwise addition of both vectors,
|
||||
/// and assigns the result to \a left.
|
||||
///
|
||||
/// \param left Left operand (a vector)
|
||||
/// \param right Right operand (a vector)
|
||||
///
|
||||
/// \return Reference to \a left
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
inline Vector2<T>& operator +=(Vector2<T>& left, const Vector2<T>& right)
|
||||
{
|
||||
left.x += right.x;
|
||||
left.y += right.y;
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \relates Vector2
|
||||
/// \brief Overload of binary operator -=
|
||||
///
|
||||
/// This operator performs a memberwise subtraction of both vectors,
|
||||
/// and assigns the result to \a left.
|
||||
///
|
||||
/// \param left Left operand (a vector)
|
||||
/// \param right Right operand (a vector)
|
||||
///
|
||||
/// \return Reference to \a left
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
inline Vector2<T>& operator -=(Vector2<T>& left, const Vector2<T>& right)
|
||||
{
|
||||
left.x -= right.x;
|
||||
left.y -= right.y;
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \relates Vector2
|
||||
/// \brief Overload of binary operator +
|
||||
///
|
||||
/// \param left Left operand (a vector)
|
||||
/// \param right Right operand (a vector)
|
||||
///
|
||||
/// \return Memberwise addition of both vectors
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
inline Vector2<T> operator +(const Vector2<T>& left, const Vector2<T>& right)
|
||||
{
|
||||
return Vector2<T>(left.x + right.x, left.y + right.y);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \relates Vector2
|
||||
/// \brief Overload of binary operator -
|
||||
///
|
||||
/// \param left Left operand (a vector)
|
||||
/// \param right Right operand (a vector)
|
||||
///
|
||||
/// \return Memberwise subtraction of both vectors
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
inline Vector2<T> operator -(const Vector2<T>& left, const Vector2<T>& right)
|
||||
{
|
||||
return Vector2<T>(left.x - right.x, left.y - right.y);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \relates Vector2
|
||||
/// \brief Overload of binary operator *
|
||||
///
|
||||
/// \param left Left operand (a vector)
|
||||
/// \param right Right operand (a scalar value)
|
||||
///
|
||||
/// \return Memberwise multiplication by \a right
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
inline Vector2<T> operator *(const Vector2<T>& left, T right)
|
||||
{
|
||||
return Vector2<T>(left.x * right, left.y * right);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \relates Vector2
|
||||
/// \brief Overload of binary operator *
|
||||
///
|
||||
/// \param left Left operand (a scalar value)
|
||||
/// \param right Right operand (a vector)
|
||||
///
|
||||
/// \return Memberwise multiplication by \a left
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
inline Vector2<T> operator *(T left, const Vector2<T>& right)
|
||||
{
|
||||
return Vector2<T>(right.x * left, right.y * left);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \relates Vector2
|
||||
/// \brief Overload of binary operator *=
|
||||
///
|
||||
/// This operator performs a memberwise multiplication by \a right,
|
||||
/// and assigns the result to \a left.
|
||||
///
|
||||
/// \param left Left operand (a vector)
|
||||
/// \param right Right operand (a scalar value)
|
||||
///
|
||||
/// \return Reference to \a left
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
inline Vector2<T>& operator *=(Vector2<T>& left, T right)
|
||||
{
|
||||
left.x *= right;
|
||||
left.y *= right;
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \relates Vector2
|
||||
/// \brief Overload of binary operator /
|
||||
///
|
||||
/// \param left Left operand (a vector)
|
||||
/// \param right Right operand (a scalar value)
|
||||
///
|
||||
/// \return Memberwise division by \a right
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
inline Vector2<T> operator /(const Vector2<T>& left, T right)
|
||||
{
|
||||
return Vector2<T>(left.x / right, left.y / right);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \relates Vector2
|
||||
/// \brief Overload of binary operator /=
|
||||
///
|
||||
/// This operator performs a memberwise division by \a right,
|
||||
/// and assigns the result to \a left.
|
||||
///
|
||||
/// \param left Left operand (a vector)
|
||||
/// \param right Right operand (a scalar value)
|
||||
///
|
||||
/// \return Reference to \a left
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
inline Vector2<T>& operator /=(Vector2<T>& left, T right)
|
||||
{
|
||||
left.x /= right;
|
||||
left.y /= right;
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \relates Vector2
|
||||
/// \brief Overload of binary operator ==
|
||||
///
|
||||
/// This operator compares strict equality between two vectors.
|
||||
///
|
||||
/// \param left Left operand (a vector)
|
||||
/// \param right Right operand (a vector)
|
||||
///
|
||||
/// \return True if \a left is equal to \a right
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
inline bool operator ==(const Vector2<T>& left, const Vector2<T>& right)
|
||||
{
|
||||
return (left.x == right.x) && (left.y == right.y);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \relates Vector2
|
||||
/// \brief Overload of binary operator !=
|
||||
///
|
||||
/// This operator compares strict difference between two vectors.
|
||||
///
|
||||
/// \param left Left operand (a vector)
|
||||
/// \param right Right operand (a vector)
|
||||
///
|
||||
/// \return True if \a left is not equal to \a right
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
inline bool operator !=(const Vector2<T>& left, const Vector2<T>& right)
|
||||
{
|
||||
return (left.x != right.x) || (left.y != right.y);
|
||||
}
|
||||
|
||||
// Define the most common types
|
||||
typedef Vector2<int> Vector2i;
|
||||
typedef Vector2<unsigned int> Vector2u;
|
||||
typedef Vector2<float> Vector2f;
|
||||
|
||||
} // namespace gd
|
||||
|
||||
|
||||
#endif // GDCORE_VECTOR2_H
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \class gd::Vector2
|
||||
/// \ingroup CommonProgrammingTools
|
||||
///
|
||||
/// gd::Vector2 is a simple class that defines a mathematical
|
||||
/// vector with two coordinates (x and y). It can be used to
|
||||
/// represent anything that has two dimensions: a size, a point,
|
||||
/// a velocity, etc.
|
||||
///
|
||||
/// The template parameter T is the type of the coordinates. It
|
||||
/// can be any type that supports arithmetic operations (+, -, /, *)
|
||||
/// and comparisons (==, !=), for example int or float.
|
||||
///
|
||||
/// You generally don't have to care about the templated form (gd::Vector2<T>),
|
||||
/// the most common specializations have special typedefs:
|
||||
/// \li gd::Vector2<float> is gd::Vector2f
|
||||
/// \li gd::Vector2<int> is gd::Vector2i
|
||||
/// \li gd::Vector2<unsigned int> is gd::Vector2u
|
||||
///
|
||||
/// The gd::Vector2 class has a small and simple interface, its x and y members
|
||||
/// can be accessed directly (there are no accessors like setX(), getX()) and it
|
||||
/// contains no mathematical function like dot product, cross product, length, etc.
|
||||
///
|
||||
/// Usage example:
|
||||
/// \code
|
||||
/// gd::Vector2f v1(16.5f, 24.f);
|
||||
/// v1.x = 18.2f;
|
||||
/// float y = v1.y;
|
||||
///
|
||||
/// gd::Vector2f v2 = v1 * 5.f;
|
||||
/// gd::Vector2f v3;
|
||||
/// v3 = v1 + v2;
|
||||
///
|
||||
/// bool different = (v2 != v3);
|
||||
/// \endcode
|
||||
///
|
||||
/// Note: for 3-dimensional vectors, see gd::Vector3.
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
@@ -75,7 +75,11 @@ TEST_CASE("EventsList", "[common][events]") {
|
||||
|
||||
size_t endMemory = gd::SystemStats::GetUsedVirtualMemory();
|
||||
INFO("Memory used: " << endMemory - startMemory << "KB");
|
||||
REQUIRE(1500 >= endMemory - startMemory);
|
||||
#if defined(WINDOWS)
|
||||
REQUIRE(3000 >= endMemory - startMemory);
|
||||
#else
|
||||
REQUIRE(1500 >= endMemory - startMemory);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -31,7 +31,7 @@ TEST_CASE("EventsCodeGenerationContext", "[common][events]") {
|
||||
gd::EventsCodeGenerationContext c1(&maxDepth);
|
||||
c1.ObjectsListNeeded("c1.object1");
|
||||
c1.ObjectsListNeeded("c1.object2");
|
||||
c1.ObjectsListWithoutPickingNeeded("c1.noPicking1");
|
||||
c1.ObjectsListNeededOrEmptyIfJustDeclared("c1.noPicking1");
|
||||
|
||||
gd::EventsCodeGenerationContext c2;
|
||||
c2.InheritsFrom(c1);
|
||||
@@ -47,7 +47,7 @@ TEST_CASE("EventsCodeGenerationContext", "[common][events]") {
|
||||
|
||||
gd::EventsCodeGenerationContext c5;
|
||||
c5.InheritsFrom(c2);
|
||||
c5.ObjectsListWithoutPickingNeeded("c5.noPicking1");
|
||||
c5.ObjectsListNeededOrEmptyIfJustDeclared("c5.noPicking1");
|
||||
c5.ObjectsListNeeded("c5.object1");
|
||||
c5.ObjectsListNeeded("c1.object2");
|
||||
c5.EmptyObjectsListNeeded("c5.empty1");
|
||||
@@ -70,36 +70,36 @@ TEST_CASE("EventsCodeGenerationContext", "[common][events]") {
|
||||
}
|
||||
|
||||
SECTION("Object list needed") {
|
||||
REQUIRE(c1.GetObjectsListsAlreadyDeclared() == std::set<gd::String>());
|
||||
REQUIRE(c1.GetObjectsListsAlreadyDeclaredByParents() == std::set<gd::String>());
|
||||
REQUIRE(c1.GetObjectsListsToBeDeclared() ==
|
||||
std::set<gd::String>({"c1.object1", "c1.object2"}));
|
||||
REQUIRE(c1.GetObjectsListsToBeDeclaredWithoutPicking() ==
|
||||
REQUIRE(c1.GetObjectsListsToBeEmptyIfJustDeclared() ==
|
||||
std::set<gd::String>({"c1.noPicking1"}));
|
||||
REQUIRE(c1.GetAllObjectsToBeDeclared() ==
|
||||
std::set<gd::String>({"c1.object1", "c1.object2", "c1.noPicking1"}));
|
||||
|
||||
REQUIRE(c2.GetObjectsListsAlreadyDeclared() ==
|
||||
REQUIRE(c2.GetObjectsListsAlreadyDeclaredByParents() ==
|
||||
std::set<gd::String>({"c1.object1", "c1.object2", "c1.noPicking1"}));
|
||||
REQUIRE(c2.GetObjectsListsToBeDeclared() ==
|
||||
std::set<gd::String>({"c2.object1"}));
|
||||
REQUIRE(c2.GetObjectsListsToBeDeclaredWithoutPicking() == std::set<gd::String>());
|
||||
REQUIRE(c2.GetObjectsListsToBeEmptyIfJustDeclared() == std::set<gd::String>());
|
||||
REQUIRE(c2.GetAllObjectsToBeDeclared() ==
|
||||
std::set<gd::String>({"c2.object1"}));
|
||||
|
||||
REQUIRE(c3.GetObjectsListsAlreadyDeclared() ==
|
||||
REQUIRE(c3.GetObjectsListsAlreadyDeclaredByParents() ==
|
||||
std::set<gd::String>({"c1.object1", "c1.object2", "c1.noPicking1"}));
|
||||
REQUIRE(c3.GetObjectsListsToBeDeclared() ==
|
||||
std::set<gd::String>({"c3.object1", "c1.object2"}));
|
||||
REQUIRE(c3.GetObjectsListsToBeDeclaredWithoutPicking() == std::set<gd::String>());
|
||||
REQUIRE(c3.GetObjectsListsToBeEmptyIfJustDeclared() == std::set<gd::String>());
|
||||
REQUIRE(c3.GetAllObjectsToBeDeclared() ==
|
||||
std::set<gd::String>({"c3.object1", "c1.object2"}));
|
||||
|
||||
REQUIRE(c5.GetObjectsListsAlreadyDeclared() ==
|
||||
REQUIRE(c5.GetObjectsListsAlreadyDeclaredByParents() ==
|
||||
std::set<gd::String>(
|
||||
{"c1.object1", "c1.object2", "c1.noPicking1", "c2.object1"}));
|
||||
REQUIRE(c5.GetObjectsListsToBeDeclared() ==
|
||||
std::set<gd::String>({"c5.object1", "c1.object2"}));
|
||||
REQUIRE(c5.GetObjectsListsToBeDeclaredWithoutPicking() ==
|
||||
REQUIRE(c5.GetObjectsListsToBeEmptyIfJustDeclared() ==
|
||||
std::set<gd::String>({"c5.noPicking1"}));
|
||||
REQUIRE(c5.GetObjectsListsToBeDeclaredEmpty() ==
|
||||
std::set<gd::String>({"c5.empty1"}));
|
||||
@@ -107,22 +107,18 @@ TEST_CASE("EventsCodeGenerationContext", "[common][events]") {
|
||||
std::set<gd::String>({"c5.object1", "c5.noPicking1", "c1.object2", "c5.empty1"}));
|
||||
}
|
||||
|
||||
SECTION("ObjectAlreadyDeclared") {
|
||||
REQUIRE(c1.ObjectAlreadyDeclared("c1.object1") == false);
|
||||
REQUIRE(c2.ObjectAlreadyDeclared("c1.object1") == true);
|
||||
REQUIRE(c3.ObjectAlreadyDeclared("c1.object1") == true);
|
||||
REQUIRE(c4.ObjectAlreadyDeclared("c1.object1") == true);
|
||||
REQUIRE(c5.ObjectAlreadyDeclared("c1.object1") == true);
|
||||
SECTION("ObjectAlreadyDeclaredByParents") {
|
||||
REQUIRE(c1.ObjectAlreadyDeclaredByParents("c1.object1") == false);
|
||||
REQUIRE(c2.ObjectAlreadyDeclaredByParents("c1.object1") == true);
|
||||
REQUIRE(c3.ObjectAlreadyDeclaredByParents("c1.object1") == true);
|
||||
REQUIRE(c4.ObjectAlreadyDeclaredByParents("c1.object1") == true);
|
||||
REQUIRE(c5.ObjectAlreadyDeclaredByParents("c1.object1") == true);
|
||||
|
||||
REQUIRE(c2.ObjectAlreadyDeclared("c2.object1") == false);
|
||||
REQUIRE(c1.ObjectAlreadyDeclared("c2.object1") == false);
|
||||
REQUIRE(c3.ObjectAlreadyDeclared("c2.object1") == false);
|
||||
REQUIRE(c4.ObjectAlreadyDeclared("c2.object1") == true);
|
||||
REQUIRE(c5.ObjectAlreadyDeclared("c2.object1") == true);
|
||||
|
||||
REQUIRE(c3.ObjectAlreadyDeclared("some object") == false);
|
||||
c3.SetObjectDeclared("some object");
|
||||
REQUIRE(c3.ObjectAlreadyDeclared("some object") == true);
|
||||
REQUIRE(c1.ObjectAlreadyDeclaredByParents("c2.object1") == false);
|
||||
REQUIRE(c2.ObjectAlreadyDeclaredByParents("c2.object1") == false);
|
||||
REQUIRE(c3.ObjectAlreadyDeclaredByParents("c2.object1") == false);
|
||||
REQUIRE(c4.ObjectAlreadyDeclaredByParents("c2.object1") == true);
|
||||
REQUIRE(c5.ObjectAlreadyDeclaredByParents("c2.object1") == true);
|
||||
}
|
||||
|
||||
SECTION("Object list last depth") {
|
||||
@@ -186,4 +182,87 @@ TEST_CASE("EventsCodeGenerationContext", "[common][events]") {
|
||||
REQUIRE(c7.IsSameObjectsList("c6.object3", c6) == false);
|
||||
REQUIRE(c7.IsSameObjectsList("c5.empty1", c5) == false);
|
||||
}
|
||||
|
||||
SECTION("Async") {
|
||||
gd::EventsCodeGenerationContext c1;
|
||||
c1.ObjectsListNeeded("c1.object1");
|
||||
c1.ObjectsListNeeded("c1.object2");
|
||||
c1.ObjectsListNeededOrEmptyIfJustDeclared("c1.possiblyEmpty1");
|
||||
c1.EmptyObjectsListNeeded("c1.empty1");
|
||||
|
||||
gd::EventsCodeGenerationContext c2;
|
||||
c2.InheritsAsAsyncCallbackFrom(c1);
|
||||
c2.ObjectsListNeeded("c2.object1");
|
||||
c2.ObjectsListNeededOrEmptyIfJustDeclared("c2.possiblyEmpty1");
|
||||
c2.EmptyObjectsListNeeded("c2.empty1");
|
||||
c2.ObjectsListNeeded("c1.object1");
|
||||
|
||||
gd::EventsCodeGenerationContext c3;
|
||||
c3.InheritsAsAsyncCallbackFrom(c2);
|
||||
c3.ObjectsListNeeded("c3.object1");
|
||||
c3.ObjectsListNeededOrEmptyIfJustDeclared("c3.possiblyEmpty1");
|
||||
c3.EmptyObjectsListNeeded("c3.empty1");
|
||||
c3.ObjectsListNeeded("c1.object1");
|
||||
|
||||
gd::EventsCodeGenerationContext c4;
|
||||
c4.InheritsFrom(c3);
|
||||
c4.ObjectsListNeeded("c4.object1");
|
||||
c4.ObjectsListNeededOrEmptyIfJustDeclared("c4.possiblyEmpty1");
|
||||
c4.EmptyObjectsListNeeded("c4.empty1");
|
||||
c4.ObjectsListNeeded("c1.object1");
|
||||
c4.ObjectsListNeeded("c1.object2");
|
||||
|
||||
gd::EventsCodeGenerationContext c5;
|
||||
c5.InheritsFrom(c4);
|
||||
c5.ObjectsListNeeded("c5.object1");
|
||||
c5.ObjectsListNeededOrEmptyIfJustDeclared("c5.possiblyEmpty1");
|
||||
c5.EmptyObjectsListNeeded("c5.empty1");
|
||||
c5.ObjectsListNeeded("c1.object1");
|
||||
c5.ObjectsListNeeded("c1.object2");
|
||||
|
||||
REQUIRE(c1.ShouldUseAsyncObjectsList("c1.object1") == false);
|
||||
REQUIRE(c1.ShouldUseAsyncObjectsList("c1.possiblyEmpty1") == false);
|
||||
REQUIRE(c1.ShouldUseAsyncObjectsList("c1.empty1") == false);
|
||||
|
||||
// Objects declared in async callback are used traditionally:
|
||||
REQUIRE(c2.ShouldUseAsyncObjectsList("c2.object1") == false);
|
||||
REQUIRE(c2.ShouldUseAsyncObjectsList("c2.possiblyEmpty1") == false);
|
||||
REQUIRE(c2.ShouldUseAsyncObjectsList("c2.empty1") == false);
|
||||
|
||||
// Objects declared in c1 are gotten from the async list in c2 and c3
|
||||
// because these contexts use them and are async.
|
||||
REQUIRE(c2.ShouldUseAsyncObjectsList("c1.object1") == true);
|
||||
REQUIRE(c3.ShouldUseAsyncObjectsList("c1.object1") == true);
|
||||
REQUIRE(c4.ShouldUseAsyncObjectsList("c1.object1") == false);
|
||||
REQUIRE(c5.ShouldUseAsyncObjectsList("c1.object1") == false);
|
||||
|
||||
// Objects declared in c1 are gotten from the async list in c4
|
||||
// because c3 is async (but is not using them)
|
||||
REQUIRE(c4.ShouldUseAsyncObjectsList("c1.object2") == true);
|
||||
|
||||
// Objects declared in c1 but gotten from the async list in c4
|
||||
// is used traditionnally:
|
||||
REQUIRE(c5.ShouldUseAsyncObjectsList("c1.object2") == false);
|
||||
|
||||
// Objects declared in or after c3 are used traditionally:
|
||||
REQUIRE(c3.ShouldUseAsyncObjectsList("c3.object1") == false);
|
||||
REQUIRE(c4.ShouldUseAsyncObjectsList("c3.object1") == false);
|
||||
REQUIRE(c5.ShouldUseAsyncObjectsList("c3.object1") == false);
|
||||
REQUIRE(c3.ShouldUseAsyncObjectsList("c3.possiblyEmpty1") == false);
|
||||
REQUIRE(c4.ShouldUseAsyncObjectsList("c3.possiblyEmpty1") == false);
|
||||
REQUIRE(c5.ShouldUseAsyncObjectsList("c3.possiblyEmpty1") == false);
|
||||
REQUIRE(c3.ShouldUseAsyncObjectsList("c3.empty1") == false);
|
||||
REQUIRE(c4.ShouldUseAsyncObjectsList("c3.empty1") == false);
|
||||
REQUIRE(c5.ShouldUseAsyncObjectsList("c3.empty1") == false);
|
||||
REQUIRE(c4.ShouldUseAsyncObjectsList("c4.object1") == false);
|
||||
REQUIRE(c4.ShouldUseAsyncObjectsList("c4.possiblyEmpty1") == false);
|
||||
REQUIRE(c4.ShouldUseAsyncObjectsList("c4.empty1") == false);
|
||||
REQUIRE(c5.ShouldUseAsyncObjectsList("c4.object1") == false);
|
||||
REQUIRE(c5.ShouldUseAsyncObjectsList("c4.possiblyEmpty1") == false);
|
||||
REQUIRE(c5.ShouldUseAsyncObjectsList("c4.empty1") == false);
|
||||
REQUIRE(c5.ShouldUseAsyncObjectsList("c5.object1") == false);
|
||||
REQUIRE(c5.ShouldUseAsyncObjectsList("c5.possiblyEmpty1") == false);
|
||||
REQUIRE(c5.ShouldUseAsyncObjectsList("c5.empty1") == false);
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
/**
|
||||
* @file Tests covering FileStream class of GDevelop Core.
|
||||
*/
|
||||
#include "GDCore/Tools/FileStream.h"
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "catch.hpp"
|
||||
|
||||
TEST_CASE("FileStream", "[common][fstream]") {
|
||||
// Creating the test file
|
||||
std::ofstream testFile("FileStreamTest.test");
|
||||
REQUIRE(testFile.is_open());
|
||||
|
||||
testFile << "this is the first line of the test file!\n";
|
||||
testFile << "the last line!";
|
||||
testFile.close();
|
||||
|
||||
SECTION("Input file") {
|
||||
gd::FileStream f;
|
||||
f.open("FileStreamTest.test", std::ios_base::in);
|
||||
|
||||
REQUIRE(f.is_open() == true);
|
||||
REQUIRE(f.tellg() == 0);
|
||||
|
||||
std::string lineContent;
|
||||
REQUIRE(f.eof() == false);
|
||||
std::getline(f, lineContent);
|
||||
REQUIRE(lineContent == "this is the first line of the test file!");
|
||||
|
||||
REQUIRE(f.eof() == false);
|
||||
std::getline(f, lineContent);
|
||||
REQUIRE(lineContent == "the last line!");
|
||||
|
||||
REQUIRE(f.eof() == true);
|
||||
REQUIRE(f.fail() == false);
|
||||
|
||||
f.close();
|
||||
REQUIRE(f.is_open() == false);
|
||||
REQUIRE(f.fail() == false);
|
||||
}
|
||||
|
||||
SECTION("Output/Input file with special characters in filepath") {
|
||||
gd::FileStream output("\xEA\x88\xA1.txt", std::ios_base::out);
|
||||
REQUIRE(output.is_open() == true);
|
||||
|
||||
output << "TEST";
|
||||
output.close();
|
||||
|
||||
gd::FileStream input("\xEA\x88\xA1.txt", std::ios_base::in);
|
||||
REQUIRE(input.is_open() == true);
|
||||
|
||||
std::string lineContent;
|
||||
REQUIRE(input.eof() == false);
|
||||
std::getline(input, lineContent);
|
||||
REQUIRE(lineContent == "TEST");
|
||||
|
||||
REQUIRE(input.eof() == true);
|
||||
|
||||
input.close();
|
||||
REQUIRE(input.is_open() == false);
|
||||
REQUIRE(input.fail() == false);
|
||||
}
|
||||
|
||||
SECTION("File opening failure") {
|
||||
gd::FileStream f("\xE4\x84\xA2",
|
||||
std::ios_base::in); // A file that doesn't exist
|
||||
|
||||
REQUIRE(f.is_open() == false);
|
||||
REQUIRE(f.fail() ==
|
||||
true); // As the opening failed, the "fail" flag should be set
|
||||
|
||||
f.close();
|
||||
REQUIRE(f.bad() == true); // As no files are opened, this should set the
|
||||
// "bad" flag of the stream
|
||||
}
|
||||
|
||||
SECTION("std::ios_base::ate") { // As ate is "emulated", needs testing
|
||||
gd::FileStream f;
|
||||
f.open("FileStreamTest.test", std::ios_base::in | std::ios_base::ate);
|
||||
|
||||
REQUIRE(f.is_open() == true);
|
||||
REQUIRE(f.tellg() > 0);
|
||||
}
|
||||
}
|
@@ -7,7 +7,6 @@
|
||||
* @file Tests covering utf8 features from GDevelop Core.
|
||||
*/
|
||||
|
||||
#include <SFML/System/String.hpp>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
@@ -19,10 +18,8 @@ TEST_CASE("Utf8 String", "[common][utf8]") {
|
||||
SECTION("ctor & conversions") {
|
||||
gd::String str = u8"UTF8 a été testé !";
|
||||
|
||||
sf::String sfStr = str;
|
||||
std::u32string u32str = str.ToUTF32();
|
||||
|
||||
REQUIRE(str == gd::String::FromSfString(sfStr));
|
||||
REQUIRE(str == gd::String::FromUTF32(u32str));
|
||||
}
|
||||
|
||||
@@ -42,8 +39,10 @@ TEST_CASE("Utf8 String", "[common][utf8]") {
|
||||
|
||||
REQUIRE(str.substr(5, 7) == u8"a été t");
|
||||
REQUIRE(str.substr(5, gd::String::npos) == u8"a été testé !");
|
||||
|
||||
REQUIRE_THROWS_AS(str.substr(50, 5), std::out_of_range);
|
||||
// Windows doesn't seems to like exceptions.
|
||||
#if !defined(WINDOWS)
|
||||
REQUIRE_THROWS_AS(str.substr(50, 5), std::out_of_range);
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("insert") {
|
||||
@@ -51,7 +50,9 @@ TEST_CASE("Utf8 String", "[common][utf8]") {
|
||||
str.insert(25, u8"vraiment ");
|
||||
|
||||
REQUIRE(str == u8"Une fonctionnalité a été vraiment testée !");
|
||||
REQUIRE_THROWS_AS(str.insert(150, u8"This gonna fail"), std::out_of_range);
|
||||
#if !defined(WINDOWS)
|
||||
REQUIRE_THROWS_AS(str.insert(150, u8"This gonna fail"), std::out_of_range);
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("replace") {
|
||||
@@ -62,8 +63,10 @@ TEST_CASE("Utf8 String", "[common][utf8]") {
|
||||
REQUIRE(str.replace(11, gd::String::npos, u8"vraiment très testé !") ==
|
||||
u8"UTF8 a été vraiment très testé !");
|
||||
|
||||
REQUIRE_THROWS_AS(str.replace(50, 5, u8"Cela va planter."),
|
||||
std::out_of_range);
|
||||
#if !defined(WINDOWS)
|
||||
REQUIRE_THROWS_AS(str.replace(50, 5, u8"Cela va planter."),
|
||||
std::out_of_range);
|
||||
#endif
|
||||
|
||||
// Testing the iterator version of replace
|
||||
gd::String str2 = u8"UTF8 a été testé !";
|
||||
@@ -94,8 +97,10 @@ TEST_CASE("Utf8 String", "[common][utf8]") {
|
||||
REQUIRE(str == "UTF8");
|
||||
}
|
||||
{
|
||||
gd::String str = u8"UTF8 a été testé !";
|
||||
REQUIRE_THROWS_AS(str.erase(100, 5), std::out_of_range);
|
||||
#if !defined(WINDOWS)
|
||||
gd::String str = u8"UTF8 a été testé !";
|
||||
REQUIRE_THROWS_AS(str.erase(100, 5), std::out_of_range);
|
||||
#endif
|
||||
}
|
||||
{
|
||||
gd::String str = u8"UTF8 a été testé !";
|
||||
|
@@ -1,54 +0,0 @@
|
||||
# Clone SFML from its official directory using Git. Only
|
||||
# do it if not already cloned to avoid triggering a whole
|
||||
# recompilation every time CMake is run.
|
||||
find_package(Git)
|
||||
if(GIT_FOUND)
|
||||
if (NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/SFML/readme.txt")
|
||||
message( "Cloning SFML in ExtLibs/SFML with Git..." )
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} clone "https://www.github.com/SFML/SFML.git" SFML
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/
|
||||
OUTPUT_QUIET)
|
||||
|
||||
message( "Resetting SFML source code to version 2.4.1..." )
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} reset --hard 2.4.1
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/SFML
|
||||
OUTPUT_QUIET)
|
||||
|
||||
message( "Applying the patches..." )
|
||||
file(GLOB SFML_PATCHES
|
||||
LIST_DIRECTORIES FALSE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/SFML-patches/*.patch)
|
||||
|
||||
if(SFML_PATCHES)
|
||||
list(SORT SFML_PATCHES)
|
||||
|
||||
foreach(SFML_PATCH ${SFML_PATCHES})
|
||||
message( "Applying patch: ${SFML_PATCH}..." )
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} apply ${SFML_PATCH} --ignore-whitespace
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/SFML
|
||||
OUTPUT_QUIET)
|
||||
endforeach()
|
||||
endif()
|
||||
else()
|
||||
message( "SFML already downloaded." )
|
||||
endif()
|
||||
else()
|
||||
message( "Git not found, make sure you have SFML >= 2.4 in ExtLibs/SFML and you applied the needed patches (from ExtLibs/SFML-patches)!" )
|
||||
endif()
|
||||
|
||||
#SFML:
|
||||
IF(NOT EMSCRIPTEN) #Don't build SFML binaries when compiling with emscripten (but keep include files!)
|
||||
add_subdirectory(SFML)
|
||||
set(sfml_lib_dir ${CMAKE_BINARY_DIR}/ExtLibs/SFML/lib PARENT_SCOPE)
|
||||
set(sfml_LIBRARIES sfml-audio sfml-graphics sfml-window sfml-network sfml-system)
|
||||
IF(WIN32)
|
||||
set(sfml_LIBRARIES "${sfml_LIBRARIES}" ws2_32 user32 opengl32 glu32 psapi)
|
||||
ELSEIF(NOT APPLE)
|
||||
set(sfml_LIBRARIES "${sfml_LIBRARIES}" GLU GL)
|
||||
ENDIF()
|
||||
set(sfml_LIBRARIES "${sfml_LIBRARIES}" PARENT_SCOPE)
|
||||
ENDIF()
|
||||
set(sfml_include_dir ${CMAKE_CURRENT_SOURCE_DIR}/SFML/include PARENT_SCOPE)
|
||||
|
@@ -1,19 +0,0 @@
|
||||
diff --git a/extlibs/headers/stb_image/stb_image.h b/extlibs/headers/stb_image/stb_image.h
|
||||
index c3945c2..5fe1050 100644
|
||||
--- a/extlibs/headers/stb_image/stb_image.h
|
||||
+++ b/extlibs/headers/stb_image/stb_image.h
|
||||
@@ -671,14 +671,9 @@ static int stbi__sse2_available()
|
||||
|
||||
static int stbi__sse2_available()
|
||||
{
|
||||
-#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 // GCC 4.8 or later
|
||||
- // GCC 4.8+ has a nice way to do this
|
||||
- return __builtin_cpu_supports("sse2");
|
||||
-#else
|
||||
// portable way to do this, preferably without using GCC inline ASM?
|
||||
// just bail for now.
|
||||
return 0;
|
||||
-#endif
|
||||
}
|
||||
#endif
|
||||
#endif
|
@@ -1,29 +0,0 @@
|
||||
From f55ee73a73398bb77ce9c63ff1a13d8053cb1d18 Mon Sep 17 00:00:00 2001
|
||||
From: Florian Rival <Florian.Rival@gmail.com>
|
||||
Date: Tue, 3 Jan 2017 21:15:11 +0100
|
||||
Subject: [PATCH] Fix crash with SFML embeded in wxWidgets on OS X
|
||||
|
||||
---
|
||||
src/SFML/Window/OSX/SFViewController.mm | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/src/SFML/Window/OSX/SFViewController.mm b/src/SFML/Window/OSX/SFViewController.mm
|
||||
index 7d736e3..280ec2b 100644
|
||||
--- a/src/SFML/Window/OSX/SFViewController.mm
|
||||
+++ b/src/SFML/Window/OSX/SFViewController.mm
|
||||
@@ -82,8 +82,12 @@ -(id)initWithView:(NSView *)view
|
||||
////////////////////////////////////////////////////////
|
||||
-(void)dealloc
|
||||
{
|
||||
+ NSLog(@"SFViewController::dealloc called on %@", self);
|
||||
[self closeWindow];
|
||||
|
||||
+
|
||||
+ // See https://github.com/SFML/SFML/issues/824
|
||||
+ [[NSNotificationCenter defaultCenter] removeObserver:m_oglView];
|
||||
[m_view release];
|
||||
[m_oglView release];
|
||||
|
||||
--
|
||||
2.7.4 (Apple Git-66)
|
||||
|
@@ -1,13 +0,0 @@
|
||||
diff --git a/include/SFML/Config.hpp b/include/SFML/Config.hpp
|
||||
index 9c68d84..2522d88 100644
|
||||
--- a/include/SFML/Config.hpp
|
||||
+++ b/include/SFML/Config.hpp
|
||||
@@ -76,7 +76,7 @@
|
||||
// Android
|
||||
#define SFML_SYSTEM_ANDROID
|
||||
|
||||
- #elif defined(__linux__)
|
||||
+ #elif defined(__linux__) || defined(EMSCRIPTEN)
|
||||
|
||||
// Linux
|
||||
#define SFML_SYSTEM_LINUX
|
@@ -45,6 +45,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('yesorno', _('Focus the window?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -61,6 +62,7 @@ module.exports = {
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -79,6 +81,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('yesorno', _('Show window?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -95,6 +98,7 @@ module.exports = {
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -113,6 +117,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('yesorno', _('Maximize window?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -129,6 +134,7 @@ module.exports = {
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -147,6 +153,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('yesorno', _('Minimize window?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -163,6 +170,7 @@ module.exports = {
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -181,6 +189,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('yesorno', _('Enable window?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -197,6 +206,7 @@ module.exports = {
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -215,6 +225,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('yesorno', _('Allow resizing?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -231,6 +242,7 @@ module.exports = {
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -249,6 +261,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('yesorno', _('Allow moving?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -265,6 +278,7 @@ module.exports = {
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -283,6 +297,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('yesorno', _('Allow maximizing?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -299,6 +314,7 @@ module.exports = {
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -317,6 +333,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('yesorno', _('Allow minimizing?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -333,6 +350,7 @@ module.exports = {
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -351,6 +369,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('yesorno', _('Allow full-screening?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -367,6 +386,7 @@ module.exports = {
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -385,6 +405,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('yesorno', _('Allow closing?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -401,6 +422,7 @@ module.exports = {
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -442,6 +464,7 @@ module.exports = {
|
||||
'above the taskbar on Windows. ' +
|
||||
'This parameter is ignored on linux.'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -458,6 +481,7 @@ module.exports = {
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -478,6 +502,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('yesorno', _('Enable kiosk mode?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -494,6 +519,7 @@ module.exports = {
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -512,6 +538,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('yesorno', _('Enable shadow?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -528,6 +555,7 @@ module.exports = {
|
||||
'res/actions/window24.png',
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -548,6 +576,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('yesorno', _('Enable content protection?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -566,6 +595,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('yesorno', _('Allow focus?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -584,6 +614,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('yesorno', _('Flash the window?'), '', false)
|
||||
.setDefaultValue('true')
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -604,6 +635,7 @@ module.exports = {
|
||||
.setParameterLongDescription(
|
||||
'A number between 0 (fully transparent) and 1 (fully opaque).'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -622,6 +654,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('expression', _('X position'), '', false)
|
||||
.addParameter('expression', _('Y position'), '', false)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -636,6 +669,7 @@ module.exports = {
|
||||
_('Windows, Linux, macOS'),
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -650,6 +684,7 @@ module.exports = {
|
||||
_('Windows, Linux, macOS'),
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
@@ -666,6 +701,7 @@ module.exports = {
|
||||
_('Windows, Linux, macOS'),
|
||||
'res/actions/window.png'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile(
|
||||
'Extensions/AdvancedWindow/electron-advancedwindowtools.js'
|
||||
|
@@ -6,16 +6,23 @@ namespace gdjs {
|
||||
*/
|
||||
export namespace evtTools {
|
||||
export namespace advancedWindow {
|
||||
/**
|
||||
* The game's BrowserWindow instance (or null on
|
||||
* non-electron platforms).
|
||||
*/
|
||||
let electronBrowserWindow: any = null;
|
||||
const getElectronBrowserWindow = (runtimeScene: gdjs.RuntimeScene) => {
|
||||
const electronRemote = runtimeScene
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getElectronRemote();
|
||||
if (electronRemote) {
|
||||
return electronRemote.getCurrentWindow();
|
||||
}
|
||||
|
||||
if (typeof require === 'function') {
|
||||
electronBrowserWindow = require('electron').remote.getCurrentWindow();
|
||||
}
|
||||
export const focus = function (activate: boolean) {
|
||||
return null;
|
||||
};
|
||||
|
||||
export const focus = function (
|
||||
activate: boolean,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
if (activate) {
|
||||
electronBrowserWindow.focus();
|
||||
@@ -25,14 +32,21 @@ namespace gdjs {
|
||||
}
|
||||
};
|
||||
|
||||
export const isFocused = function (): boolean {
|
||||
export const isFocused = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): boolean {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
return electronBrowserWindow.isFocused();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const show = function (activate: boolean) {
|
||||
export const show = function (
|
||||
activate: boolean,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
if (activate) {
|
||||
electronBrowserWindow.showInactive();
|
||||
@@ -42,14 +56,21 @@ namespace gdjs {
|
||||
}
|
||||
};
|
||||
|
||||
export const isVisible = function (): boolean {
|
||||
export const isVisible = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): boolean {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
return electronBrowserWindow.isVisible();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const maximize = function (activate: boolean) {
|
||||
export const maximize = function (
|
||||
activate: boolean,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
if (activate) {
|
||||
electronBrowserWindow.maximize();
|
||||
@@ -59,14 +80,21 @@ namespace gdjs {
|
||||
}
|
||||
};
|
||||
|
||||
export const isMaximized = function (): boolean {
|
||||
export const isMaximized = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): boolean {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
return electronBrowserWindow.isMaximized();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const minimize = function (activate: boolean) {
|
||||
export const minimize = function (
|
||||
activate: boolean,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
if (activate) {
|
||||
electronBrowserWindow.minimize();
|
||||
@@ -76,98 +104,150 @@ namespace gdjs {
|
||||
}
|
||||
};
|
||||
|
||||
export const isMinimized = function (): boolean {
|
||||
export const isMinimized = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): boolean {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
return electronBrowserWindow.isMinimized();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const enable = function (activate: boolean) {
|
||||
export const enable = function (
|
||||
activate: boolean,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
electronBrowserWindow.setEnabled(activate);
|
||||
}
|
||||
};
|
||||
|
||||
export const isEnabled = function (): boolean {
|
||||
export const isEnabled = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): boolean {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
return electronBrowserWindow.isEnabled();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const setResizable = function (activate: boolean) {
|
||||
export const setResizable = function (
|
||||
activate: boolean,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
electronBrowserWindow.setResizable(activate);
|
||||
}
|
||||
};
|
||||
|
||||
export const isResizable = function (): boolean {
|
||||
export const isResizable = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): boolean {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
return electronBrowserWindow.isResizable();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const setMovable = function (activate: boolean) {
|
||||
export const setMovable = function (
|
||||
activate: boolean,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
electronBrowserWindow.setMovable(activate);
|
||||
}
|
||||
};
|
||||
|
||||
export const isMovable = function (): boolean {
|
||||
export const isMovable = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): boolean {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
return electronBrowserWindow.isMovable();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const setMaximizable = function (activate: boolean) {
|
||||
export const setMaximizable = function (
|
||||
activate: boolean,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
electronBrowserWindow.setMaximizable(activate);
|
||||
}
|
||||
};
|
||||
|
||||
export const isMaximizable = function (): boolean {
|
||||
export const isMaximizable = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): boolean {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
return electronBrowserWindow.isMaximizable();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const setMinimizable = function (activate: boolean) {
|
||||
export const setMinimizable = function (
|
||||
activate: boolean,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
electronBrowserWindow.setMinimizable(activate);
|
||||
}
|
||||
};
|
||||
|
||||
export const isMinimizable = function (): boolean {
|
||||
export const isMinimizable = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): boolean {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
return electronBrowserWindow.isMinimizable();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const setFullScreenable = function (activate: boolean) {
|
||||
export const setFullScreenable = function (
|
||||
activate: boolean,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
electronBrowserWindow.setFullScreenable(activate);
|
||||
}
|
||||
};
|
||||
|
||||
export const isFullScreenable = function (): boolean {
|
||||
export const isFullScreenable = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): boolean {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
return electronBrowserWindow.isFullScreenable();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const setClosable = function (activate: boolean) {
|
||||
export const setClosable = function (
|
||||
activate: boolean,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
electronBrowserWindow.setClosable(activate);
|
||||
}
|
||||
};
|
||||
|
||||
export const isClosable = function (): boolean {
|
||||
export const isClosable = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): boolean {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
return electronBrowserWindow.isClosable();
|
||||
}
|
||||
@@ -184,93 +264,142 @@ namespace gdjs {
|
||||
| 'main-menu'
|
||||
| 'status'
|
||||
| 'pop-up-menu'
|
||||
| 'screen-saver'
|
||||
| 'screen-saver',
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
electronBrowserWindow.setAlwaysOnTop(activate, level);
|
||||
}
|
||||
};
|
||||
|
||||
export const isAlwaysOnTop = function (): boolean {
|
||||
export const isAlwaysOnTop = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): boolean {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
return electronBrowserWindow.isAlwaysOnTop();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const setPosition = function (x: float, y: float) {
|
||||
export const setPosition = function (
|
||||
x: float,
|
||||
y: float,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
// Convert x and y to (32 bit) integers to avoid Electron errors.
|
||||
electronBrowserWindow.setPosition(~~x, ~~y);
|
||||
}
|
||||
};
|
||||
|
||||
export const getPositionX = function (): number {
|
||||
export const getPositionX = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): number {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
return electronBrowserWindow.getPosition()[0];
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
export const getPositionY = function (): number {
|
||||
export const getPositionY = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): number {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
return electronBrowserWindow.getPosition()[1];
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
export const setKiosk = function (activate: boolean) {
|
||||
export const setKiosk = function (
|
||||
activate: boolean,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
electronBrowserWindow.setKiosk(activate);
|
||||
}
|
||||
};
|
||||
|
||||
export const isKiosk = function (): boolean {
|
||||
export const isKiosk = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): boolean {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
return electronBrowserWindow.isKiosk();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const flash = function (activate: boolean) {
|
||||
export const flash = function (
|
||||
activate: boolean,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
electronBrowserWindow.flashFrame(activate);
|
||||
}
|
||||
};
|
||||
|
||||
export const setHasShadow = function (activate: boolean) {
|
||||
export const setHasShadow = function (
|
||||
activate: boolean,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
electronBrowserWindow.setHasShadow(activate);
|
||||
}
|
||||
};
|
||||
|
||||
export const hasShadow = function (): boolean {
|
||||
export const hasShadow = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): boolean {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
return electronBrowserWindow.hasShadow();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const setOpacity = function (opacity: float) {
|
||||
export const setOpacity = function (
|
||||
opacity: float,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
electronBrowserWindow.setOpacity(opacity);
|
||||
}
|
||||
};
|
||||
|
||||
export const getOpacity = function (): number {
|
||||
export const getOpacity = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): number {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
return electronBrowserWindow.getOpacity();
|
||||
}
|
||||
return 1;
|
||||
};
|
||||
|
||||
export const setContentProtection = function (activate: boolean) {
|
||||
export const setContentProtection = function (
|
||||
activate: boolean,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
electronBrowserWindow.setContentProtection(activate);
|
||||
}
|
||||
};
|
||||
|
||||
export const setFocusable = function (activate: boolean) {
|
||||
export const setFocusable = function (
|
||||
activate: boolean,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
const electronBrowserWindow = getElectronBrowserWindow(runtimeScene);
|
||||
if (electronBrowserWindow) {
|
||||
electronBrowserWindow.setFocusable(activate);
|
||||
}
|
||||
|
@@ -5,7 +5,9 @@ Copyright (c) 2016 Victor Levasseur (victorlevasseur52@gmail.com)
|
||||
This project is released under the MIT License.
|
||||
*/
|
||||
#include "AnchorBehavior.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
@@ -20,6 +22,7 @@ void AnchorBehavior::InitializeContent(gd::SerializerElement& content) {
|
||||
content.SetAttribute("topEdgeAnchor", static_cast<int>(ANCHOR_VERTICAL_NONE));
|
||||
content.SetAttribute("bottomEdgeAnchor",
|
||||
static_cast<int>(ANCHOR_VERTICAL_NONE));
|
||||
content.SetAttribute("useLegacyBottomAndRightAnchors", false);
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
@@ -68,7 +71,7 @@ std::map<gd::String, gd::PropertyDescriptor> AnchorBehavior::GetProperties(
|
||||
.AddExtraInfo(_("Window left"))
|
||||
.AddExtraInfo(_("Window right"))
|
||||
.AddExtraInfo(_("Proportional"))
|
||||
.SetDescription(_("Use this to anchor the object on X axis."));
|
||||
.SetDescription(_("Anchor the left edge of the object on X axis."));
|
||||
|
||||
properties[_("Right edge anchor")]
|
||||
.SetValue(GetAnchorAsString(static_cast<HorizontalAnchor>(
|
||||
@@ -77,7 +80,8 @@ std::map<gd::String, gd::PropertyDescriptor> AnchorBehavior::GetProperties(
|
||||
.AddExtraInfo(_("No anchor"))
|
||||
.AddExtraInfo(_("Window left"))
|
||||
.AddExtraInfo(_("Window right"))
|
||||
.AddExtraInfo(_("Proportional"));
|
||||
.AddExtraInfo(_("Proportional"))
|
||||
.SetDescription(_("Anchor the right edge of the object on X axis."));
|
||||
|
||||
properties[_("Top edge anchor")]
|
||||
.SetValue(GetAnchorAsString(static_cast<VerticalAnchor>(
|
||||
@@ -87,7 +91,7 @@ std::map<gd::String, gd::PropertyDescriptor> AnchorBehavior::GetProperties(
|
||||
.AddExtraInfo(_("Window top"))
|
||||
.AddExtraInfo(_("Window bottom"))
|
||||
.AddExtraInfo(_("Proportional"))
|
||||
.SetDescription(_("Use this to anchor the object on Y axis."));
|
||||
.SetDescription(_("Anchor the top edge of the object on Y axis."));
|
||||
|
||||
properties[_("Bottom edge anchor")]
|
||||
.SetValue(GetAnchorAsString(static_cast<VerticalAnchor>(
|
||||
@@ -96,7 +100,20 @@ std::map<gd::String, gd::PropertyDescriptor> AnchorBehavior::GetProperties(
|
||||
.AddExtraInfo(_("No anchor"))
|
||||
.AddExtraInfo(_("Window top"))
|
||||
.AddExtraInfo(_("Window bottom"))
|
||||
.AddExtraInfo(_("Proportional"));
|
||||
.AddExtraInfo(_("Proportional"))
|
||||
.SetDescription(_("Anchor the bottom edge of the object on Y axis."));
|
||||
|
||||
properties[("useLegacyBottomAndRightAnchors")]
|
||||
.SetLabel(_(
|
||||
"Stretch object when anchoring right or bottom ledge (deprecated, "
|
||||
"it's recommended to let this unchecked and anchor both sides if you "
|
||||
"want Sprite to stretch instead.)"))
|
||||
.SetGroup(_("Deprecated options (advanced)"))
|
||||
.SetValue(behaviorContent.GetBoolAttribute(
|
||||
"useLegacyBottomAndRightAnchors", true)
|
||||
? "true"
|
||||
: "false")
|
||||
.SetType("Boolean");
|
||||
|
||||
return properties;
|
||||
}
|
||||
@@ -147,6 +164,9 @@ bool AnchorBehavior::UpdateProperty(gd::SerializerElement& behaviorContent,
|
||||
behaviorContent.SetAttribute(
|
||||
"bottomEdgeAnchor",
|
||||
static_cast<int>(GetVerticalAnchorFromString(value)));
|
||||
else if (name == "useLegacyBottomAndRightAnchors")
|
||||
behaviorContent.SetAttribute("useLegacyBottomAndRightAnchors",
|
||||
(value == "1"));
|
||||
else
|
||||
return false;
|
||||
|
||||
|
@@ -15,6 +15,7 @@ namespace gdjs {
|
||||
_rightEdgeDistance: number = 0;
|
||||
_topEdgeDistance: number = 0;
|
||||
_bottomEdgeDistance: number = 0;
|
||||
_useLegacyBottomAndRightAnchors: boolean = false;
|
||||
|
||||
constructor(runtimeScene, behaviorData, owner) {
|
||||
super(runtimeScene, behaviorData, owner);
|
||||
@@ -23,6 +24,10 @@ namespace gdjs {
|
||||
this._rightEdgeAnchor = behaviorData.rightEdgeAnchor;
|
||||
this._topEdgeAnchor = behaviorData.topEdgeAnchor;
|
||||
this._bottomEdgeAnchor = behaviorData.bottomEdgeAnchor;
|
||||
this._useLegacyBottomAndRightAnchors =
|
||||
behaviorData.useLegacyBottomAndRightAnchors === undefined
|
||||
? true
|
||||
: behaviorData.useLegacyBottomAndRightAnchors;
|
||||
}
|
||||
|
||||
updateFromBehaviorData(oldBehaviorData, newBehaviorData): boolean {
|
||||
@@ -40,6 +45,13 @@ namespace gdjs {
|
||||
) {
|
||||
this._bottomEdgeAnchor = newBehaviorData.bottomEdgeAnchor;
|
||||
}
|
||||
if (
|
||||
oldBehaviorData.useLegacyTrajectory !==
|
||||
newBehaviorData.useLegacyTrajectory
|
||||
) {
|
||||
this._useLegacyBottomAndRightAnchors =
|
||||
newBehaviorData.useLegacyBottomAndRightAnchors;
|
||||
}
|
||||
if (
|
||||
oldBehaviorData.relativeToOriginalWindowSize !==
|
||||
newBehaviorData.relativeToOriginalWindowSize
|
||||
@@ -262,28 +274,94 @@ namespace gdjs {
|
||||
bottomPixel
|
||||
);
|
||||
|
||||
//Move and resize the object according to the anchors
|
||||
if (
|
||||
this._rightEdgeAnchor !== AnchorRuntimeBehavior.HorizontalAnchor.NONE
|
||||
) {
|
||||
this.owner.setWidth(bottomRightCoord[0] - topLeftCoord[0]);
|
||||
// Compatibility with GD <= 5.0.133
|
||||
if (this._useLegacyBottomAndRightAnchors) {
|
||||
//Move and resize the object according to the anchors
|
||||
if (
|
||||
this._rightEdgeAnchor !==
|
||||
AnchorRuntimeBehavior.HorizontalAnchor.NONE
|
||||
) {
|
||||
this.owner.setWidth(bottomRightCoord[0] - topLeftCoord[0]);
|
||||
}
|
||||
if (
|
||||
this._bottomEdgeAnchor !== AnchorRuntimeBehavior.VerticalAnchor.NONE
|
||||
) {
|
||||
this.owner.setHeight(bottomRightCoord[1] - topLeftCoord[1]);
|
||||
}
|
||||
if (
|
||||
this._leftEdgeAnchor !== AnchorRuntimeBehavior.HorizontalAnchor.NONE
|
||||
) {
|
||||
this.owner.setX(
|
||||
topLeftCoord[0] + this.owner.getX() - this.owner.getDrawableX()
|
||||
);
|
||||
}
|
||||
if (
|
||||
this._topEdgeAnchor !== AnchorRuntimeBehavior.VerticalAnchor.NONE
|
||||
) {
|
||||
this.owner.setY(
|
||||
topLeftCoord[1] + this.owner.getY() - this.owner.getDrawableY()
|
||||
);
|
||||
}
|
||||
}
|
||||
if (
|
||||
this._bottomEdgeAnchor !== AnchorRuntimeBehavior.VerticalAnchor.NONE
|
||||
) {
|
||||
this.owner.setHeight(bottomRightCoord[1] - topLeftCoord[1]);
|
||||
}
|
||||
if (
|
||||
this._leftEdgeAnchor !== AnchorRuntimeBehavior.HorizontalAnchor.NONE
|
||||
) {
|
||||
this.owner.setX(
|
||||
topLeftCoord[0] + this.owner.getX() - this.owner.getDrawableX()
|
||||
);
|
||||
}
|
||||
if (this._topEdgeAnchor !== AnchorRuntimeBehavior.VerticalAnchor.NONE) {
|
||||
this.owner.setY(
|
||||
topLeftCoord[1] + this.owner.getY() - this.owner.getDrawableY()
|
||||
);
|
||||
// End of compatibility code
|
||||
else {
|
||||
// Resize if right and left anchors are set
|
||||
if (
|
||||
this._rightEdgeAnchor !==
|
||||
AnchorRuntimeBehavior.HorizontalAnchor.NONE &&
|
||||
this._leftEdgeAnchor !== AnchorRuntimeBehavior.HorizontalAnchor.NONE
|
||||
) {
|
||||
this.owner.setWidth(bottomRightCoord[0] - topLeftCoord[0]);
|
||||
this.owner.setX(topLeftCoord[0]);
|
||||
} else {
|
||||
if (
|
||||
this._leftEdgeAnchor !==
|
||||
AnchorRuntimeBehavior.HorizontalAnchor.NONE
|
||||
) {
|
||||
this.owner.setX(
|
||||
topLeftCoord[0] + this.owner.getX() - this.owner.getDrawableX()
|
||||
);
|
||||
}
|
||||
if (
|
||||
this._rightEdgeAnchor !==
|
||||
AnchorRuntimeBehavior.HorizontalAnchor.NONE
|
||||
) {
|
||||
this.owner.setX(
|
||||
bottomRightCoord[0] +
|
||||
this.owner.getX() -
|
||||
this.owner.getDrawableX() -
|
||||
this.owner.getWidth()
|
||||
);
|
||||
}
|
||||
}
|
||||
// Resize if top and bottom anchors are set
|
||||
if (
|
||||
this._bottomEdgeAnchor !==
|
||||
AnchorRuntimeBehavior.VerticalAnchor.NONE &&
|
||||
this._topEdgeAnchor !== AnchorRuntimeBehavior.VerticalAnchor.NONE
|
||||
) {
|
||||
this.owner.setHeight(bottomRightCoord[1] - topLeftCoord[1]);
|
||||
this.owner.setY(topLeftCoord[1]);
|
||||
} else {
|
||||
if (
|
||||
this._topEdgeAnchor !== AnchorRuntimeBehavior.VerticalAnchor.NONE
|
||||
) {
|
||||
this.owner.setY(
|
||||
topLeftCoord[1] + this.owner.getY() - this.owner.getDrawableY()
|
||||
);
|
||||
}
|
||||
if (
|
||||
this._bottomEdgeAnchor !==
|
||||
AnchorRuntimeBehavior.VerticalAnchor.NONE
|
||||
) {
|
||||
this.owner.setY(
|
||||
bottomRightCoord[1] +
|
||||
this.owner.getY() -
|
||||
this.owner.getDrawableY() -
|
||||
this.owner.getHeight()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
204
Extensions/AnchorBehavior/tests/anchorruntimebehavior.spec.js
Normal file
204
Extensions/AnchorBehavior/tests/anchorruntimebehavior.spec.js
Normal file
@@ -0,0 +1,204 @@
|
||||
// @ts-check
|
||||
describe.only('gdjs.AnchorRuntimeBehavior', function () {
|
||||
const runtimeGame = new gdjs.RuntimeGame({
|
||||
variables: [],
|
||||
resources: { resources: [] },
|
||||
// @ts-ignore
|
||||
properties: { windowWidth: 1000, windowHeight: 1000 },
|
||||
});
|
||||
const anchorBehaviorName = 'Anchor';
|
||||
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
runtimeScene.loadFromScene({
|
||||
layers: [
|
||||
{
|
||||
name: '',
|
||||
visibility: true,
|
||||
cameras: [],
|
||||
effects: [],
|
||||
ambientLightColorR: 127,
|
||||
ambientLightColorB: 127,
|
||||
ambientLightColorG: 127,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: false,
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
r: 0,
|
||||
v: 0,
|
||||
b: 0,
|
||||
mangledName: 'Scene1',
|
||||
name: 'Scene1',
|
||||
stopSoundsOnStartup: false,
|
||||
title: '',
|
||||
behaviorsSharedData: [],
|
||||
objects: [],
|
||||
instances: [],
|
||||
});
|
||||
|
||||
function createObject(behaviorProperties) {
|
||||
const object = new gdjs.TestRuntimeObject(runtimeScene, {
|
||||
name: 'obj1',
|
||||
type: '',
|
||||
behaviors: [
|
||||
{
|
||||
name: anchorBehaviorName,
|
||||
type: 'AnchorBehavior::AnchorBehavior',
|
||||
// @ts-ignore - properties are not typed
|
||||
rightEdgeAnchor: 0,
|
||||
leftEdgeAnchor: 0,
|
||||
topEdgeAnchor: 0,
|
||||
bottomEdgeAnchor: 0,
|
||||
relativeToOriginalWindowSize: true,
|
||||
useLegacyBottomAndRightAnchors: false,
|
||||
...behaviorProperties,
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
effects: [],
|
||||
});
|
||||
|
||||
object.setCustomWidthAndHeight(10, 10);
|
||||
runtimeScene.addObject(object);
|
||||
return object;
|
||||
}
|
||||
|
||||
function getAnchorBehavior(object) {
|
||||
const behavior = object.getBehavior(anchorBehaviorName);
|
||||
if (!(behavior instanceof gdjs.AnchorRuntimeBehavior)) {
|
||||
throw new Error(
|
||||
'Expected behavior to be an instance of gdjs.AnchorBehavior'
|
||||
);
|
||||
}
|
||||
return behavior;
|
||||
}
|
||||
|
||||
describe('(anchor horizontal edge)', function () {
|
||||
['rightEdgeAnchor', 'leftEdgeAnchor'].forEach((objectEdge) => {
|
||||
it(`anchors the ${objectEdge} edge of object to window left (fixed)`, function () {
|
||||
const object = createObject({ [objectEdge]: 1 });
|
||||
runtimeGame.setGameResolutionSize(1000, 1000);
|
||||
object.setPosition(500, 500);
|
||||
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
runtimeGame.setGameResolutionSize(2000, 2000);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
expect(object.getX()).to.equal(500);
|
||||
expect(object.getY()).to.equal(500);
|
||||
expect(object.getWidth()).to.equal(10);
|
||||
});
|
||||
});
|
||||
['rightEdgeAnchor', 'leftEdgeAnchor'].forEach((objectEdge) => {
|
||||
it(`anchors the ${objectEdge} edge of object to window right (fixed)`, function () {
|
||||
const object = createObject({ [objectEdge]: 2 });
|
||||
runtimeGame.setGameResolutionSize(1000, 1000);
|
||||
object.setPosition(500, 500);
|
||||
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
runtimeGame.setGameResolutionSize(2000, 2000);
|
||||
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
expect(object.getX()).to.equal(1500);
|
||||
expect(object.getY()).to.equal(500);
|
||||
expect(object.getWidth()).to.equal(10);
|
||||
});
|
||||
});
|
||||
|
||||
it('anchors the right and left edge of object (fixed)', function () {
|
||||
const object = createObject({ leftEdgeAnchor: 1, rightEdgeAnchor: 2 });
|
||||
runtimeGame.setGameResolutionSize(1000, 1000);
|
||||
object.setPosition(500, 500);
|
||||
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
runtimeGame.setGameResolutionSize(2000, 2000);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
expect(object.getX()).to.equal(500);
|
||||
expect(object.getY()).to.equal(500);
|
||||
expect(object.getWidth()).to.equal(1010);
|
||||
});
|
||||
|
||||
it('anchors the left edge of object (proportional)', function () {
|
||||
const object = createObject({ leftEdgeAnchor: 3 });
|
||||
runtimeGame.setGameResolutionSize(1000, 1000);
|
||||
object.setPosition(500, 500);
|
||||
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
runtimeGame.setGameResolutionSize(2000, 2000);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
expect(object.getX()).to.equal(1000);
|
||||
expect(object.getY()).to.equal(500);
|
||||
expect(object.getWidth()).to.equal(10);
|
||||
});
|
||||
});
|
||||
|
||||
describe('(anchor vertical edge)', function () {
|
||||
['topEdgeAnchor', 'bottomEdgeAnchor'].forEach((objectEdge) => {
|
||||
it(`anchors the ${objectEdge} edge of object to window top (fixed)`, function () {
|
||||
const object = createObject({ [objectEdge]: 1 });
|
||||
runtimeGame.setGameResolutionSize(1000, 1000);
|
||||
object.setPosition(500, 500);
|
||||
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
runtimeGame.setGameResolutionSize(2000, 2000);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
expect(object.getX()).to.equal(500);
|
||||
expect(object.getY()).to.equal(500);
|
||||
expect(object.getWidth()).to.equal(10);
|
||||
});
|
||||
});
|
||||
['topEdgeAnchor', 'bottomEdgeAnchor'].forEach((objectEdge) => {
|
||||
it(`anchors the ${objectEdge} edge of object to window bottom (fixed)`, function () {
|
||||
const object = createObject({ [objectEdge]: 2 });
|
||||
runtimeGame.setGameResolutionSize(1000, 1000);
|
||||
object.setPosition(500, 500);
|
||||
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
runtimeGame.setGameResolutionSize(2000, 2000);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
expect(object.getX()).to.equal(500);
|
||||
expect(object.getY()).to.equal(1500);
|
||||
expect(object.getWidth()).to.equal(10);
|
||||
});
|
||||
});
|
||||
|
||||
it('anchors the top and bottom edge of object (fixed)', function () {
|
||||
const object = createObject({ topEdgeAnchor: 1, bottomEdgeAnchor: 2 });
|
||||
runtimeGame.setGameResolutionSize(1000, 1000);
|
||||
object.setPosition(500, 500);
|
||||
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
runtimeGame.setGameResolutionSize(2000, 2000);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
expect(object.getX()).to.equal(500);
|
||||
expect(object.getY()).to.equal(500);
|
||||
expect(object.getHeight()).to.equal(1010);
|
||||
});
|
||||
|
||||
it('anchors the top edge of object (proportional)', function () {
|
||||
const object = createObject({ topEdgeAnchor: 3 });
|
||||
runtimeGame.setGameResolutionSize(1000, 1000);
|
||||
object.setPosition(500, 500);
|
||||
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
runtimeGame.setGameResolutionSize(2000, 2000);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
expect(object.getX()).to.equal(500);
|
||||
expect(object.getY()).to.equal(1000);
|
||||
expect(object.getWidth()).to.equal(10);
|
||||
});
|
||||
});
|
||||
});
|
@@ -4,7 +4,6 @@
|
||||
# consist in a few lines containing calls to these functions.
|
||||
|
||||
macro(gd_add_extension_includes)
|
||||
include_directories(${sfml_include_dir})
|
||||
include_directories(${GDCORE_include_dir})
|
||||
endmacro()
|
||||
|
||||
@@ -81,7 +80,6 @@ function(gd_extension_link_libraries target_name)
|
||||
#Nothing.
|
||||
ELSE()
|
||||
target_link_libraries(${target_name} GDCore)
|
||||
target_link_libraries(${target_name} ${sfml_LIBRARIES})
|
||||
ENDIF()
|
||||
endfunction()
|
||||
|
||||
|
@@ -7,7 +7,7 @@ This project is released under the MIT License.
|
||||
|
||||
#ifndef DRAGGABLEBEHAVIOR_H
|
||||
#define DRAGGABLEBEHAVIOR_H
|
||||
#include <SFML/System/Vector2.hpp>
|
||||
#include "GDCore/Vector2.h"
|
||||
#include <map>
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
|
@@ -307,7 +307,7 @@ module.exports = {
|
||||
.setLabel(_('Color map texture for the effect'))
|
||||
.setDescription(
|
||||
_(
|
||||
'You can change colors of pixels by modifing a reference color image, containing each colors, called the *Color Map Texture*. To get started, **download** [a default color map texture here](http://wiki.compilgames.net/doku.php/gdevelop5/interface/scene-editor/layer-effects).'
|
||||
'You can change colors of pixels by modifing a reference color image, containing each colors, called the *Color Map Texture*. To get started, **download** [a default color map texture here](https://wiki.gdevelop.io/gdevelop5/interface/scene-editor/layer-effects).'
|
||||
)
|
||||
);
|
||||
colorMapProperties
|
||||
@@ -442,7 +442,7 @@ module.exports = {
|
||||
.setLabel(_('Displacement map texture'))
|
||||
.setDescription(
|
||||
_(
|
||||
'Displacement map texture for the effect. To get started, **download** [a default displacement map texture here](http://wiki.compilgames.net/doku.php/gdevelop5/interface/scene-editor/layer-effects).'
|
||||
'Displacement map texture for the effect. To get started, **download** [a default displacement map texture here](https://wiki.gdevelop.io/gdevelop5/interface/scene-editor/layer-effects).'
|
||||
)
|
||||
);
|
||||
displacementProperties
|
||||
|
@@ -68,7 +68,7 @@ module.exports = {
|
||||
.setFullName(_('Dummy effect example'))
|
||||
.setDescription(
|
||||
_(
|
||||
'This is an example of an effect ("shader") with an [external link to the wiki](http://wiki.compilgames.net/doku.php/gdevelop5/) and **bold letters**.'
|
||||
'This is an example of an effect ("shader") with an [external link to the wiki](https://wiki.gdevelop.io/gdevelop5/) and **bold letters**.'
|
||||
)
|
||||
)
|
||||
.addIncludeFile('Extensions/ExampleJsExtension/dummyeffect.js');
|
||||
|
@@ -8,22 +8,18 @@ namespace gdjs {
|
||||
|
||||
/** Get the Node.js path module, or null if it can't be loaded */
|
||||
export const _getPath = function () {
|
||||
if (!gdjs.fileSystem._path) {
|
||||
// @ts-ignore
|
||||
gdjs.fileSystem._path =
|
||||
typeof require !== 'undefined' ? require('path') : null;
|
||||
if (!_path) {
|
||||
_path = typeof require !== 'undefined' ? require('path') : null;
|
||||
}
|
||||
return gdjs.fileSystem._path;
|
||||
return _path;
|
||||
};
|
||||
|
||||
/** Get the Node.js fs module, or null if it can't be loaded */
|
||||
export const _getFs = function () {
|
||||
if (!gdjs.fileSystem._fs) {
|
||||
// @ts-ignore
|
||||
gdjs.fileSystem._fs =
|
||||
typeof require !== 'undefined' ? require('fs') : null;
|
||||
if (!_fs) {
|
||||
_fs = typeof require !== 'undefined' ? require('fs') : null;
|
||||
}
|
||||
return gdjs.fileSystem._fs;
|
||||
return _fs;
|
||||
};
|
||||
|
||||
export const getDirectoryName = function (fileOrFolderPath: string) {
|
||||
@@ -58,9 +54,10 @@ namespace gdjs {
|
||||
export const getDesktopPath = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): string {
|
||||
const electron = runtimeScene.getGame().getRenderer().getElectron();
|
||||
if (electron) {
|
||||
return electron.remote.app.getPath('desktop') || '';
|
||||
const remote = runtimeScene.getGame().getRenderer().getElectronRemote();
|
||||
const app = remote ? remote.app : null;
|
||||
if (app) {
|
||||
return app.getPath('desktop') || '';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
@@ -74,9 +71,10 @@ namespace gdjs {
|
||||
export const getDocumentsPath = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): string {
|
||||
const electron = runtimeScene.getGame().getRenderer().getElectron();
|
||||
if (electron) {
|
||||
return electron.remote.app.getPath('documents') || '';
|
||||
const remote = runtimeScene.getGame().getRenderer().getElectronRemote();
|
||||
const app = remote ? remote.app : null;
|
||||
if (app) {
|
||||
return app.getPath('documents') || '';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
@@ -90,9 +88,10 @@ namespace gdjs {
|
||||
export const getPicturesPath = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): string {
|
||||
const electron = runtimeScene.getGame().getRenderer().getElectron();
|
||||
if (electron) {
|
||||
return electron.remote.app.getPath('pictures') || '';
|
||||
const remote = runtimeScene.getGame().getRenderer().getElectronRemote();
|
||||
const app = remote ? remote.app : null;
|
||||
if (app) {
|
||||
return app.getPath('pictures') || '';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
@@ -106,9 +105,10 @@ namespace gdjs {
|
||||
export const getExecutablePath = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): string {
|
||||
const electron = runtimeScene.getGame().getRenderer().getElectron();
|
||||
if (electron) {
|
||||
return electron.remote.app.getPath('exe') || '';
|
||||
const remote = runtimeScene.getGame().getRenderer().getElectronRemote();
|
||||
const app = remote ? remote.app : null;
|
||||
if (app) {
|
||||
return app.getPath('exe') || '';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
@@ -138,9 +138,10 @@ namespace gdjs {
|
||||
export const getUserdataPath = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): string {
|
||||
const electron = runtimeScene.getGame().getRenderer().getElectron();
|
||||
if (electron) {
|
||||
return electron.remote.app.getPath('userData') || '';
|
||||
const remote = runtimeScene.getGame().getRenderer().getElectronRemote();
|
||||
const app = remote ? remote.app : null;
|
||||
if (app) {
|
||||
return app.getPath('userData') || '';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
@@ -153,9 +154,10 @@ namespace gdjs {
|
||||
export const getUserHomePath = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): string {
|
||||
const electron = runtimeScene.getGame().getRenderer().getElectron();
|
||||
if (electron) {
|
||||
return electron.remote.app.getPath('home') || '';
|
||||
const remote = runtimeScene.getGame().getRenderer().getElectronRemote();
|
||||
const app = remote ? remote.app : null;
|
||||
if (app) {
|
||||
return app.getPath('home') || '';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
@@ -169,9 +171,10 @@ namespace gdjs {
|
||||
export const getTempPath = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): string {
|
||||
const electron = runtimeScene.getGame().getRenderer().getElectron();
|
||||
if (electron) {
|
||||
return electron.remote.app.getPath('temp') || '';
|
||||
const remote = runtimeScene.getGame().getRenderer().getElectronRemote();
|
||||
const app = remote ? remote.app : null;
|
||||
if (app) {
|
||||
return app.getPath('temp') || '';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
|
@@ -1324,7 +1324,7 @@ module.exports = {
|
||||
true
|
||||
)
|
||||
.setParameterLongDescription(
|
||||
'See the shape of the returned data on [the wiki page](http://wiki.compilgames.net/doku.php/gdevelop5/all-features/firebase/firestore#the_query_result).'
|
||||
'See the shape of the returned data on [the wiki page](https://wiki.gdevelop.io/gdevelop5/all-features/firebase/firestore#the_query_result).'
|
||||
)
|
||||
.addParameter(
|
||||
'scenevar',
|
||||
|
@@ -1,39 +1,40 @@
|
||||
describe('Inventory', function () {
|
||||
var runtimeGame = new gdjs.RuntimeGame({
|
||||
variables: [],
|
||||
properties: { windowWidth: 800, windowHeight: 600 },
|
||||
resources: { resources: [] },
|
||||
it('Inventories can be serialized then unserialized with no data loss', () => {
|
||||
var runtimeGame = new gdjs.RuntimeGame({
|
||||
variables: [],
|
||||
properties: { windowWidth: 800, windowHeight: 600 },
|
||||
resources: { resources: [] },
|
||||
});
|
||||
var runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
|
||||
gdjs.evtTools.inventory.add(runtimeScene, 'MyInventory', 'sword');
|
||||
gdjs.evtTools.inventory.add(runtimeScene, 'MyInventory', 'sword');
|
||||
gdjs.evtTools.inventory.equip(runtimeScene, 'MyInventory', 'sword', true);
|
||||
gdjs.evtTools.inventory.add(runtimeScene, 'MyInventory', 'armor');
|
||||
gdjs.evtTools.inventory.setMaximum(runtimeScene, 'MyInventory', 'armor', 1);
|
||||
|
||||
var variable = new gdjs.Variable();
|
||||
gdjs.evtTools.inventory.serializeToVariable(
|
||||
runtimeScene,
|
||||
'MyInventory',
|
||||
variable
|
||||
);
|
||||
gdjs.evtTools.inventory.unserializeFromVariable(
|
||||
runtimeScene,
|
||||
'MyInventory2',
|
||||
variable
|
||||
);
|
||||
expect(
|
||||
gdjs.evtTools.inventory.count(runtimeScene, 'MyInventory2', 'sword')
|
||||
).to.be(2);
|
||||
expect(
|
||||
gdjs.evtTools.inventory.isEquipped(runtimeScene, 'MyInventory2', 'sword')
|
||||
).to.be(true);
|
||||
expect(
|
||||
gdjs.evtTools.inventory.count(runtimeScene, 'MyInventory2', 'armor')
|
||||
).to.be(1);
|
||||
expect(
|
||||
gdjs.evtTools.inventory.add(runtimeScene, 'MyInventory2', 'armor')
|
||||
).to.be(false);
|
||||
});
|
||||
var runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
|
||||
gdjs.evtTools.inventory.add(runtimeScene, 'MyInventory', 'sword');
|
||||
gdjs.evtTools.inventory.add(runtimeScene, 'MyInventory', 'sword');
|
||||
gdjs.evtTools.inventory.equip(runtimeScene, 'MyInventory', 'sword', true);
|
||||
gdjs.evtTools.inventory.add(runtimeScene, 'MyInventory', 'armor');
|
||||
gdjs.evtTools.inventory.setMaximum(runtimeScene, 'MyInventory', 'armor', 1);
|
||||
|
||||
var variable = new gdjs.Variable();
|
||||
gdjs.evtTools.inventory.serializeToVariable(
|
||||
runtimeScene,
|
||||
'MyInventory',
|
||||
variable
|
||||
);
|
||||
gdjs.evtTools.inventory.unserializeFromVariable(
|
||||
runtimeScene,
|
||||
'MyInventory2',
|
||||
variable
|
||||
);
|
||||
|
||||
expect(
|
||||
gdjs.evtTools.inventory.count(runtimeScene, 'MyInventory2', 'sword')
|
||||
).to.be(2);
|
||||
expect(
|
||||
gdjs.evtTools.inventory.isEquipped(runtimeScene, 'MyInventory2', 'sword')
|
||||
).to.be(true);
|
||||
expect(
|
||||
gdjs.evtTools.inventory.count(runtimeScene, 'MyInventory2', 'armor')
|
||||
).to.be(1);
|
||||
expect(
|
||||
gdjs.evtTools.inventory.add(runtimeScene, 'MyInventory2', 'armor')
|
||||
).to.be(false);
|
||||
});
|
||||
|
258
Extensions/Leaderboards/JsExtension.js
Normal file
258
Extensions/Leaderboards/JsExtension.js
Normal file
@@ -0,0 +1,258 @@
|
||||
// @flow
|
||||
/**
|
||||
* This is a declaration of an extension for GDevelop 5.
|
||||
*
|
||||
* ℹ️ Changes in this file are watched and automatically imported if the editor
|
||||
* is running. You can also manually run `node import-GDJS-Runtime.js` (in newIDE/app/scripts).
|
||||
*
|
||||
* The file must be named "JsExtension.js", otherwise GDevelop won't load it.
|
||||
* ⚠️ If you make a change and the extension is not loaded, open the developer console
|
||||
* and search for any errors.
|
||||
*
|
||||
* More information on https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md
|
||||
*/
|
||||
|
||||
/*::
|
||||
// Import types to allow Flow to do static type checking on this file.
|
||||
// Extensions declaration are typed using Flow (like the editor), but the files
|
||||
// for the game engine are checked with TypeScript annotations.
|
||||
import { type ObjectsRenderingService, type ObjectsEditorService } from '../JsExtensionTypes.flow.js'
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
createExtension: function (
|
||||
_ /*: (string) => string */,
|
||||
gd /*: libGDevelop */
|
||||
) {
|
||||
const extension = new gd.PlatformExtension();
|
||||
extension
|
||||
.setExtensionInformation(
|
||||
'Leaderboards',
|
||||
_('Leaderboards (experimental)'),
|
||||
_('Allow your game to send scores to your leaderboards.'),
|
||||
'Florian Rival',
|
||||
'Open source (MIT License)'
|
||||
)
|
||||
.setExtensionHelpPath('/all-features/leaderboards')
|
||||
.setCategory('Leaderboards')
|
||||
.addInstructionOrExpressionGroupMetadata(_('Leaderboards (experimental)'))
|
||||
.setIcon('JsPlatform/Extensions/leaderboard.svg');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'SavePlayerScore',
|
||||
_('Save player score'),
|
||||
_("Save the player's score to the given leaderboard."),
|
||||
_(
|
||||
'Send to leaderboard _PARAM1_ the score _PARAM2_ with player name: _PARAM3_.'
|
||||
),
|
||||
_('Save score'),
|
||||
'JsPlatform/Extensions/leaderboard.svg',
|
||||
'JsPlatform/Extensions/leaderboard.svg'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.addParameter('leaderboardId', _('Leaderboard'), '', false)
|
||||
.addParameter(
|
||||
'expression',
|
||||
_('Score to register for the player'),
|
||||
'',
|
||||
false
|
||||
)
|
||||
.addParameter('string', _('Name to register for the player'), '', false)
|
||||
.setHelpPath('/all-features/leaderboards')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Leaderboards/sha256.js')
|
||||
.addIncludeFile('Extensions/Leaderboards/leaderboardstools.js')
|
||||
.setFunctionName('gdjs.evtTools.leaderboards.savePlayerScore');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'HasLastSaveErrored',
|
||||
_('Last score save has errored'),
|
||||
_('Check if the last attempt to save a score has errored.'),
|
||||
_('Last score save in leaderboard _PARAM0_ has errored'),
|
||||
_('Save score'),
|
||||
'JsPlatform/Extensions/leaderboard.svg',
|
||||
'JsPlatform/Extensions/leaderboard.svg'
|
||||
)
|
||||
.addParameter('leaderboardId', _('Leaderboard'), '', true)
|
||||
.setParameterLongDescription(
|
||||
_(
|
||||
'If no leaderboard is specified, will return the value related to the last leaderboard save action.'
|
||||
)
|
||||
)
|
||||
.setHelpPath('/all-features/leaderboards')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Leaderboards/leaderboardstools.js')
|
||||
.setFunctionName('gdjs.evtTools.leaderboards.hasSavingErrored');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'HasLastSaveSucceeded',
|
||||
_('Last score save has succeeded'),
|
||||
_('Check if the last attempt to save a score has succeeded.'),
|
||||
_('Last score save in leaderboard _PARAM0_ has succeeded'),
|
||||
_('Save score'),
|
||||
'JsPlatform/Extensions/leaderboard.svg',
|
||||
'JsPlatform/Extensions/leaderboard.svg'
|
||||
)
|
||||
.addParameter('leaderboardId', _('Leaderboard'), '', true)
|
||||
.setParameterLongDescription(
|
||||
_(
|
||||
'If no leaderboard is specified, will return the value related to the last leaderboard save action that successfully ended.'
|
||||
)
|
||||
)
|
||||
.setHelpPath('/all-features/leaderboards')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Leaderboards/leaderboardstools.js')
|
||||
.setFunctionName('gdjs.evtTools.leaderboards.hasBeenSaved');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'IsSaving',
|
||||
_('Score is saving'),
|
||||
_('Check if a score is currently being saved in leaderboard.'),
|
||||
_('Score is saving in leaderboard _PARAM0_'),
|
||||
_('Save score'),
|
||||
'JsPlatform/Extensions/leaderboard.svg',
|
||||
'JsPlatform/Extensions/leaderboard.svg'
|
||||
)
|
||||
.addParameter('leaderboardId', _('Leaderboard'), '', true)
|
||||
.setParameterLongDescription(
|
||||
_(
|
||||
'If no leaderboard is specified, will return the value related to the last leaderboard save action.'
|
||||
)
|
||||
)
|
||||
.setHelpPath('/all-features/leaderboards')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Leaderboards/leaderboardstools.js')
|
||||
.setFunctionName('gdjs.evtTools.leaderboards.isSaving');
|
||||
|
||||
extension
|
||||
.addStrExpression(
|
||||
'LastSaveError',
|
||||
_('Error of last save attempt'),
|
||||
_('Get the error of the last save attempt.'),
|
||||
_('Error of last save attempt in leaderboard _PARAM0_'),
|
||||
'JsPlatform/Extensions/leaderboard.svg'
|
||||
)
|
||||
.addParameter('leaderboardId', _('Leaderboard'), '', true)
|
||||
.setParameterLongDescription(
|
||||
_(
|
||||
'If no leaderboard is specified, will return the value related to the last leaderboard save action.'
|
||||
)
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Leaderboards/leaderboardstools.js')
|
||||
.setFunctionName('gdjs.evtTools.leaderboards.getLastSaveError');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'IsLeaderboardViewErrored',
|
||||
_('Leaderboard display has errored'),
|
||||
_('Check if the display of the leaderboard errored.'),
|
||||
_('Leaderboard display has errored'),
|
||||
_('Display leaderboard'),
|
||||
'JsPlatform/Extensions/leaderboard.svg',
|
||||
'JsPlatform/Extensions/leaderboard.svg'
|
||||
)
|
||||
.setHelpPath('/all-features/leaderboards')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Leaderboards/leaderboardstools.js')
|
||||
.setFunctionName('gdjs.evtTools.leaderboards.isLeaderboardViewErrored');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'IsLeaderboardViewLoaded',
|
||||
_('Leaderboard display has loaded'),
|
||||
_(
|
||||
'Check if the display of the leaderboard has finished loading and been displayed on screen.'
|
||||
),
|
||||
_('Leaderboard display has loaded and is displayed on screen'),
|
||||
_('Display leaderboard'),
|
||||
'JsPlatform/Extensions/leaderboard.svg',
|
||||
'JsPlatform/Extensions/leaderboard.svg'
|
||||
)
|
||||
.setHelpPath('/all-features/leaderboards')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Leaderboards/leaderboardstools.js')
|
||||
.setFunctionName('gdjs.evtTools.leaderboards.isLeaderboardViewLoaded');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'IsLeaderboardViewLoading',
|
||||
_('Leaderboard display is loading'),
|
||||
_('Check if the display of the leaderboard is loading.'),
|
||||
_('Leaderboard display is loading'),
|
||||
_('Display leaderboard'),
|
||||
'JsPlatform/Extensions/leaderboard.svg',
|
||||
'JsPlatform/Extensions/leaderboard.svg'
|
||||
)
|
||||
.setHelpPath('/all-features/leaderboards')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Leaderboards/leaderboardstools.js')
|
||||
.setFunctionName('gdjs.evtTools.leaderboards.isLeaderboardViewLoading');
|
||||
|
||||
extension
|
||||
.addStrExpression(
|
||||
'FormatPlayerName',
|
||||
_('Format player name'),
|
||||
_('Formats a name so that it can be submitted to a leaderboard.'),
|
||||
_('Save score'),
|
||||
'JsPlatform/Extensions/leaderboard.svg'
|
||||
)
|
||||
.addParameter('string', _('Raw player name'), '', false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Leaderboards/leaderboardstools.js')
|
||||
.setFunctionName('gdjs.evtTools.leaderboards.formatPlayerName');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'DisplayLeaderboard',
|
||||
_('Display leaderboard'),
|
||||
_(
|
||||
'Display the specified leaderboard on top of the game. If a leaderboard was already displayed on top of the game, the new leaderboard will replace it.'
|
||||
),
|
||||
_('Display leaderboard _PARAM1_ (display a loader: _PARAM2_)'),
|
||||
_('Display leaderboard'),
|
||||
'JsPlatform/Extensions/leaderboard.svg',
|
||||
'JsPlatform/Extensions/leaderboard.svg'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.addParameter('leaderboardId', _('Leaderboard'), '', false)
|
||||
.addParameter(
|
||||
'yesorno',
|
||||
_('Display loader while leaderboard is loading'),
|
||||
'',
|
||||
false
|
||||
)
|
||||
.setHelpPath('/all-features/leaderboards')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Leaderboards/leaderboardstools.js')
|
||||
.setFunctionName('gdjs.evtTools.leaderboards.displayLeaderboard');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'CloseLeaderboardView',
|
||||
_('Close current leaderboard'),
|
||||
_('Close the leaderboard currently displayed on top of the game.'),
|
||||
_('Close current leaderboard displayed on top of the game'),
|
||||
_('Display leaderboard'),
|
||||
'JsPlatform/Extensions/leaderboard.svg',
|
||||
'JsPlatform/Extensions/leaderboard.svg'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.setHelpPath('/all-features/leaderboards')
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Leaderboards/leaderboardstools.js')
|
||||
.setFunctionName('gdjs.evtTools.leaderboards.closeLeaderboardView');
|
||||
|
||||
return extension;
|
||||
},
|
||||
runExtensionSanityTests: function (
|
||||
gd /*: libGDevelop */,
|
||||
extension /*: gdPlatformExtension*/
|
||||
) {
|
||||
return [];
|
||||
},
|
||||
};
|
645
Extensions/Leaderboards/leaderboardstools.ts
Normal file
645
Extensions/Leaderboards/leaderboardstools.ts
Normal file
@@ -0,0 +1,645 @@
|
||||
/// <reference path="sha256.d.ts" />
|
||||
|
||||
namespace gdjs {
|
||||
const logger = new gdjs.Logger('Leaderboards');
|
||||
export namespace evtTools {
|
||||
export namespace leaderboards {
|
||||
const computeDigest = (payload: string): string => {
|
||||
const shaObj = new jsSHA('SHA-256', 'TEXT', { encoding: 'UTF8' });
|
||||
shaObj.update(payload);
|
||||
return shaObj.getHash('B64');
|
||||
};
|
||||
|
||||
// Score saving
|
||||
class ScoreSavingState {
|
||||
lastScoreSavingStartedAt: number | null;
|
||||
lastScoreSavingSucceededAt: number | null;
|
||||
currentlySavingScore: number | null;
|
||||
currentlySavingPlayerName: string | null;
|
||||
lastSavedScore: number | null;
|
||||
lastSavedPlayerName: string | null;
|
||||
lastSaveError: string | null;
|
||||
isScoreSaving: boolean;
|
||||
hasScoreBeenSaved: boolean;
|
||||
hasScoreSavingErrored: boolean;
|
||||
|
||||
constructor() {
|
||||
this.lastScoreSavingStartedAt = null;
|
||||
this.lastScoreSavingSucceededAt = null;
|
||||
this.currentlySavingScore = null;
|
||||
this.currentlySavingPlayerName = null;
|
||||
this.lastSavedScore = null;
|
||||
this.lastSavedPlayerName = null;
|
||||
this.lastSaveError = null;
|
||||
this.isScoreSaving = false;
|
||||
this.hasScoreBeenSaved = false;
|
||||
this.hasScoreSavingErrored = false;
|
||||
}
|
||||
|
||||
isSameAsLastScore(playerName: string, score: number): boolean {
|
||||
return (
|
||||
this.lastSavedPlayerName === playerName &&
|
||||
this.lastSavedScore === score
|
||||
);
|
||||
}
|
||||
|
||||
isAlreadySavingThisScore(playerName: string, score: number): boolean {
|
||||
return (
|
||||
this.isScoreSaving &&
|
||||
this.currentlySavingPlayerName === playerName &&
|
||||
this.currentlySavingScore === score
|
||||
);
|
||||
}
|
||||
|
||||
isTooSoonToSaveAnotherScore(): boolean {
|
||||
return (
|
||||
!!this.lastScoreSavingSucceededAt &&
|
||||
Date.now() - this.lastScoreSavingSucceededAt < 500
|
||||
);
|
||||
}
|
||||
|
||||
startSaving(playerName: string, score: number): void {
|
||||
this.lastScoreSavingStartedAt = Date.now();
|
||||
this.isScoreSaving = true;
|
||||
this.hasScoreBeenSaved = false;
|
||||
this.hasScoreSavingErrored = false;
|
||||
this.currentlySavingScore = score;
|
||||
this.currentlySavingPlayerName = playerName;
|
||||
}
|
||||
|
||||
closeSaving(): void {
|
||||
this.lastScoreSavingSucceededAt = Date.now();
|
||||
this.lastSavedScore = this.currentlySavingScore;
|
||||
this.lastSavedPlayerName = this.currentlySavingPlayerName;
|
||||
this.isScoreSaving = false;
|
||||
this.hasScoreBeenSaved = true;
|
||||
}
|
||||
|
||||
setError(errorCode: string): void {
|
||||
this.lastSaveError = errorCode;
|
||||
this.isScoreSaving = false;
|
||||
this.hasScoreBeenSaved = false;
|
||||
this.hasScoreSavingErrored = true;
|
||||
}
|
||||
}
|
||||
|
||||
let _scoreSavingStateByLeaderboard: {
|
||||
[leaderboardId: string]: ScoreSavingState;
|
||||
} = {};
|
||||
|
||||
// Leaderboard display
|
||||
let _requestedLeaderboardId: string | null;
|
||||
let _leaderboardViewIframe: HTMLIFrameElement | null = null;
|
||||
let _leaderboardViewIframeErrored: boolean = false;
|
||||
let _leaderboardViewIframeLoading: boolean = false;
|
||||
let _leaderboardViewIframeLoaded: boolean = false;
|
||||
let _errorTimeoutId: NodeJS.Timeout | null = null;
|
||||
let _leaderboardViewClosingCallback:
|
||||
| ((event: MessageEvent) => void)
|
||||
| null = null;
|
||||
|
||||
const _loaderContainer: HTMLDivElement = document.createElement('div');
|
||||
_loaderContainer.style.backgroundColor = '#000000';
|
||||
_loaderContainer.style.display = 'flex';
|
||||
_loaderContainer.style.height = '100%';
|
||||
_loaderContainer.style.width = '100%';
|
||||
_loaderContainer.style.justifyContent = 'center';
|
||||
_loaderContainer.style.alignItems = 'center';
|
||||
_loaderContainer.style.position = 'relative';
|
||||
_loaderContainer.style.zIndex = '2';
|
||||
const _loader = document.createElement('img');
|
||||
_loader.setAttribute('width', '50px');
|
||||
_loader.setAttribute(
|
||||
'src',
|
||||
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCAyNCAyNCI+CjxjaXJjbGUgb3BhY2l0eT0nMC4yNScgY3g9IjEyIiBjeT0iMTIiIHI9IjEwIiBzdHJva2U9IiNGRkZGRkYiIHN0cm9rZS13aWR0aD0iNCI+PC9jaXJjbGU+CjxwYXRoIG9wYWNpdHk9JzAuNzUnIGZpbGw9IiNGRkZGRkYiIGQ9Ik00IDEyYTggOCAwIDAxOC04VjBDNS4zNzMgMCAwIDUuMzczIDAgMTJoNHptMiA1LjI5MUE3Ljk2MiA3Ljk2MiAwIDAxNCAxMkgwYzAgMy4wNDIgMS4xMzUgNS44MjQgMyA3LjkzOGwzLTIuNjQ3eiI+PC9wYXRoPgo8L3N2Zz4='
|
||||
);
|
||||
try {
|
||||
_loader.animate(
|
||||
[{ transform: 'rotate(0deg)' }, { transform: 'rotate(359deg)' }],
|
||||
{
|
||||
duration: 3000,
|
||||
iterations: Infinity,
|
||||
}
|
||||
);
|
||||
} catch {
|
||||
logger.warn('Animation not supported, loader will be fixed.');
|
||||
}
|
||||
_loaderContainer.appendChild(_loader);
|
||||
|
||||
const getLastScoreSavingState = function ({
|
||||
hasSucceeded,
|
||||
}: {
|
||||
hasSucceeded: boolean;
|
||||
}): ScoreSavingState | null {
|
||||
const getDateField = (scoreSavingState: ScoreSavingState) =>
|
||||
hasSucceeded
|
||||
? scoreSavingState.lastScoreSavingSucceededAt
|
||||
: scoreSavingState.lastScoreSavingStartedAt;
|
||||
const scoreSavingStates = Object.values(
|
||||
_scoreSavingStateByLeaderboard
|
||||
).filter((scoreSavingState) => !!getDateField(scoreSavingState));
|
||||
if (scoreSavingStates.length === 0) return null;
|
||||
|
||||
let lastScoreSavingState = scoreSavingStates[0];
|
||||
scoreSavingStates.forEach((scoreSavingState) => {
|
||||
const currentItemDate = getDateField(scoreSavingState);
|
||||
const lastItemDate = getDateField(lastScoreSavingState);
|
||||
if (
|
||||
currentItemDate &&
|
||||
lastItemDate &&
|
||||
currentItemDate > lastItemDate
|
||||
) {
|
||||
lastScoreSavingState = scoreSavingState;
|
||||
}
|
||||
});
|
||||
return lastScoreSavingState;
|
||||
};
|
||||
|
||||
export const savePlayerScore = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
leaderboardId: string,
|
||||
score: float,
|
||||
playerName: string
|
||||
) {
|
||||
let scoreSavingState: ScoreSavingState;
|
||||
if (_scoreSavingStateByLeaderboard[leaderboardId]) {
|
||||
scoreSavingState = _scoreSavingStateByLeaderboard[leaderboardId];
|
||||
if (scoreSavingState.isAlreadySavingThisScore(playerName, score)) {
|
||||
logger.warn(
|
||||
'There is already a request to save with this player name and this score. Ignoring this one.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (scoreSavingState.isSameAsLastScore(playerName, score)) {
|
||||
logger.warn(
|
||||
'The player and score to be sent are the same as previous one. Ignoring this one.'
|
||||
);
|
||||
const errorCode = 'SAME_AS_PREVIOUS';
|
||||
scoreSavingState.setError(errorCode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (scoreSavingState.isTooSoonToSaveAnotherScore()) {
|
||||
logger.warn(
|
||||
'Last entry was sent too little time ago. Ignoring this one.'
|
||||
);
|
||||
const errorCode = 'TOO_FAST';
|
||||
scoreSavingState.setError(errorCode);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
scoreSavingState = new ScoreSavingState();
|
||||
_scoreSavingStateByLeaderboard[leaderboardId] = scoreSavingState;
|
||||
}
|
||||
|
||||
scoreSavingState.startSaving(playerName, score);
|
||||
|
||||
const baseUrl = 'https://api.gdevelop-app.com/play';
|
||||
const game = runtimeScene.getGame();
|
||||
const payload = JSON.stringify({
|
||||
playerName: formatPlayerName(playerName),
|
||||
score: score,
|
||||
sessionId: game.getSessionId(),
|
||||
clientPlayerId: game.getPlayerId(),
|
||||
location:
|
||||
typeof window !== 'undefined' && (window as any).location
|
||||
? (window as any).location.href
|
||||
: '',
|
||||
});
|
||||
fetch(
|
||||
`${baseUrl}/game/${gdjs.projectData.properties.projectUuid}/leaderboard/${leaderboardId}/entry`,
|
||||
{
|
||||
body: payload,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Digest: computeDigest(payload),
|
||||
},
|
||||
}
|
||||
).then(
|
||||
(response) => {
|
||||
if (!response.ok) {
|
||||
const errorCode = response.status.toString();
|
||||
logger.error(
|
||||
'Server responded with an error:',
|
||||
errorCode,
|
||||
response.statusText
|
||||
);
|
||||
scoreSavingState.setError(errorCode);
|
||||
return;
|
||||
}
|
||||
|
||||
scoreSavingState.closeSaving();
|
||||
|
||||
return response.text().then(
|
||||
(text) => {},
|
||||
(error) => {
|
||||
logger.warn(
|
||||
'An error occurred when reading response but score has been saved:',
|
||||
error
|
||||
);
|
||||
}
|
||||
);
|
||||
},
|
||||
(error) => {
|
||||
logger.error('Error while submitting a leaderboard score:', error);
|
||||
const errorCode = 'REQUEST_NOT_SENT';
|
||||
scoreSavingState.setError(errorCode);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const isSaving = function (leaderboardId?: string): boolean {
|
||||
if (leaderboardId) {
|
||||
return _scoreSavingStateByLeaderboard[leaderboardId]
|
||||
? _scoreSavingStateByLeaderboard[leaderboardId].isScoreSaving
|
||||
: false;
|
||||
}
|
||||
|
||||
const lastScoreSavingState = getLastScoreSavingState({
|
||||
hasSucceeded: false,
|
||||
});
|
||||
return lastScoreSavingState
|
||||
? lastScoreSavingState.isScoreSaving
|
||||
: false;
|
||||
};
|
||||
|
||||
export const hasBeenSaved = function (leaderboardId?: string): boolean {
|
||||
if (leaderboardId) {
|
||||
return _scoreSavingStateByLeaderboard[leaderboardId]
|
||||
? _scoreSavingStateByLeaderboard[leaderboardId].hasScoreBeenSaved
|
||||
: false;
|
||||
}
|
||||
|
||||
const lastScoreSavingState = getLastScoreSavingState({
|
||||
hasSucceeded: true,
|
||||
});
|
||||
return lastScoreSavingState
|
||||
? lastScoreSavingState.hasScoreBeenSaved
|
||||
: false;
|
||||
};
|
||||
|
||||
export const hasSavingErrored = function (
|
||||
leaderboardId?: string
|
||||
): boolean {
|
||||
if (leaderboardId) {
|
||||
return _scoreSavingStateByLeaderboard[leaderboardId]
|
||||
? _scoreSavingStateByLeaderboard[leaderboardId]
|
||||
.hasScoreSavingErrored
|
||||
: false;
|
||||
}
|
||||
|
||||
const lastScoreSavingState = getLastScoreSavingState({
|
||||
hasSucceeded: false,
|
||||
});
|
||||
return lastScoreSavingState
|
||||
? lastScoreSavingState.hasScoreSavingErrored
|
||||
: false;
|
||||
};
|
||||
|
||||
export const getLastSaveError = function (
|
||||
leaderboardId?: string
|
||||
): string | null {
|
||||
if (leaderboardId) {
|
||||
return _scoreSavingStateByLeaderboard[leaderboardId]
|
||||
? _scoreSavingStateByLeaderboard[leaderboardId].lastSaveError
|
||||
: 'NO_DATA_ERROR';
|
||||
}
|
||||
|
||||
const lastScoreSavingState = getLastScoreSavingState({
|
||||
hasSucceeded: false,
|
||||
});
|
||||
return lastScoreSavingState
|
||||
? lastScoreSavingState.lastSaveError
|
||||
: 'NO_DATA_ERROR';
|
||||
};
|
||||
|
||||
export const formatPlayerName = function (rawName: string): string {
|
||||
if (
|
||||
!rawName ||
|
||||
typeof rawName !== 'string' ||
|
||||
(typeof rawName === 'string' && rawName.length === 0)
|
||||
) {
|
||||
return `Player${Math.round(
|
||||
(Math.random() * 9 + 1) * 10000 // Number between 10,000 and 99,999
|
||||
)}`;
|
||||
}
|
||||
return rawName
|
||||
.trim()
|
||||
.normalize('NFD')
|
||||
.replace(/[\u0300-\u036f]/g, '')
|
||||
.replace(/\s/g, '_')
|
||||
.replace(/[^\w|-]/g, '')
|
||||
.slice(0, 30);
|
||||
};
|
||||
|
||||
const checkLeaderboardAvailability = function (
|
||||
url: string
|
||||
): Promise<boolean> {
|
||||
return fetch(url, {
|
||||
method: 'GET',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
}).then(
|
||||
(response) => {
|
||||
if (!response.ok) {
|
||||
logger.error(
|
||||
`Error while fetching leaderboard view, server returned: ${response.status} ${response.statusText}`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
(err) => {
|
||||
logger.error('Error while fetching leaderboard view:', err);
|
||||
return false;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const receiveMessageFromLeaderboardView = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
displayLoader: boolean,
|
||||
event: MessageEvent
|
||||
) {
|
||||
switch (event.data) {
|
||||
case 'closeLeaderboardView':
|
||||
closeLeaderboardView(runtimeScene);
|
||||
break;
|
||||
case 'leaderboardViewLoaded':
|
||||
if (displayLoader) {
|
||||
if (_errorTimeoutId) clearTimeout(_errorTimeoutId);
|
||||
displayLoaderInLeaderboardView(false, runtimeScene, {
|
||||
callOnErrorIfDomElementContainerMissing: false,
|
||||
});
|
||||
}
|
||||
if (!_leaderboardViewIframe) {
|
||||
handleErrorDisplayingLeaderboard(
|
||||
runtimeScene,
|
||||
"The leaderboard view couldn't be found. Doing nothing."
|
||||
);
|
||||
return;
|
||||
}
|
||||
_leaderboardViewIframe.style.opacity = '1';
|
||||
_leaderboardViewIframeLoaded = true;
|
||||
_leaderboardViewIframeLoading = false;
|
||||
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const handleErrorDisplayingLeaderboard = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
message: string
|
||||
) {
|
||||
logger.error(message);
|
||||
_leaderboardViewIframeErrored = true;
|
||||
_leaderboardViewIframeLoading = false;
|
||||
closeLeaderboardView(runtimeScene);
|
||||
};
|
||||
|
||||
const resetLeaderboardDisplayErrorTimeout = (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) => {
|
||||
if (_errorTimeoutId) clearTimeout(_errorTimeoutId);
|
||||
_errorTimeoutId = setTimeout(() => {
|
||||
if (!_leaderboardViewIframeLoaded) {
|
||||
handleErrorDisplayingLeaderboard(
|
||||
runtimeScene,
|
||||
'Leaderboard page did not send message in time. Closing leaderboard view.'
|
||||
);
|
||||
}
|
||||
}, 5000);
|
||||
};
|
||||
|
||||
const displayLoaderInLeaderboardView = function (
|
||||
yesOrNo: boolean,
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
options: { callOnErrorIfDomElementContainerMissing: boolean }
|
||||
): boolean {
|
||||
const domElementContainer = runtimeScene
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getDomElementContainer();
|
||||
if (!domElementContainer) {
|
||||
if (options.callOnErrorIfDomElementContainerMissing) {
|
||||
handleErrorDisplayingLeaderboard(
|
||||
runtimeScene,
|
||||
"The div element covering the game couldn't be found, the leaderboard cannot be displayed."
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (yesOrNo) {
|
||||
if (
|
||||
domElementContainer.children &&
|
||||
domElementContainer.children.length > 0
|
||||
) {
|
||||
domElementContainer.insertBefore(
|
||||
_loaderContainer,
|
||||
domElementContainer.children[0]
|
||||
);
|
||||
} else {
|
||||
domElementContainer.appendChild(_loaderContainer);
|
||||
}
|
||||
if (_leaderboardViewIframe) {
|
||||
_leaderboardViewIframe.style.opacity = '0';
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
domElementContainer.removeChild(_loaderContainer);
|
||||
if (_leaderboardViewIframe) {
|
||||
_leaderboardViewIframe.style.opacity = '1';
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const computeLeaderboardDisplayingIframe = function (
|
||||
url: string
|
||||
): HTMLIFrameElement {
|
||||
const iframe = document.createElement('iframe');
|
||||
|
||||
iframe.src = url;
|
||||
iframe.id = 'leaderboard-view';
|
||||
iframe.style.position = 'absolute';
|
||||
// To trigger iframe loading and be able to listen to its events, use `opacity: 0` instead of `visibility: hidden` or `display: none`
|
||||
iframe.style.opacity = '0';
|
||||
iframe.style.pointerEvents = 'all';
|
||||
iframe.style.backgroundColor = '#FFFFFF';
|
||||
iframe.style.top = '0px';
|
||||
iframe.style.height = '100%';
|
||||
iframe.style.left = '0px';
|
||||
iframe.style.width = '100%';
|
||||
iframe.style.border = 'none';
|
||||
|
||||
return iframe;
|
||||
};
|
||||
|
||||
export const displayLeaderboard = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
leaderboardId: string,
|
||||
displayLoader: boolean
|
||||
) {
|
||||
// First ensure we're not trying to display multiple times the same leaderboard (in which case
|
||||
// we "de-duplicate" the request to display it).
|
||||
if (leaderboardId === _requestedLeaderboardId) {
|
||||
if (_leaderboardViewIframeLoading) {
|
||||
logger.warn(
|
||||
`Already loading the view for the requested loader (${leaderboardId}), ignoring.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (_leaderboardViewIframeLoaded) {
|
||||
logger.warn(
|
||||
`Already loaded the view for the requested loader (${leaderboardId}), ignoring.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We are now assured we want to display a new (or different) leaderboard: start loading it.
|
||||
_requestedLeaderboardId = leaderboardId;
|
||||
_leaderboardViewIframeErrored = false;
|
||||
_leaderboardViewIframeLoaded = false;
|
||||
_leaderboardViewIframeLoading = true;
|
||||
|
||||
if (displayLoader) {
|
||||
displayLoaderInLeaderboardView(true, runtimeScene, {
|
||||
callOnErrorIfDomElementContainerMissing: true,
|
||||
});
|
||||
}
|
||||
|
||||
const gameId = gdjs.projectData.properties.projectUuid;
|
||||
const targetUrl = `https://liluo.io/games/${gameId}/leaderboard/${leaderboardId}?inGameEmbedded=true`;
|
||||
checkLeaderboardAvailability(targetUrl).then(
|
||||
(isAvailable) => {
|
||||
if (leaderboardId !== _requestedLeaderboardId) {
|
||||
logger.warn(
|
||||
`Received a response for leaderboard ${leaderboardId} though the last leaderboard requested is ${_requestedLeaderboardId}, ignoring this response.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!isAvailable) {
|
||||
handleErrorDisplayingLeaderboard(
|
||||
runtimeScene,
|
||||
'Leaderboard data could not be fetched. Closing leaderboard view if there is one.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_leaderboardViewIframe) {
|
||||
resetLeaderboardDisplayErrorTimeout(runtimeScene);
|
||||
if (displayLoader) {
|
||||
displayLoaderInLeaderboardView(true, runtimeScene, {
|
||||
callOnErrorIfDomElementContainerMissing: false,
|
||||
});
|
||||
}
|
||||
_leaderboardViewIframe.src = targetUrl;
|
||||
} else {
|
||||
const domElementContainer = runtimeScene
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getDomElementContainer();
|
||||
if (!domElementContainer) {
|
||||
handleErrorDisplayingLeaderboard(
|
||||
runtimeScene,
|
||||
"The div element covering the game couldn't be found, the leaderboard cannot be displayed."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
resetLeaderboardDisplayErrorTimeout(runtimeScene);
|
||||
|
||||
_leaderboardViewIframe = computeLeaderboardDisplayingIframe(
|
||||
targetUrl
|
||||
);
|
||||
if (typeof window !== 'undefined') {
|
||||
_leaderboardViewClosingCallback = (event: MessageEvent) => {
|
||||
receiveMessageFromLeaderboardView(
|
||||
runtimeScene,
|
||||
displayLoader,
|
||||
event
|
||||
);
|
||||
};
|
||||
(window as any).addEventListener(
|
||||
'message',
|
||||
_leaderboardViewClosingCallback,
|
||||
true
|
||||
);
|
||||
}
|
||||
domElementContainer.appendChild(_leaderboardViewIframe);
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
logger.error(err);
|
||||
handleErrorDisplayingLeaderboard(
|
||||
runtimeScene,
|
||||
'An error occurred when fetching leaderboard data. Closing leaderboard view if there is one.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const isLeaderboardViewErrored = function (): boolean {
|
||||
return _leaderboardViewIframeErrored;
|
||||
};
|
||||
|
||||
export const isLeaderboardViewLoaded = function (): boolean {
|
||||
return _leaderboardViewIframeLoaded;
|
||||
};
|
||||
|
||||
export const isLeaderboardViewLoading = function (): boolean {
|
||||
return _leaderboardViewIframeLoading;
|
||||
};
|
||||
|
||||
export const closeLeaderboardView = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
try {
|
||||
displayLoaderInLeaderboardView(false, runtimeScene, {
|
||||
callOnErrorIfDomElementContainerMissing: false,
|
||||
});
|
||||
|
||||
if (!_leaderboardViewIframe) {
|
||||
logger.info(
|
||||
"The iframe displaying the current leaderboard couldn't be found, the leaderboard view must be already closed."
|
||||
);
|
||||
return;
|
||||
}
|
||||
const domElementContainer = runtimeScene
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getDomElementContainer();
|
||||
if (!domElementContainer) {
|
||||
logger.info(
|
||||
"The div element covering the game couldn't be found, the leaderboard view must be already closed."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
(window as any).removeEventListener(
|
||||
'message',
|
||||
_leaderboardViewClosingCallback,
|
||||
true
|
||||
);
|
||||
_leaderboardViewClosingCallback = null;
|
||||
}
|
||||
domElementContainer.removeChild(_leaderboardViewIframe);
|
||||
_leaderboardViewIframe = null;
|
||||
} finally {
|
||||
// Don't reset the loading flag (the view of another leaderboard might be loading)
|
||||
// or the error flag (we want to persist the error flag even after the view is closed),
|
||||
// but reset the flag indicating the view is loaded (if it was).
|
||||
_leaderboardViewIframeLoaded = false;
|
||||
|
||||
const gameCanvas = runtimeScene.getGame().getRenderer().getCanvas();
|
||||
if (gameCanvas) gameCanvas.focus();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
234
Extensions/Leaderboards/sha256.d.ts
vendored
Normal file
234
Extensions/Leaderboards/sha256.d.ts
vendored
Normal file
@@ -0,0 +1,234 @@
|
||||
declare type EncodingType = 'UTF8' | 'UTF16BE' | 'UTF16LE';
|
||||
declare type FormatNoTextType =
|
||||
| 'HEX'
|
||||
| 'B64'
|
||||
| 'BYTES'
|
||||
| 'ARRAYBUFFER'
|
||||
| 'UINT8ARRAY';
|
||||
declare type FormatType = 'TEXT' | FormatNoTextType;
|
||||
declare type GenericInputType =
|
||||
| {
|
||||
value: string;
|
||||
format: 'TEXT';
|
||||
encoding?: EncodingType;
|
||||
}
|
||||
| {
|
||||
value: string;
|
||||
format: 'B64' | 'HEX' | 'BYTES';
|
||||
}
|
||||
| {
|
||||
value: ArrayBuffer;
|
||||
format: 'ARRAYBUFFER';
|
||||
}
|
||||
| {
|
||||
value: Uint8Array;
|
||||
format: 'UINT8ARRAY';
|
||||
};
|
||||
declare type FixedLengthOptionsNoEncodingType =
|
||||
| {
|
||||
hmacKey?: GenericInputType;
|
||||
}
|
||||
| {
|
||||
numRounds?: number;
|
||||
};
|
||||
declare type FixedLengthOptionsEncodingType =
|
||||
| {
|
||||
hmacKey?: GenericInputType;
|
||||
encoding?: EncodingType;
|
||||
}
|
||||
| {
|
||||
numRounds?: number;
|
||||
encoding?: EncodingType;
|
||||
};
|
||||
interface packedValue {
|
||||
value: number[];
|
||||
binLen: number;
|
||||
}
|
||||
|
||||
declare abstract class jsSHABase<StateT, VariantT> {
|
||||
/**
|
||||
* @param variant The desired SHA variant.
|
||||
* @param inputFormat The input format to be used in future `update` calls.
|
||||
* @param options Hashmap of extra input options.
|
||||
*/
|
||||
protected readonly shaVariant: VariantT;
|
||||
protected readonly inputFormat: FormatType;
|
||||
protected readonly utfType: EncodingType;
|
||||
protected readonly numRounds: number;
|
||||
protected abstract intermediateState: StateT;
|
||||
protected keyWithIPad: number[];
|
||||
protected keyWithOPad: number[];
|
||||
protected remainder: number[];
|
||||
protected remainderLen: number;
|
||||
protected updateCalled: boolean;
|
||||
protected processedLen: number;
|
||||
protected macKeySet: boolean;
|
||||
protected abstract readonly variantBlockSize: number;
|
||||
protected abstract readonly bigEndianMod: -1 | 1;
|
||||
protected abstract readonly outputBinLen: number;
|
||||
protected abstract readonly isVariableLen: boolean;
|
||||
protected abstract readonly HMACSupported: boolean;
|
||||
protected abstract readonly converterFunc: (
|
||||
input: any,
|
||||
existingBin: number[],
|
||||
existingBinLen: number
|
||||
) => packedValue;
|
||||
protected abstract readonly roundFunc: (block: number[], H: StateT) => StateT;
|
||||
protected abstract readonly finalizeFunc: (
|
||||
remainder: number[],
|
||||
remainderBinLen: number,
|
||||
processedBinLen: number,
|
||||
H: StateT,
|
||||
outputLen: number
|
||||
) => number[];
|
||||
protected abstract readonly stateCloneFunc: (state: StateT) => StateT;
|
||||
protected abstract readonly newStateFunc: (variant: VariantT) => StateT;
|
||||
protected abstract readonly getMAC:
|
||||
| ((options: { outputLen: number }) => number[])
|
||||
| null;
|
||||
protected constructor(
|
||||
variant: VariantT,
|
||||
inputFormat: 'TEXT',
|
||||
options?: FixedLengthOptionsEncodingType
|
||||
);
|
||||
protected constructor(
|
||||
variant: VariantT,
|
||||
inputFormat: FormatNoTextType,
|
||||
options?: FixedLengthOptionsNoEncodingType
|
||||
);
|
||||
/**
|
||||
* Hashes as many blocks as possible. Stores the rest for either a future update or getHash call.
|
||||
*
|
||||
* @param srcString The input to be hashed.
|
||||
*/
|
||||
update(srcString: string | ArrayBuffer | Uint8Array): void;
|
||||
/**
|
||||
* Returns the desired SHA hash of the input fed in via `update` calls.
|
||||
*
|
||||
* @param format The desired output formatting
|
||||
* @param options Hashmap of output formatting options. `outputLen` must be specified for variable length hashes.
|
||||
* `outputLen` replaces the now deprecated `shakeLen` key.
|
||||
* @returns The hash in the format specified.
|
||||
*/
|
||||
getHash(
|
||||
format: 'HEX',
|
||||
options?: {
|
||||
outputUpper?: boolean;
|
||||
outputLen?: number;
|
||||
shakeLen?: number;
|
||||
}
|
||||
): string;
|
||||
getHash(
|
||||
format: 'B64',
|
||||
options?: {
|
||||
b64Pad?: string;
|
||||
outputLen?: number;
|
||||
shakeLen?: number;
|
||||
}
|
||||
): string;
|
||||
getHash(
|
||||
format: 'BYTES',
|
||||
options?: {
|
||||
outputLen?: number;
|
||||
shakeLen?: number;
|
||||
}
|
||||
): string;
|
||||
getHash(
|
||||
format: 'UINT8ARRAY',
|
||||
options?: {
|
||||
outputLen?: number;
|
||||
shakeLen?: number;
|
||||
}
|
||||
): Uint8Array;
|
||||
getHash(
|
||||
format: 'ARRAYBUFFER',
|
||||
options?: {
|
||||
outputLen?: number;
|
||||
shakeLen?: number;
|
||||
}
|
||||
): ArrayBuffer;
|
||||
/**
|
||||
* Sets the HMAC key for an eventual `getHMAC` call. Must be called immediately after jsSHA object instantiation.
|
||||
*
|
||||
* @param key The key used to calculate the HMAC
|
||||
* @param inputFormat The format of key.
|
||||
* @param options Hashmap of extra input options.
|
||||
*/
|
||||
setHMACKey(
|
||||
key: string,
|
||||
inputFormat: 'TEXT',
|
||||
options?: {
|
||||
encoding?: EncodingType;
|
||||
}
|
||||
): void;
|
||||
setHMACKey(key: string, inputFormat: 'B64' | 'HEX' | 'BYTES'): void;
|
||||
setHMACKey(key: ArrayBuffer, inputFormat: 'ARRAYBUFFER'): void;
|
||||
setHMACKey(key: Uint8Array, inputFormat: 'UINT8ARRAY'): void;
|
||||
/**
|
||||
* Internal function that sets the MAC key.
|
||||
*
|
||||
* @param key The packed MAC key to use
|
||||
*/
|
||||
protected _setHMACKey(key: packedValue): void;
|
||||
/**
|
||||
* Returns the the HMAC in the specified format using the key given by a previous `setHMACKey` call.
|
||||
*
|
||||
* @param format The desired output formatting.
|
||||
* @param options Hashmap of extra outputs options.
|
||||
* @returns The HMAC in the format specified.
|
||||
*/
|
||||
getHMAC(
|
||||
format: 'HEX',
|
||||
options?: {
|
||||
outputUpper?: boolean;
|
||||
}
|
||||
): string;
|
||||
getHMAC(
|
||||
format: 'B64',
|
||||
options?: {
|
||||
b64Pad?: string;
|
||||
}
|
||||
): string;
|
||||
getHMAC(format: 'BYTES'): string;
|
||||
getHMAC(format: 'UINT8ARRAY'): Uint8Array;
|
||||
getHMAC(format: 'ARRAYBUFFER'): ArrayBuffer;
|
||||
/**
|
||||
* Internal function that returns the "raw" HMAC
|
||||
*/
|
||||
protected _getHMAC(): number[];
|
||||
}
|
||||
|
||||
declare type VariantType = 'SHA-224' | 'SHA-256';
|
||||
declare class jsSHA extends jsSHABase<number[], VariantType> {
|
||||
intermediateState: number[];
|
||||
variantBlockSize: number;
|
||||
bigEndianMod: -1 | 1;
|
||||
outputBinLen: number;
|
||||
isVariableLen: boolean;
|
||||
HMACSupported: boolean;
|
||||
converterFunc: (
|
||||
input: any,
|
||||
existingBin: number[],
|
||||
existingBinLen: number
|
||||
) => packedValue;
|
||||
roundFunc: (block: number[], H: number[]) => number[];
|
||||
finalizeFunc: (
|
||||
remainder: number[],
|
||||
remainderBinLen: number,
|
||||
processedBinLen: number,
|
||||
H: number[]
|
||||
) => number[];
|
||||
stateCloneFunc: (state: number[]) => number[];
|
||||
newStateFunc: (variant: VariantType) => number[];
|
||||
getMAC: () => number[];
|
||||
constructor(
|
||||
variant: VariantType,
|
||||
inputFormat: 'TEXT',
|
||||
options?: FixedLengthOptionsEncodingType
|
||||
);
|
||||
constructor(
|
||||
variant: VariantType,
|
||||
inputFormat: FormatNoTextType,
|
||||
options?: FixedLengthOptionsNoEncodingType
|
||||
);
|
||||
}
|
21
Extensions/Leaderboards/sha256.js
Normal file
21
Extensions/Leaderboards/sha256.js
Normal file
File diff suppressed because one or more lines are too long
68
Extensions/Leaderboards/tests/leaderboardstools.spec.js
Normal file
68
Extensions/Leaderboards/tests/leaderboardstools.spec.js
Normal file
@@ -0,0 +1,68 @@
|
||||
// @ts-check
|
||||
|
||||
describe('Leaderboards', () => {
|
||||
describe('formatPlayerName', () => {
|
||||
it('it returns name if correct', () => {
|
||||
expect(gdjs.evtTools.leaderboards.formatPlayerName('PlayerName')).to.be(
|
||||
'PlayerName'
|
||||
);
|
||||
});
|
||||
|
||||
it('it returns name with underscores instead of whitespaces except for leading and trailing ones that are removed', () => {
|
||||
expect(
|
||||
gdjs.evtTools.leaderboards.formatPlayerName('\tMy Player Name ')
|
||||
).to.be('My_Player_Name');
|
||||
});
|
||||
|
||||
it("it doesn't change a name with vertical bars and hyphens", () => {
|
||||
expect(gdjs.evtTools.leaderboards.formatPlayerName('Pla-yer|Name')).to.be(
|
||||
'Pla-yer|Name'
|
||||
);
|
||||
});
|
||||
|
||||
it('it truncates name if longer than 30', () => {
|
||||
expect(
|
||||
gdjs.evtTools.leaderboards.formatPlayerName(
|
||||
'aPlayerNameTh4tIsT00LongToBeSaved'
|
||||
)
|
||||
).to.be('aPlayerNameTh4tIsT00LongToBeSa');
|
||||
});
|
||||
|
||||
it('it generates a predefined player name with a random number if input is void/wrong type/empty', () => {
|
||||
// @ts-ignore
|
||||
expect(gdjs.evtTools.leaderboards.formatPlayerName(null)).to.match(
|
||||
/^Player\d{5}/
|
||||
);
|
||||
// @ts-ignore
|
||||
expect(gdjs.evtTools.leaderboards.formatPlayerName(5)).to.match(
|
||||
/^Player\d{5}/
|
||||
);
|
||||
// @ts-ignore
|
||||
expect(gdjs.evtTools.leaderboards.formatPlayerName(undefined)).to.match(
|
||||
/^Player\d{5}/
|
||||
);
|
||||
// @ts-ignore
|
||||
expect(gdjs.evtTools.leaderboards.formatPlayerName(() => {})).to.match(
|
||||
/^Player\d{5}/
|
||||
);
|
||||
// @ts-ignore
|
||||
expect(gdjs.evtTools.leaderboards.formatPlayerName('')).to.match(
|
||||
/^Player\d{5}/
|
||||
);
|
||||
});
|
||||
|
||||
it('it removes accents from latin letters', () => {
|
||||
expect(gdjs.evtTools.leaderboards.formatPlayerName('plâyèrÏonisé')).to.be(
|
||||
'playerIonise'
|
||||
);
|
||||
});
|
||||
|
||||
it('it removes non-accepted characters in a long name', () => {
|
||||
expect(
|
||||
gdjs.evtTools.leaderboards.formatPlayerName(
|
||||
'aPιΥÉᚱnÀⅯeThatᎥsTooⅬonᏀToBeՏaѵÊĐThisPartAppears'
|
||||
)
|
||||
).to.be('aEAeThatsTooonToBeaEThisPartAp');
|
||||
});
|
||||
});
|
||||
});
|
@@ -5,7 +5,6 @@ Copyright (c) 2012-2016 Victor Levasseur (victorlevasseur01@orange.fr)
|
||||
This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Project/InitialInstance.h"
|
||||
|
@@ -16,30 +16,30 @@ This project is released under the MIT License.
|
||||
*/
|
||||
void ExtensionSubDeclaration2(gd::ObjectMetadata& obj) {
|
||||
obj.AddAction("ParticleColor1",
|
||||
_("Initial color"),
|
||||
_("Modify initial color of particles."),
|
||||
_("Put initial color of particles of _PARAM0_ to _PARAM1_"),
|
||||
_("Start color"),
|
||||
_("Modify start color of particles."),
|
||||
_("Change particles start color of _PARAM0_ to _PARAM1_"),
|
||||
_("Common"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter")
|
||||
.AddParameter("color", _("Initial color"));
|
||||
.AddParameter("color", _("Start color"));
|
||||
|
||||
obj.AddAction("ParticleColor2",
|
||||
_("Final color"),
|
||||
_("Modify final color of particles."),
|
||||
_("Put final color of particles of _PARAM0_ to _PARAM1_"),
|
||||
_("End color"),
|
||||
_("Modify end color of particles."),
|
||||
_("Change particles end color of _PARAM0_ to _PARAM1_"),
|
||||
_("Common"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter")
|
||||
.AddParameter("color", _("Final color"));
|
||||
.AddParameter("color", _("End color"));
|
||||
|
||||
obj.AddAction(
|
||||
"ParticleRed1",
|
||||
_("Red color, parameter 1"),
|
||||
_("Modify parameter 1 of the red color."),
|
||||
_("the parameter 1 of red color"),
|
||||
_("Start color red component"),
|
||||
_("Modify the start color red component."),
|
||||
_("the start color red component"),
|
||||
_("Advanced"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
@@ -48,9 +48,9 @@ void ExtensionSubDeclaration2(gd::ObjectMetadata& obj) {
|
||||
|
||||
obj.AddCondition(
|
||||
"ParticleRed1",
|
||||
_("Red color, parameter 1"),
|
||||
_("Test parameter 1 of the red color"),
|
||||
_("the parameter 1 of red color"),
|
||||
_("Start color red component"),
|
||||
_("Compare the start color red component."),
|
||||
_("the start color red component"),
|
||||
_("Advanced"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
@@ -59,9 +59,9 @@ void ExtensionSubDeclaration2(gd::ObjectMetadata& obj) {
|
||||
|
||||
obj.AddAction(
|
||||
"ParticleRed2",
|
||||
_("Red color, parameter 2"),
|
||||
_("Modify parameter 2 of the red color"),
|
||||
_("the parameter 2 of red color"),
|
||||
_("End color red component"),
|
||||
_("Modify the end color red component."),
|
||||
_("the end color red component"),
|
||||
_("Advanced"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
@@ -70,9 +70,9 @@ void ExtensionSubDeclaration2(gd::ObjectMetadata& obj) {
|
||||
|
||||
obj.AddCondition(
|
||||
"ParticleRed2",
|
||||
_("Red color, parameter 2"),
|
||||
_("Test parameter 2 of the red color"),
|
||||
_("the parameter 2 of red color"),
|
||||
_("End color red component"),
|
||||
_("Compare the end color red component."),
|
||||
_("the end color red component"),
|
||||
_("Advanced"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
@@ -81,9 +81,9 @@ void ExtensionSubDeclaration2(gd::ObjectMetadata& obj) {
|
||||
|
||||
obj.AddAction(
|
||||
"ParticleBlue1",
|
||||
_("Blue color, parameter 1"),
|
||||
_("Modify parameter 1 of blue color"),
|
||||
_("the parameter 1 of blue color"),
|
||||
_("Start color blue component"),
|
||||
_("Modify the start color blue component."),
|
||||
_("the start color blue component"),
|
||||
_("Advanced"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
@@ -92,9 +92,9 @@ void ExtensionSubDeclaration2(gd::ObjectMetadata& obj) {
|
||||
|
||||
obj.AddCondition(
|
||||
"ParticleBlue1",
|
||||
_("Blue color, parameter 1"),
|
||||
_("Test parameter 1 of blue color"),
|
||||
_("the parameter 1 of blue color"),
|
||||
_("Start color blue component"),
|
||||
_("Compare the start color blue component."),
|
||||
_("the start color blue component"),
|
||||
_("Advanced"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
@@ -103,9 +103,9 @@ void ExtensionSubDeclaration2(gd::ObjectMetadata& obj) {
|
||||
|
||||
obj.AddAction(
|
||||
"ParticleBlue2",
|
||||
_("Blue color, parameter 2"),
|
||||
_("Modify parameter 2 of blue color"),
|
||||
_("the parameter 2 of blue color"),
|
||||
_("End color blue component"),
|
||||
_("Modify the end color blue component."),
|
||||
_("the end color blue component"),
|
||||
_("Advanced"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
@@ -114,9 +114,9 @@ void ExtensionSubDeclaration2(gd::ObjectMetadata& obj) {
|
||||
|
||||
obj.AddCondition(
|
||||
"ParticleBlue2",
|
||||
_("Blue color, parameter 2"),
|
||||
_("Test parameter 2 of blue color"),
|
||||
_("the parameter 2 of blue color"),
|
||||
_("End color blue component"),
|
||||
_("Compare the end color blue component."),
|
||||
_("the end color blue component"),
|
||||
_("Advanced"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
@@ -125,9 +125,9 @@ void ExtensionSubDeclaration2(gd::ObjectMetadata& obj) {
|
||||
|
||||
obj.AddAction(
|
||||
"ParticleGreen1",
|
||||
_("Green color, parameter 1"),
|
||||
_("Modify parameter 1 of green color"),
|
||||
_("the parameter 1 of green color"),
|
||||
_("Start color green component"),
|
||||
_("Modify the start color green component."),
|
||||
_("the start color green component"),
|
||||
_("Advanced"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
@@ -136,9 +136,9 @@ void ExtensionSubDeclaration2(gd::ObjectMetadata& obj) {
|
||||
|
||||
obj.AddCondition(
|
||||
"ParticleGreen1",
|
||||
_("Green color, parameter 1"),
|
||||
_("Test parameter 1 of green color"),
|
||||
_("the parameter 1 of green color"),
|
||||
_("Start color green component"),
|
||||
_("Compare the start color green component."),
|
||||
_("the start color green component"),
|
||||
_("Advanced"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
@@ -147,9 +147,9 @@ void ExtensionSubDeclaration2(gd::ObjectMetadata& obj) {
|
||||
|
||||
obj.AddAction(
|
||||
"ParticleGreen2",
|
||||
_("Green color, parameter 2"),
|
||||
_("Modify the parameter 2 of the green color"),
|
||||
_("the parameter 2 of green color"),
|
||||
_("End color green component"),
|
||||
_("Modify the end color green component."),
|
||||
_("the end color green component"),
|
||||
_("Advanced"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
@@ -158,9 +158,9 @@ void ExtensionSubDeclaration2(gd::ObjectMetadata& obj) {
|
||||
|
||||
obj.AddCondition(
|
||||
"ParticleGreen2",
|
||||
_("Green color, parameter 2"),
|
||||
_("Test the parameter 2 of the green color"),
|
||||
_("the parameter 2 of green color"),
|
||||
_("End color green component"),
|
||||
_("Compare the end color green component."),
|
||||
_("the end color green component"),
|
||||
_("Advanced"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
@@ -168,9 +168,9 @@ void ExtensionSubDeclaration2(gd::ObjectMetadata& obj) {
|
||||
.UseStandardRelationalOperatorParameters("number");
|
||||
|
||||
obj.AddAction("ParticleSize1",
|
||||
_("Size, parameter 1"),
|
||||
_("Modify parameter 1 of the size of particles"),
|
||||
_("the parameter 1 of size"),
|
||||
_("Start size"),
|
||||
_("Modify the particle start size."),
|
||||
_("the start size"),
|
||||
_("Common"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
@@ -178,9 +178,9 @@ void ExtensionSubDeclaration2(gd::ObjectMetadata& obj) {
|
||||
.UseStandardOperatorParameters("number");
|
||||
|
||||
obj.AddCondition("ParticleSize1",
|
||||
_("Size, parameter 1"),
|
||||
_("Test parameter 1 of the size of particles"),
|
||||
_("the parameter 1 of the size"),
|
||||
_("Start size"),
|
||||
_("Compare the particle start size."),
|
||||
_("the start size"),
|
||||
_("Common"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
@@ -188,9 +188,9 @@ void ExtensionSubDeclaration2(gd::ObjectMetadata& obj) {
|
||||
.UseStandardRelationalOperatorParameters("number");
|
||||
|
||||
obj.AddAction("ParticleSize2",
|
||||
_("Size, parameter 2"),
|
||||
_("Modify parameter 2 of the size of particles"),
|
||||
_("the parameter 2 of size"),
|
||||
_("End size"),
|
||||
_("Modify the particle end size."),
|
||||
_("the end size"),
|
||||
_("Common"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
@@ -198,9 +198,9 @@ void ExtensionSubDeclaration2(gd::ObjectMetadata& obj) {
|
||||
.UseStandardOperatorParameters("number");
|
||||
|
||||
obj.AddCondition("ParticleSize2",
|
||||
_("Size, parameter 2"),
|
||||
_("Test parameter 2 of the size of particles"),
|
||||
_("the parameter 2 of the size"),
|
||||
_("End size"),
|
||||
_("Compare the particle end size."),
|
||||
_("the end size"),
|
||||
_("Common"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
@@ -210,7 +210,7 @@ void ExtensionSubDeclaration2(gd::ObjectMetadata& obj) {
|
||||
obj.AddAction(
|
||||
"ParticleAngle1",
|
||||
_("Angle, parameter 1"),
|
||||
_("Modify parameter 1 of the angle of particles"),
|
||||
_("Modify parameter 1 of the angle of particles."),
|
||||
_("the parameter 1 of angle"),
|
||||
_("Common"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
@@ -220,7 +220,7 @@ void ExtensionSubDeclaration2(gd::ObjectMetadata& obj) {
|
||||
|
||||
obj.AddCondition("ParticleAngle1",
|
||||
_("Angle, parameter 1"),
|
||||
_("Test parameter 1 of the angle of particles"),
|
||||
_("Compare parameter 1 of the angle of particles."),
|
||||
_("the parameter 1 of angle"),
|
||||
_("Common"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
@@ -241,7 +241,7 @@ void ExtensionSubDeclaration2(gd::ObjectMetadata& obj) {
|
||||
|
||||
obj.AddCondition("ParticleAngle2",
|
||||
_("Angle, parameter 2"),
|
||||
_("Test parameter 2 of the angle of particles"),
|
||||
_("Compare parameter 2 of the angle of particles."),
|
||||
_("the parameter 2 of angle"),
|
||||
_("Common"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
@@ -250,9 +250,9 @@ void ExtensionSubDeclaration2(gd::ObjectMetadata& obj) {
|
||||
.UseStandardRelationalOperatorParameters("number");
|
||||
|
||||
obj.AddAction("ParticleAlpha1",
|
||||
_("Transparency, parameter 1"),
|
||||
_("Modify parameter 1 of the transparency of particles"),
|
||||
_("the parameter 1 of the transparency"),
|
||||
_("Start opacity"),
|
||||
_("Modify the start opacity of particles."),
|
||||
_("the start opacity"),
|
||||
_("Common"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
@@ -261,9 +261,9 @@ void ExtensionSubDeclaration2(gd::ObjectMetadata& obj) {
|
||||
|
||||
obj.AddCondition(
|
||||
"ParticleAlpha1",
|
||||
_("Transparency, parameter 1"),
|
||||
_("Test parameter 1 of the transparency of particles"),
|
||||
_("the parameter 1 of the transparency"),
|
||||
_("Start opacity"),
|
||||
_("Compare the start opacity of particles."),
|
||||
_("the start opacity"),
|
||||
_("Common"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
@@ -271,9 +271,9 @@ void ExtensionSubDeclaration2(gd::ObjectMetadata& obj) {
|
||||
.UseStandardRelationalOperatorParameters("number");
|
||||
|
||||
obj.AddAction("ParticleAlpha2",
|
||||
_("Transparency, parameter 2"),
|
||||
_("Modify parameter 2 of the transparency of particles"),
|
||||
_("the parameter 2 of the transparency"),
|
||||
_("End opacity"),
|
||||
_("Modify the end opacity of particles."),
|
||||
_("the end opacity"),
|
||||
_("Common"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
@@ -282,9 +282,9 @@ void ExtensionSubDeclaration2(gd::ObjectMetadata& obj) {
|
||||
|
||||
obj.AddCondition(
|
||||
"ParticleAlpha2",
|
||||
_("Transparency, parameter 2"),
|
||||
_("Test parameter 2 of the transparency of particles"),
|
||||
_("the parameter 2 of the transparency"),
|
||||
_("Start opacity"),
|
||||
_("Compare the end opacity of particles."),
|
||||
_("the end opacity"),
|
||||
_("Common"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
|
@@ -28,7 +28,7 @@ void ExtensionSubDeclaration3(gd::ObjectMetadata& obj) {
|
||||
obj.AddAction(
|
||||
"RendererParam1",
|
||||
_("Rendering first parameter"),
|
||||
_("Modify first parameter of rendering ( Size/Length ).\nParticles "
|
||||
_("Modify first parameter of rendering (Size/Length).\nParticles "
|
||||
"have to be recreated in order to take changes in account."),
|
||||
_("the rendering 1st parameter"),
|
||||
_("Setup"),
|
||||
@@ -40,7 +40,7 @@ void ExtensionSubDeclaration3(gd::ObjectMetadata& obj) {
|
||||
obj.AddCondition(
|
||||
"RendererParam1",
|
||||
_("Rendering first parameter"),
|
||||
_("Test the first parameter of rendering ( Size/Length )."),
|
||||
_("Test the first parameter of rendering (Size/Length)."),
|
||||
_("the 1st rendering parameter"),
|
||||
_("Setup"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
@@ -51,7 +51,7 @@ void ExtensionSubDeclaration3(gd::ObjectMetadata& obj) {
|
||||
|
||||
obj.AddAction("RendererParam2",
|
||||
_("Rendering second parameter"),
|
||||
_("Modify the second parameter of rendering ( Size/Length "
|
||||
_("Modify the second parameter of rendering (Size/Length"
|
||||
").\nParticles have to be recreated in order to take changes "
|
||||
"in account."),
|
||||
_("the rendering 2nd parameter"),
|
||||
@@ -64,7 +64,7 @@ void ExtensionSubDeclaration3(gd::ObjectMetadata& obj) {
|
||||
obj.AddCondition(
|
||||
"RendererParam2",
|
||||
_("Rendering second parameter"),
|
||||
_("Test the second parameter of rendering ( Size/Length )."),
|
||||
_("Test the second parameter of rendering (Size/Length)."),
|
||||
_("the 2nd rendering parameter"),
|
||||
_("Setup"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
@@ -135,14 +135,25 @@ void ExtensionSubDeclaration3(gd::ObjectMetadata& obj) {
|
||||
.UseStandardRelationalOperatorParameters("number");
|
||||
|
||||
obj.AddAction("Texture",
|
||||
_("Image"),
|
||||
_("Change the image of particles ( if displayed )."),
|
||||
_("Change image (using an expression)"),
|
||||
_("Change the image of particles (if displayed)."),
|
||||
_("Change the image of particles of _PARAM0_ to _PARAM1_"),
|
||||
_("Advanced"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter")
|
||||
.AddParameter("string", _("Image to use"))
|
||||
.SetParameterLongDescription("Indicate the name of the resource");
|
||||
|
||||
obj.AddAction("SetTextureFromResource",
|
||||
_("Change image"),
|
||||
_("Change the image of particles (if displayed)."),
|
||||
_("Change the image of particles of _PARAM0_ to _PARAM1_"),
|
||||
_("Common"),
|
||||
"CppPlatform/Extensions/particleSystemicon24.png",
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter")
|
||||
.AddParameter("string", _("New image"));
|
||||
.AddParameter("imageResource", _("Image file (or image resource name)"));
|
||||
|
||||
obj.AddCondition(
|
||||
"Texture",
|
||||
@@ -157,7 +168,7 @@ void ExtensionSubDeclaration3(gd::ObjectMetadata& obj) {
|
||||
|
||||
obj.AddStrExpression("Texture",
|
||||
_("Particles image"),
|
||||
_("Name of the image displayed by particles"),
|
||||
_("Name of the image displayed by particles."),
|
||||
_("Particles"),
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter", false);
|
||||
@@ -172,7 +183,7 @@ void ExtensionSubDeclaration3(gd::ObjectMetadata& obj) {
|
||||
|
||||
obj.AddExpression("CurrentParticleCount",
|
||||
_("Particles count"),
|
||||
_("Number of particles currently displayed"),
|
||||
_("Number of particles currently displayed."),
|
||||
_("Particles"),
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter", false);
|
||||
@@ -193,35 +204,35 @@ void ExtensionSubDeclaration3(gd::ObjectMetadata& obj) {
|
||||
|
||||
obj.AddExpression("Tank",
|
||||
_("Capacity"),
|
||||
_("Capacity"),
|
||||
_("Capacity of the particle tank."),
|
||||
_("Common"),
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter", false);
|
||||
|
||||
obj.AddExpression("Flow",
|
||||
_("Flow"),
|
||||
_("Flow"),
|
||||
_("Flow of the particles (particles/second)."),
|
||||
_("Common"),
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter", false);
|
||||
|
||||
obj.AddExpression("EmitterForceMin",
|
||||
_("Emission minimal force"),
|
||||
_("Emission minimal force"),
|
||||
_("The minimal emission force of the particles."),
|
||||
_("Common"),
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter", false);
|
||||
|
||||
obj.AddExpression("EmitterForceMax",
|
||||
_("Emission maximal force"),
|
||||
_("Emission maximal force"),
|
||||
_("The maximal emission force of the particles."),
|
||||
_("Common"),
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter", false);
|
||||
|
||||
obj.AddExpression("EmitterAngle",
|
||||
_("Emission angle"),
|
||||
_("Emission angle"),
|
||||
_("Emission angle of the particles."),
|
||||
_("Common"),
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter", false);
|
||||
@@ -238,104 +249,104 @@ void ExtensionSubDeclaration3(gd::ObjectMetadata& obj) {
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter", false);
|
||||
obj.AddExpression("ZoneRadius",
|
||||
_("Radius of the emission zone"),
|
||||
_("Radius of the emission zone"),
|
||||
_("Radius of emission zone"),
|
||||
_("The radius of the emission zone."),
|
||||
_("Common"),
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter", false);
|
||||
obj.AddExpression("ParticleGravityX",
|
||||
_("X Gravity of particles"),
|
||||
_("X Gravity of particles"),
|
||||
_("X gravity"),
|
||||
_("Gravity of particles applied on X-axis."),
|
||||
_("Setup"),
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter", false);
|
||||
obj.AddExpression("ParticleGravityY",
|
||||
_("Y Gravity of particles"),
|
||||
_("Y Gravity of particles"),
|
||||
_("Y gravity"),
|
||||
_("Gravity of particles applied on Y-axis."),
|
||||
_("Setup"),
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter", false);
|
||||
obj.AddExpression("ParticleGravityAngle",
|
||||
_("Gravity angle"),
|
||||
_("Gravity angle"),
|
||||
_("Angle of gravity."),
|
||||
_("Common"),
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter", false);
|
||||
obj.AddExpression("ParticleGravityLength",
|
||||
_("Gravity"),
|
||||
_("Gravity value"),
|
||||
_("Value of gravity."),
|
||||
_("Common"),
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter", false);
|
||||
obj.AddExpression("ParticleLifeTimeMin",
|
||||
_("Minimum lifetime of particles"),
|
||||
_("Minimum lifetime of particles"),
|
||||
_("Minimum lifetime of the particles."),
|
||||
_("Setup"),
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter", false);
|
||||
obj.AddExpression("ParticleLifeTimeMax",
|
||||
_("Maximum lifetime of particles"),
|
||||
_("Maximum lifetime of particles"),
|
||||
_("Maximum lifetime of the particles."),
|
||||
_("Setup"),
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter", false);
|
||||
obj.AddExpression("ParticleRed1",
|
||||
_("Parameter 1 of red color"),
|
||||
_("Parameter 1 of red color"),
|
||||
_("Start color red component"),
|
||||
_("The start color red component of the particles."),
|
||||
_("Setup"),
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter", false);
|
||||
obj.AddExpression("ParticleRed2",
|
||||
_("Parameter 2 of red color"),
|
||||
_("Parameter 2 of red color"),
|
||||
_("End color red component"),
|
||||
_("The end color red component of the particles."),
|
||||
_("Setup"),
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter", false);
|
||||
obj.AddExpression("ParticleBlue1",
|
||||
_("Parameter 1 of blue color"),
|
||||
_("Parameter 1 of blue color"),
|
||||
_("Start color blue component"),
|
||||
_("The start color blue component of the particles."),
|
||||
_("Setup"),
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter", false);
|
||||
obj.AddExpression("ParticleBlue2",
|
||||
_("Parameter 2 of blue color"),
|
||||
_("Parameter 2 of blue color"),
|
||||
_("End color blue component"),
|
||||
_("The end color blue component of the particles."),
|
||||
_("Setup"),
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter", false);
|
||||
obj.AddExpression("ParticleGreen1",
|
||||
_("Parameter 1 of green color"),
|
||||
_("Parameter 1 of green color"),
|
||||
_("Start color green component"),
|
||||
_("The start color green component of the particles."),
|
||||
_("Setup"),
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter", false);
|
||||
obj.AddExpression("ParticleGreen2",
|
||||
_("Parameter 2 of green color"),
|
||||
_("Parameter 2 of green color"),
|
||||
_("End color green component"),
|
||||
_("The end color green component of the particles."),
|
||||
_("Setup"),
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter", false);
|
||||
obj.AddExpression("ParticleAlpha1",
|
||||
_("Parameter 1 of transparency"),
|
||||
_("Parameter 1 of transparency"),
|
||||
_("Start opacity"),
|
||||
_("Start opacity of the particles."),
|
||||
_("Setup"),
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter", false);
|
||||
obj.AddExpression("ParticleAlpha2",
|
||||
_("Parameter 2 of transparency"),
|
||||
_("Parameter 2 of transparency"),
|
||||
_("End opacity"),
|
||||
_("End opacity of the particles."),
|
||||
_("Setup"),
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter", false);
|
||||
obj.AddExpression("ParticleSize1",
|
||||
_("Parameter 1 of size"),
|
||||
_("Parameter 1 of size"),
|
||||
_("Start size"),
|
||||
_("Start size of particles."),
|
||||
_("Setup"),
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter", false);
|
||||
obj.AddExpression("ParticleSize2",
|
||||
_("Parameter 2 of size"),
|
||||
_("Parameter 2 of size"),
|
||||
_("End size"),
|
||||
_("End size of particles."),
|
||||
_("Setup"),
|
||||
"CppPlatform/Extensions/particleSystemicon16.png")
|
||||
.AddParameter("object", _("Object"), "ParticleEmitter", false);
|
||||
|
@@ -169,6 +169,10 @@ class ParticleSystemJsExtension : public gd::PlatformExtension {
|
||||
actions["ParticleSystem::Flow"].SetFunctionName("setFlow").SetGetter(
|
||||
"getFlow");
|
||||
conditions["ParticleSystem::Flow"].SetFunctionName("getFlow");
|
||||
actions["ParticleSystem::SetTextureFromResource"]
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.SetFunctionName("setTexture")
|
||||
.SetGetter("getTexture");
|
||||
actions["ParticleSystem::Texture"]
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.SetFunctionName("setTexture")
|
||||
|
@@ -7,7 +7,7 @@ This project is released under the MIT License.
|
||||
|
||||
#ifndef PATHFINDINGBEHAVIOR_H
|
||||
#define PATHFINDINGBEHAVIOR_H
|
||||
#include <SFML/System/Vector2.hpp>
|
||||
#include "GDCore/Vector2.h"
|
||||
#include <vector>
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
|
@@ -33,7 +33,7 @@ void PhysicsBehavior::InitializeContent(
|
||||
behaviorContent.SetAttribute("polygonWidth", 200);
|
||||
behaviorContent.SetAttribute("polygonHeight", 200);
|
||||
|
||||
std::vector<sf::Vector2f> polygonCoords;
|
||||
std::vector<gd::Vector2f> polygonCoords;
|
||||
behaviorContent.SetAttribute(
|
||||
"coordsList",
|
||||
PhysicsBehavior::GetStringFromCoordsVector(polygonCoords, '/', ';'));
|
||||
@@ -128,7 +128,7 @@ bool PhysicsBehavior::UpdateProperty(gd::SerializerElement &behaviorContent,
|
||||
#endif
|
||||
|
||||
gd::String PhysicsBehavior::GetStringFromCoordsVector(
|
||||
const std::vector<sf::Vector2f> &vec,
|
||||
const std::vector<gd::Vector2f> &vec,
|
||||
char32_t coordsSep,
|
||||
char32_t composantSep) {
|
||||
gd::String coordsStr;
|
||||
|
@@ -13,7 +13,7 @@ This project is released under the MIT License.
|
||||
#include <vector>
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "SFML/System/Vector2.hpp"
|
||||
#include "GDCore/Vector2.h"
|
||||
namespace gd {
|
||||
class Project;
|
||||
class SerializerElement;
|
||||
@@ -43,7 +43,7 @@ class GD_EXTENSION_API PhysicsBehavior : public gd::Behavior {
|
||||
gd::SerializerElement &behaviorContent) override;
|
||||
|
||||
private:
|
||||
gd::String GetStringFromCoordsVector(const std::vector<sf::Vector2f> &vec,
|
||||
gd::String GetStringFromCoordsVector(const std::vector<gd::Vector2f> &vec,
|
||||
char32_t coordsSep,
|
||||
char32_t composantSep);
|
||||
enum ShapeType {
|
||||
|
@@ -11,9 +11,8 @@ namespace gdjs {
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
savePath: string
|
||||
) {
|
||||
const electron = runtimeScene.getGame().getRenderer().getElectron();
|
||||
if (electron) {
|
||||
const fileSystem = electron.remote.require('fs');
|
||||
const fs = typeof require !== 'undefined' ? require('fs') : null;
|
||||
if (fs) {
|
||||
const canvas = runtimeScene.getGame().getRenderer().getCanvas();
|
||||
if (canvas) {
|
||||
const content = canvas
|
||||
@@ -22,7 +21,7 @@ namespace gdjs {
|
||||
if (savePath.toLowerCase().indexOf('.png') == -1) {
|
||||
savePath += '.png';
|
||||
}
|
||||
fileSystem.writeFile(savePath, content, 'base64', (err) => {
|
||||
fs.writeFile(savePath, content, 'base64', (err) => {
|
||||
if (err) {
|
||||
logger.error(
|
||||
'Unable to save the screenshot at path: ' + savePath
|
||||
|
@@ -4,7 +4,6 @@ cmake_policy(SET CMP0015 NEW)
|
||||
project(GDJS)
|
||||
#Dependencies on external libraries:
|
||||
###
|
||||
include_directories(${sfml_include_dir})
|
||||
include_directories(${GDCORE_include_dir})
|
||||
|
||||
#Defines
|
||||
@@ -75,5 +74,4 @@ IF(EMSCRIPTEN)
|
||||
#Nothing.
|
||||
ELSE()
|
||||
target_link_libraries(GDJS GDCore)
|
||||
target_link_libraries(GDJS ${sfml_LIBRARIES})
|
||||
ENDIF()
|
||||
|
@@ -18,8 +18,8 @@
|
||||
#include "GDCore/IDE/EventsFunctionTools.h"
|
||||
#include "GDCore/IDE/SceneNameMangler.h"
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/EventsFunction.h"
|
||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||
#include "GDCore/Project/EventsFunction.h"
|
||||
#include "GDCore/Project/ExternalEvents.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
@@ -83,7 +83,7 @@ gd::String EventsCodeGenerator::GenerateEventsListCompleteFunctionCode(
|
||||
wholeEventsCode + "\n" +
|
||||
functionReturnCode + "\n" +
|
||||
"}\n";
|
||||
// clang-format on
|
||||
// clang-format on
|
||||
|
||||
return output;
|
||||
}
|
||||
@@ -233,7 +233,11 @@ gd::String EventsCodeGenerator::GenerateFreeEventsFunctionContext(
|
||||
gd::String objectsGettersMap;
|
||||
gd::String objectArraysMap;
|
||||
gd::String behaviorNamesMap;
|
||||
return GenerateEventsFunctionContext(parameters, onceTriggersVariable, objectsGettersMap, objectArraysMap, behaviorNamesMap);
|
||||
return GenerateEventsFunctionContext(parameters,
|
||||
onceTriggersVariable,
|
||||
objectsGettersMap,
|
||||
objectArraysMap,
|
||||
behaviorNamesMap);
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateBehaviorEventsFunctionContext(
|
||||
@@ -260,35 +264,38 @@ gd::String EventsCodeGenerator::GenerateBehaviorEventsFunctionContext(
|
||||
}
|
||||
|
||||
if (!thisBehaviorName.empty()) {
|
||||
// If we have a behavior considered as the current behavior ("this") (usually
|
||||
// called Behavior in behavior events function), generate a slightly more
|
||||
// optimized getter for it.
|
||||
// If we have a behavior considered as the current behavior ("this")
|
||||
// (usually called Behavior in behavior events function), generate a
|
||||
// slightly more optimized getter for it.
|
||||
behaviorNamesMap += ConvertToStringExplicit(thisBehaviorName) + ": " +
|
||||
thisBehaviorName + "\n";
|
||||
|
||||
// Add required behaviors from properties
|
||||
for (size_t i = 0; i < eventsBasedBehavior.GetPropertyDescriptors().GetCount(); i++)
|
||||
{
|
||||
const gd::NamedPropertyDescriptor& propertyDescriptor = eventsBasedBehavior.GetPropertyDescriptors().Get(i);
|
||||
const std::vector<gd::String>& extraInfo = propertyDescriptor.GetExtraInfo();
|
||||
for (size_t i = 0;
|
||||
i < eventsBasedBehavior.GetPropertyDescriptors().GetCount();
|
||||
i++) {
|
||||
const gd::NamedPropertyDescriptor& propertyDescriptor =
|
||||
eventsBasedBehavior.GetPropertyDescriptors().Get(i);
|
||||
const std::vector<gd::String>& extraInfo =
|
||||
propertyDescriptor.GetExtraInfo();
|
||||
if (propertyDescriptor.GetType() == "Behavior") {
|
||||
// Generate map that will be used to transform from behavior name used in
|
||||
// function to the "real" behavior name from the caller.
|
||||
// Generate map that will be used to transform from behavior name used
|
||||
// in function to the "real" behavior name from the caller.
|
||||
gd::String comma = behaviorNamesMap.empty() ? "" : ", ";
|
||||
behaviorNamesMap += comma + ConvertToStringExplicit(propertyDescriptor.GetName()) +
|
||||
": this._get" + propertyDescriptor.GetName() + "()\n";
|
||||
behaviorNamesMap +=
|
||||
comma + ConvertToStringExplicit(propertyDescriptor.GetName()) +
|
||||
": this._get" + propertyDescriptor.GetName() + "()\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return GenerateEventsFunctionContext(
|
||||
parameters,
|
||||
onceTriggersVariable,
|
||||
objectsGettersMap,
|
||||
objectArraysMap,
|
||||
behaviorNamesMap,
|
||||
thisObjectName,
|
||||
thisBehaviorName);
|
||||
return GenerateEventsFunctionContext(parameters,
|
||||
onceTriggersVariable,
|
||||
objectsGettersMap,
|
||||
objectArraysMap,
|
||||
behaviorNamesMap,
|
||||
thisObjectName,
|
||||
thisBehaviorName);
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateEventsFunctionContext(
|
||||
@@ -384,7 +391,7 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionContext(
|
||||
// to create the new object as the object names used in the function
|
||||
// are not the same as the objects available in the scene.
|
||||
" createObject: function(objectName) {\n"
|
||||
" var objectsList = "
|
||||
" const objectsList = "
|
||||
"eventsFunctionContext._objectsMap[objectName];\n" +
|
||||
// TODO: we could speed this up by storing a map of object names, but
|
||||
// the cost of creating/storing it for each events function might not
|
||||
@@ -398,13 +405,27 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionContext(
|
||||
// Add the new instance to object lists
|
||||
" if (object) {\n" +
|
||||
" objectsList.get(objectsList.firstKey()).push(object);\n" +
|
||||
" eventsFunctionContext._objectArraysMap[objectName].push(object);\n" +
|
||||
" }\n" +
|
||||
" return object;" +
|
||||
" }\n" +
|
||||
" "
|
||||
"eventsFunctionContext._objectArraysMap[objectName].push(object);\n" +
|
||||
" }\n" + " return object;" + " }\n" +
|
||||
// Unknown object, don't create anything:
|
||||
" return null;\n" +
|
||||
" },\n"
|
||||
// Function to count instances on the scene. We need it here because
|
||||
// it needs the objects map to get the object names of the parent context.
|
||||
" getInstancesCountOnScene: function(objectName) {\n"
|
||||
" const objectsList = "
|
||||
"eventsFunctionContext._objectsMap[objectName];\n" +
|
||||
" let count = 0;\n" +
|
||||
" if (objectsList) {\n" +
|
||||
" for(const objectName in objectsList.items)\n" +
|
||||
" count += parentEventsFunctionContext ?\n" +
|
||||
"parentEventsFunctionContext.getInstancesCountOnScene(objectName) "
|
||||
":\n" +
|
||||
" runtimeScene.getInstancesCountOnScene(objectName);\n" +
|
||||
" }\n" +
|
||||
" return count;\n" +
|
||||
" },\n"
|
||||
// Allow to get a layer directly from the context for convenience:
|
||||
" getLayer: function(layerName) {\n"
|
||||
" return runtimeScene.getLayer(layerName);\n"
|
||||
@@ -664,7 +685,8 @@ gd::String EventsCodeGenerator::GenerateObjectAction(
|
||||
const gd::ObjectMetadata& objInfo,
|
||||
const std::vector<gd::String>& arguments,
|
||||
const gd::InstructionMetadata& instrInfos,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
gd::EventsCodeGenerationContext& context,
|
||||
const gd::String& optionalAsyncCallbackName) {
|
||||
gd::String actionCode;
|
||||
|
||||
// Prepare call
|
||||
@@ -701,12 +723,23 @@ gd::String EventsCodeGenerator::GenerateObjectAction(
|
||||
GenerateArgumentsList(arguments, 1) + ")";
|
||||
}
|
||||
|
||||
if (!optionalAsyncCallbackName.empty()) {
|
||||
actionCode += "{\nconst asyncTaskGroup = new gdjs.TaskGroup();\n";
|
||||
call = "asyncTaskGroup.addTask(" + call + ")";
|
||||
}
|
||||
|
||||
actionCode +=
|
||||
"for(var i = 0, len = " + GetObjectListName(objectName, context) +
|
||||
".length ;i < len;++i) {\n";
|
||||
actionCode += " " + call + ";\n";
|
||||
actionCode += "}\n";
|
||||
|
||||
if (!optionalAsyncCallbackName.empty()) {
|
||||
actionCode +=
|
||||
"runtimeScene.getAsyncTasksManager().addTask(asyncTaskGroup, " +
|
||||
optionalAsyncCallbackName + ")\n}";
|
||||
}
|
||||
|
||||
return actionCode;
|
||||
}
|
||||
|
||||
@@ -716,7 +749,8 @@ gd::String EventsCodeGenerator::GenerateBehaviorAction(
|
||||
const gd::BehaviorMetadata& autoInfo,
|
||||
const std::vector<gd::String>& arguments,
|
||||
const gd::InstructionMetadata& instrInfos,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
gd::EventsCodeGenerationContext& context,
|
||||
const gd::String& optionalAsyncCallbackName) {
|
||||
gd::String actionCode;
|
||||
|
||||
// Prepare call
|
||||
@@ -764,11 +798,22 @@ gd::String EventsCodeGenerator::GenerateBehaviorAction(
|
||||
<< "\" requested for object \'" << objectName
|
||||
<< "\" (action: " << instrInfos.GetFullName() << ")." << endl;
|
||||
} else {
|
||||
if (!optionalAsyncCallbackName.empty()) {
|
||||
actionCode += "{\n const asyncTaskGroup = new gdjs.TaskGroup();\n";
|
||||
call = "asyncTaskGroup.addTask(" + call + ")";
|
||||
}
|
||||
|
||||
actionCode +=
|
||||
"for(var i = 0, len = " + GetObjectListName(objectName, context) +
|
||||
".length ;i < len;++i) {\n";
|
||||
actionCode += " " + call + ";\n";
|
||||
actionCode += "}\n";
|
||||
|
||||
if (!optionalAsyncCallbackName.empty()) {
|
||||
actionCode +=
|
||||
"runtimeScene.getAsyncTasksManager().addTask(asyncTaskGroup, " +
|
||||
optionalAsyncCallbackName + ");\n };";
|
||||
}
|
||||
}
|
||||
|
||||
return actionCode;
|
||||
@@ -792,7 +837,7 @@ gd::String EventsCodeGenerator::GenerateGetBehaviorNameCode(
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateObjectsDeclarationCode(
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
auto declareObjectList = [this](gd::String object,
|
||||
auto declareObjectListFromParent = [this](gd::String object,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
gd::String objectListName = GetObjectListName(object, context);
|
||||
if (!context.GetParentContext()) {
|
||||
@@ -802,6 +847,11 @@ gd::String EventsCodeGenerator::GenerateObjectsDeclarationCode(
|
||||
return "/* Could not declare " + objectListName + " */";
|
||||
}
|
||||
|
||||
if (context.ShouldUseAsyncObjectsList(object)) {
|
||||
gd::String copiedListName = "asyncObjectsList.getObjects(" + ConvertToStringExplicit(object) + ")";
|
||||
return "gdjs.copyArray(" + copiedListName + ", " + objectListName + ");\n";
|
||||
}
|
||||
|
||||
//*Optimization*: Avoid expensive copy of the object list if we're using
|
||||
// the same list as the one from the parent context.
|
||||
if (context.IsSameObjectsList(object, *context.GetParentContext()))
|
||||
@@ -815,33 +865,30 @@ gd::String EventsCodeGenerator::GenerateObjectsDeclarationCode(
|
||||
gd::String declarationsCode;
|
||||
for (auto object : context.GetObjectsListsToBeDeclared()) {
|
||||
gd::String objectListDeclaration = "";
|
||||
if (!context.ObjectAlreadyDeclared(object)) {
|
||||
if (!context.ObjectAlreadyDeclaredByParents(object)) {
|
||||
objectListDeclaration += "gdjs.copyArray(" +
|
||||
GenerateAllInstancesGetterCode(object) + ", " +
|
||||
GetObjectListName(object, context) + ");";
|
||||
context.SetObjectDeclared(object);
|
||||
GenerateAllInstancesGetterCode(object, context) +
|
||||
", " + GetObjectListName(object, context) + ");";
|
||||
} else
|
||||
objectListDeclaration = declareObjectList(object, context);
|
||||
objectListDeclaration = declareObjectListFromParent(object, context);
|
||||
|
||||
declarationsCode += objectListDeclaration + "\n";
|
||||
}
|
||||
for (auto object : context.GetObjectsListsToBeDeclaredWithoutPicking()) {
|
||||
for (auto object : context.GetObjectsListsToBeEmptyIfJustDeclared()) {
|
||||
gd::String objectListDeclaration = "";
|
||||
if (!context.ObjectAlreadyDeclared(object)) {
|
||||
if (!context.ObjectAlreadyDeclaredByParents(object)) {
|
||||
objectListDeclaration =
|
||||
GetObjectListName(object, context) + ".length = 0;\n";
|
||||
context.SetObjectDeclared(object);
|
||||
} else
|
||||
objectListDeclaration = declareObjectList(object, context);
|
||||
objectListDeclaration = declareObjectListFromParent(object, context);
|
||||
|
||||
declarationsCode += objectListDeclaration + "\n";
|
||||
}
|
||||
for (auto object : context.GetObjectsListsToBeDeclaredEmpty()) {
|
||||
gd::String objectListDeclaration = "";
|
||||
if (!context.ObjectAlreadyDeclared(object)) {
|
||||
if (!context.ObjectAlreadyDeclaredByParents(object)) {
|
||||
objectListDeclaration =
|
||||
GetObjectListName(object, context) + ".length = 0;\n";
|
||||
context.SetObjectDeclared(object);
|
||||
} else
|
||||
objectListDeclaration =
|
||||
GetObjectListName(object, context) + ".length = 0;\n";
|
||||
@@ -853,7 +900,7 @@ gd::String EventsCodeGenerator::GenerateObjectsDeclarationCode(
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateAllInstancesGetterCode(
|
||||
gd::String& objectName) {
|
||||
const gd::String& objectName, gd::EventsCodeGenerationContext& context) {
|
||||
if (HasProjectAndLayout()) {
|
||||
return "runtimeScene.getObjects(" + ConvertToStringExplicit(objectName) +
|
||||
")";
|
||||
@@ -864,7 +911,7 @@ gd::String EventsCodeGenerator::GenerateAllInstancesGetterCode(
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateEventsListCode(
|
||||
gd::EventsList& events, const gd::EventsCodeGenerationContext& context) {
|
||||
gd::EventsList& events, gd::EventsCodeGenerationContext& context) {
|
||||
// *Optimization*: generating all JS code of events in a single, enormous
|
||||
// function is badly handled by JS engines and in particular the garbage
|
||||
// collectors, leading to intermittent lag/freeze while the garbage collector
|
||||
@@ -875,9 +922,7 @@ gd::String EventsCodeGenerator::GenerateEventsListCode(
|
||||
gd::String code =
|
||||
gd::EventsCodeGenerator::GenerateEventsListCode(events, context);
|
||||
|
||||
gd::String parametersCode = HasProjectAndLayout()
|
||||
? "runtimeScene"
|
||||
: "runtimeScene, eventsFunctionContext";
|
||||
gd::String parametersCode = GenerateEventsParameters(context);
|
||||
|
||||
// Generate a unique name for the function.
|
||||
gd::String uniqueId =
|
||||
@@ -979,12 +1024,16 @@ gd::String EventsCodeGenerator::GenerateObject(
|
||||
// avoid re-creating them at runtime. Arrays are passed as reference in JS and
|
||||
// we always use the same static arrays, making this possible.
|
||||
auto declareMapOfObjects =
|
||||
[this](const std::vector<gd::String>& objects,
|
||||
const gd::EventsCodeGenerationContext& context) {
|
||||
[this](const std::vector<gd::String>& declaredObjectNames,
|
||||
const gd::EventsCodeGenerationContext& context,
|
||||
const std::vector<gd::String>& notDeclaredObjectNames = {}) {
|
||||
// The map name must be unique for each set of objects lists.
|
||||
// We generate it from the objects lists names.
|
||||
gd::String objectsMapName = GetCodeNamespaceAccessor() + "mapOf";
|
||||
gd::String mapDeclaration;
|
||||
for (auto& objectName : objects) {
|
||||
// The map name must be unique for each set of objects lists.
|
||||
|
||||
// Map each declared object to its list.
|
||||
for (auto& objectName : declaredObjectNames) {
|
||||
objectsMapName +=
|
||||
ManObjListName(GetObjectListName(objectName, context));
|
||||
|
||||
@@ -993,8 +1042,20 @@ gd::String EventsCodeGenerator::GenerateObject(
|
||||
"\": " + GetObjectListName(objectName, context);
|
||||
}
|
||||
|
||||
// Map each object not declared to an empty list.
|
||||
// Useful for parameters willing to get objects lists without
|
||||
// picking the objects for future instructions.
|
||||
for (auto& objectName : notDeclaredObjectNames) {
|
||||
objectsMapName += "Empty" + ManObjListName(objectName);
|
||||
|
||||
if (!mapDeclaration.empty()) mapDeclaration += ", ";
|
||||
mapDeclaration += "\"" + ConvertToString(objectName) +
|
||||
"\": []";
|
||||
}
|
||||
|
||||
// TODO: this should be de-duplicated.
|
||||
AddCustomCodeOutsideMain(objectsMapName + " = Hashtable.newFrom({" +
|
||||
mapDeclaration + "});");
|
||||
mapDeclaration + "});\n");
|
||||
return objectsMapName;
|
||||
};
|
||||
|
||||
@@ -1006,14 +1067,32 @@ gd::String EventsCodeGenerator::GenerateObject(
|
||||
|
||||
gd::String objectsMapName = declareMapOfObjects(realObjects, context);
|
||||
output = objectsMapName;
|
||||
} else if (type == "objectListWithoutPicking") {
|
||||
} else if (type == "objectListOrEmptyIfJustDeclared") {
|
||||
std::vector<gd::String> realObjects =
|
||||
ExpandObjectsName(objectName, context);
|
||||
for (auto& objectName : realObjects)
|
||||
context.ObjectsListWithoutPickingNeeded(objectName);
|
||||
context.ObjectsListNeededOrEmptyIfJustDeclared(objectName);
|
||||
|
||||
gd::String objectsMapName = declareMapOfObjects(realObjects, context);
|
||||
output = objectsMapName;
|
||||
} else if (type == "objectListOrEmptyWithoutPicking") {
|
||||
std::vector<gd::String> realObjects = ExpandObjectsName(objectName, context);
|
||||
|
||||
// Find the objects not yet declared, and handle them separately so they are
|
||||
// passed as empty object lists.
|
||||
std::vector<gd::String> objectToBeDeclaredNames;
|
||||
std::vector<gd::String> objectNotYetDeclaredNames;
|
||||
for (auto& objectName : realObjects) {
|
||||
if (context.ObjectAlreadyDeclaredByParents(objectName) ||
|
||||
context.IsToBeDeclared(objectName)) {
|
||||
objectToBeDeclaredNames.push_back(objectName);
|
||||
} else {
|
||||
objectNotYetDeclaredNames.push_back(objectName);
|
||||
}
|
||||
}
|
||||
|
||||
gd::String objectsMapName = declareMapOfObjects(objectToBeDeclaredNames, context, objectNotYetDeclaredNames);
|
||||
output = objectsMapName;
|
||||
} else if (type == "objectPtr") {
|
||||
std::vector<gd::String> realObjects =
|
||||
ExpandObjectsName(objectName, context);
|
||||
|
@@ -77,10 +77,10 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
* \param eventsFunction The events function to be compiled.
|
||||
* \param codeNamespace Where to store the context used by the function.
|
||||
* \param includeFiles Will be filled with the necessary include files.
|
||||
* \param onceTriggersVariable The code to access the variable holding OnceTriggers.
|
||||
* \param preludeCode The code to run just before the events generated code.
|
||||
* \param compilationForRuntime Set this to true if the code is generated for
|
||||
* runtime.
|
||||
* \param onceTriggersVariable The code to access the variable holding
|
||||
* OnceTriggers. \param preludeCode The code to run just before the events
|
||||
* generated code. \param compilationForRuntime Set this to true if the code
|
||||
* is generated for runtime.
|
||||
*
|
||||
* \return JavaScript code
|
||||
*/
|
||||
@@ -107,7 +107,7 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
* \return Code
|
||||
*/
|
||||
virtual gd::String GenerateEventsListCode(
|
||||
gd::EventsList& events, const gd::EventsCodeGenerationContext& context);
|
||||
gd::EventsList& events, gd::EventsCodeGenerationContext& context);
|
||||
|
||||
/**
|
||||
* Generate code for executing a condition list
|
||||
@@ -229,7 +229,8 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
const gd::ObjectMetadata& objInfo,
|
||||
const std::vector<gd::String>& arguments,
|
||||
const gd::InstructionMetadata& instrInfos,
|
||||
gd::EventsCodeGenerationContext& context);
|
||||
gd::EventsCodeGenerationContext& context,
|
||||
const gd::String& optionalAsyncCallbackName = "");
|
||||
|
||||
virtual gd::String GenerateBehaviorAction(
|
||||
const gd::String& objectName,
|
||||
@@ -237,7 +238,8 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
const gd::BehaviorMetadata& autoInfo,
|
||||
const std::vector<gd::String>& arguments,
|
||||
const gd::InstructionMetadata& instrInfos,
|
||||
gd::EventsCodeGenerationContext& context);
|
||||
gd::EventsCodeGenerationContext& context,
|
||||
const gd::String& optionalAsyncCallbackName = "");
|
||||
|
||||
virtual gd::String GenerateGetBehaviorNameCode(
|
||||
const gd::String& behaviorName);
|
||||
@@ -279,7 +281,8 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
virtual gd::String GenerateObjectsDeclarationCode(
|
||||
gd::EventsCodeGenerationContext& context);
|
||||
|
||||
virtual gd::String GenerateAllInstancesGetterCode(gd::String& objectName);
|
||||
virtual gd::String GenerateAllInstancesGetterCode(
|
||||
const gd::String& objectName, gd::EventsCodeGenerationContext& context);
|
||||
|
||||
virtual gd::String GenerateProfilerSectionBegin(const gd::String& section);
|
||||
virtual gd::String GenerateProfilerSectionEnd(const gd::String& section);
|
||||
@@ -323,18 +326,18 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
bool isBehaviorEventsFunction);
|
||||
|
||||
/**
|
||||
* \brief Generate the "eventsFunctionContext" object that allow a free function
|
||||
* to provides access objects, object creation and access to arguments from
|
||||
* the rest of the events.
|
||||
* \brief Generate the "eventsFunctionContext" object that allow a free
|
||||
* function to provides access objects, object creation and access to
|
||||
* arguments from the rest of the events.
|
||||
*/
|
||||
gd::String GenerateFreeEventsFunctionContext(
|
||||
const std::vector<gd::ParameterMetadata>& parameters,
|
||||
const gd::String& onceTriggersVariable);
|
||||
|
||||
/**
|
||||
* \brief Generate the "eventsFunctionContext" object that allow a behavior function
|
||||
* to provides access objects, object creation and access to arguments from
|
||||
* the rest of the events.
|
||||
* \brief Generate the "eventsFunctionContext" object that allow a behavior
|
||||
* function to provides access objects, object creation and access to
|
||||
* arguments from the rest of the events.
|
||||
*/
|
||||
gd::String GenerateBehaviorEventsFunctionContext(
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
@@ -360,7 +363,7 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
|
||||
gd::String codeNamespace; ///< Optional namespace for the generated code,
|
||||
///< used when generating events function.
|
||||
private:
|
||||
private:
|
||||
/**
|
||||
* \brief Generate the "eventsFunctionContext" object that allow a function
|
||||
* to provides access objects, object creation and access to arguments from
|
||||
|
73
GDJS/GDJS/Extensions/Builtin/AsyncExtension.cpp
Normal file
73
GDJS/GDJS/Extensions/Builtin/AsyncExtension.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* GDevelop JS Platform
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "AsyncExtension.h"
|
||||
|
||||
#include "GDCore/Events/Builtin/AsyncEvent.h"
|
||||
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
|
||||
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
|
||||
#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h"
|
||||
|
||||
namespace gdjs {
|
||||
|
||||
AsyncExtension::AsyncExtension() {
|
||||
gd::BuiltinExtensionsImplementer::ImplementsAsyncExtension(*this);
|
||||
|
||||
GetAllEvents()["BuiltinAsync::Async"].SetCodeGenerator(
|
||||
[](gd::BaseEvent &event_,
|
||||
gd::EventsCodeGenerator &codeGenerator,
|
||||
gd::EventsCodeGenerationContext &parentContext) {
|
||||
gd::AsyncEvent &event = dynamic_cast<gd::AsyncEvent &>(event_);
|
||||
|
||||
// Generate callback code
|
||||
const auto callbackDescriptor = codeGenerator.GenerateCallback(
|
||||
gd::String::From(codeGenerator.GenerateSingleUsageUniqueIdFor(
|
||||
event.GetInstruction().GetOriginalInstruction().lock().get())),
|
||||
parentContext,
|
||||
event.GetActions(),
|
||||
event.HasSubEvents() ? &event.GetSubEvents() : nullptr);
|
||||
|
||||
const gd::String callbackCallCode =
|
||||
"(runtimeScene) => (" + callbackDescriptor.functionName + "(" +
|
||||
callbackDescriptor.argumentsList + "))";
|
||||
|
||||
// Generate the action and store the generated task.
|
||||
const gd::String asyncActionCode = codeGenerator.GenerateActionCode(
|
||||
event.GetInstruction(), parentContext, callbackCallCode);
|
||||
|
||||
// Generate code to backup the objects lists.
|
||||
// Do it after generating the code of the action so that it uses the
|
||||
// same object list as used in the action.
|
||||
gd::String parentAsyncObjectsListGetter =
|
||||
parentContext.IsInsideAsync()
|
||||
? "const parentAsyncObjectsList = asyncObjectsList;\n"
|
||||
: "";
|
||||
gd::String asyncObjectsListBuilder =
|
||||
parentContext.IsInsideAsync()
|
||||
? "const asyncObjectsList = "
|
||||
"gdjs.LongLivedObjectsList.from(parentAsyncObjectsList);\n"
|
||||
: "const asyncObjectsList = new gdjs.LongLivedObjectsList();\n";
|
||||
for (const gd::String &objectNameToBackup :
|
||||
callbackDescriptor.requiredObjects) {
|
||||
if (parentContext.ShouldUseAsyncObjectsList(objectNameToBackup))
|
||||
asyncObjectsListBuilder +=
|
||||
"/* Don't save " + objectNameToBackup +
|
||||
" as it will be provided by the parent asyncObjectsList. */\n";
|
||||
else
|
||||
asyncObjectsListBuilder +=
|
||||
"for (const obj of " +
|
||||
codeGenerator.GetObjectListName(objectNameToBackup,
|
||||
parentContext) +
|
||||
") asyncObjectsList.addObject(" +
|
||||
codeGenerator.ConvertToStringExplicit(objectNameToBackup) +
|
||||
", obj);\n";
|
||||
}
|
||||
|
||||
return "{\n" + parentAsyncObjectsListGetter + "{\n" +
|
||||
asyncObjectsListBuilder + asyncActionCode + "}\n" + "}\n";
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace gdjs
|
24
GDJS/GDJS/Extensions/Builtin/AsyncExtension.h
Normal file
24
GDJS/GDJS/Extensions/Builtin/AsyncExtension.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* GDevelop JS Platform
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef ASYNCEXTENSION_H
|
||||
#define ASYNCEXTENSION_H
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
|
||||
namespace gdjs {
|
||||
|
||||
/**
|
||||
* \brief Built-in extension providing async functionality.
|
||||
*
|
||||
* \ingroup BuiltinExtensions
|
||||
*/
|
||||
class AsyncExtension : public gd::PlatformExtension {
|
||||
public:
|
||||
AsyncExtension();
|
||||
virtual ~AsyncExtension(){};
|
||||
};
|
||||
|
||||
} // namespace gdjs
|
||||
#endif // ASYNCEXTENSION_H
|
@@ -33,6 +33,8 @@ AudioExtension::AudioExtension() {
|
||||
"gdjs.evtTools.sound.pauseMusicOnChannel");
|
||||
GetAllActions()["RePlayMusicCanal"].SetFunctionName(
|
||||
"gdjs.evtTools.sound.continueMusicOnChannel");
|
||||
GetAllActions()["FadeMusicVolume"].SetFunctionName(
|
||||
"gdjs.evtTools.sound.fadeMusicVolume");
|
||||
|
||||
GetAllActions()["PreloadMusic"].SetFunctionName(
|
||||
"gdjs.evtTools.sound.preloadMusic");
|
||||
@@ -44,6 +46,9 @@ AudioExtension::AudioExtension() {
|
||||
"gdjs.evtTools.sound.unloadSound");
|
||||
GetAllActions()["UnloadAllAudio"].SetFunctionName(
|
||||
"gdjs.evtTools.sound.unloadAllAudio");
|
||||
GetAllActions()["FadeSoundVolume"].SetFunctionName(
|
||||
"gdjs.evtTools.sound.fadeSoundVolume");
|
||||
|
||||
|
||||
GetAllConditions()["MusicPlaying"].SetFunctionName(
|
||||
"gdjs.evtTools.sound.isMusicOnChannelPlaying");
|
||||
|
@@ -252,10 +252,21 @@ BaseObjectExtension::BaseObjectExtension() {
|
||||
"gdjs.evtTools.object.createObjectOnScene");
|
||||
GetAllActions()["CreateByName"].SetFunctionName(
|
||||
"gdjs.evtTools.object.createObjectFromGroupOnScene");
|
||||
|
||||
GetAllExpressions()["Count"].SetFunctionName(
|
||||
"gdjs.evtTools.object.pickedObjectsCount");
|
||||
"gdjs.evtTools.object.pickedObjectsCount"); // Deprecated
|
||||
GetAllConditions()["NbObjet"].SetFunctionName(
|
||||
"gdjs.evtTools.object.pickedObjectsCount");
|
||||
"gdjs.evtTools.object.pickedObjectsCount"); // Deprecated
|
||||
|
||||
GetAllExpressions()["SceneInstancesCount"].SetFunctionName(
|
||||
"gdjs.evtTools.object.getSceneInstancesCount");
|
||||
GetAllConditions()["SceneInstancesCount"].SetFunctionName(
|
||||
"gdjs.evtTools.object.getSceneInstancesCount");
|
||||
GetAllExpressions()["PickedInstancesCount"].SetFunctionName(
|
||||
"gdjs.evtTools.object.getPickedInstancesCount");
|
||||
GetAllConditions()["PickedInstancesCount"].SetFunctionName(
|
||||
"gdjs.evtTools.object.getPickedInstancesCount");
|
||||
|
||||
GetAllConditions()["CollisionNP"].SetFunctionName(
|
||||
"gdjs.evtTools.object.hitBoxesCollisionTest");
|
||||
GetAllConditions()["Raycast"].SetFunctionName(
|
||||
|
@@ -30,6 +30,7 @@
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
#include "GDJS/Events/Builtin/JsCodeEvent.h"
|
||||
#include "GDJS/Events/CodeGeneration/EventsCodeGenerator.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace gd;
|
||||
@@ -89,8 +90,8 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
|
||||
return gd::String("");
|
||||
});
|
||||
GetAllConditions()["BuiltinCommonInstructions::CompareNumbers"].codeExtraInformation =
|
||||
GetAllConditions()["Egal"].codeExtraInformation;
|
||||
GetAllConditions()["BuiltinCommonInstructions::CompareNumbers"]
|
||||
.codeExtraInformation = GetAllConditions()["Egal"].codeExtraInformation;
|
||||
|
||||
GetAllConditions()["StrEqual"].codeExtraInformation.SetCustomCodeGenerator(
|
||||
[](gd::Instruction& instruction,
|
||||
@@ -123,8 +124,9 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
|
||||
return gd::String("");
|
||||
});
|
||||
GetAllConditions()["BuiltinCommonInstructions::CompareStrings"].codeExtraInformation =
|
||||
GetAllConditions()["StrEqual"].codeExtraInformation;
|
||||
GetAllConditions()["BuiltinCommonInstructions::CompareStrings"]
|
||||
.codeExtraInformation =
|
||||
GetAllConditions()["StrEqual"].codeExtraInformation;
|
||||
|
||||
GetAllEvents()["BuiltinCommonInstructions::Link"]
|
||||
.SetCodeGenerator([](gd::BaseEvent& event_,
|
||||
@@ -216,7 +218,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
// "MyObject" will both have to declare a "MyObject" object list.
|
||||
gd::EventsCodeGenerationContext context;
|
||||
context.InheritsFrom(parentContext);
|
||||
context.ForbidReuse(); // TODO: This may not be necessary
|
||||
context.ForbidReuse(); // TODO: This may not be necessary (to be investigated/heavily tested).
|
||||
|
||||
gd::String conditionCode = codeGenerator.GenerateConditionCode(
|
||||
conditions[cId],
|
||||
@@ -280,7 +282,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
//"OR" condition must declare objects list, but without getting
|
||||
// the objects from the scene. Lists are either empty or come from
|
||||
// a parent event.
|
||||
parentContext.ObjectsListWithoutPickingNeeded(*it);
|
||||
parentContext.ObjectsListNeededOrEmptyIfJustDeclared(*it);
|
||||
// We need to duplicate the object lists : The "final" ones will
|
||||
// be filled with objects by conditions, but they will have no
|
||||
// incidence on further conditions, as conditions use "normal"
|
||||
@@ -437,11 +439,8 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
|
||||
// Prevent code generation if the event is empty, as this would
|
||||
// get the game stuck in a never ending loop.
|
||||
if (
|
||||
event.GetWhileConditions().empty() &&
|
||||
event.GetConditions().empty() &&
|
||||
event.GetActions().empty()
|
||||
)
|
||||
if (event.GetWhileConditions().empty() &&
|
||||
event.GetConditions().empty() && event.GetActions().empty())
|
||||
return gd::String(
|
||||
"\n// While event not generated to prevent an infinite loop.\n");
|
||||
|
||||
@@ -495,6 +494,8 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
outputCode += "if (" + ifPredicat + ") {\n";
|
||||
outputCode += actionsCode;
|
||||
outputCode += "\n{ //Subevents: \n";
|
||||
// TODO: check (and heavily test) if sub events should be generated before
|
||||
// the call to GenerateObjectsDeclarationCode.
|
||||
outputCode +=
|
||||
codeGenerator.GenerateEventsListCode(event.GetSubEvents(), context);
|
||||
outputCode += "} //Subevents end.\n";
|
||||
@@ -553,6 +554,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
!event.GetValueIteratorVariableName().empty();
|
||||
bool keyIteratorExists = !event.GetKeyIteratorVariableName().empty();
|
||||
|
||||
// clang-format off
|
||||
// Define references to variables (if they exist)
|
||||
if (keyIteratorExists)
|
||||
outputCode +=
|
||||
@@ -599,6 +601,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
" // Arrays are passed by reference like JS objects\n"
|
||||
" $VALUE_ITERATOR_REFERENCE.replaceChildrenArray($STRUCTURE_CHILD_VARIABLE.getAllChildrenArray());\n"
|
||||
" } else console.warn(\"Cannot identify type: \", type);\n";
|
||||
// clang-format on
|
||||
|
||||
// Now do the rest of standard event code generation
|
||||
outputCode += objectDeclaration;
|
||||
@@ -755,7 +758,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
// picked again)
|
||||
gd::EventsCodeGenerationContext context;
|
||||
context.InheritsFrom(parentContext);
|
||||
context.ForbidReuse();
|
||||
context.ForbidReuse(); // TODO: This may not be necessary (to be investigated/heavily tested).
|
||||
|
||||
for (unsigned int i = 0; i < realObjects.size(); ++i)
|
||||
context.EmptyObjectsListNeeded(realObjects[i]);
|
||||
|
@@ -37,7 +37,9 @@ MathematicalToolsExtension::MathematicalToolsExtension() {
|
||||
GetAllExpressions()["atanh"].SetFunctionName("gdjs.evtTools.common.atanh");
|
||||
GetAllExpressions()["cbrt"].SetFunctionName("gdjs.evtTools.common.cbrt");
|
||||
GetAllExpressions()["ceil"].SetFunctionName("Math.ceil");
|
||||
GetAllExpressions()["ceilTo"].SetFunctionName("gdjs.evtTools.common.ceilTo");
|
||||
GetAllExpressions()["floor"].SetFunctionName("Math.floor");
|
||||
GetAllExpressions()["floorTo"].SetFunctionName("gdjs.evtTools.common.floorTo");
|
||||
GetAllExpressions()["cosh"].SetFunctionName("gdjs.evtTools.common.cosh");
|
||||
GetAllExpressions()["sinh"].SetFunctionName("gdjs.evtTools.common.sinh");
|
||||
GetAllExpressions()["tanh"].SetFunctionName("gdjs.evtTools.common.tanh");
|
||||
@@ -63,6 +65,7 @@ MathematicalToolsExtension::MathematicalToolsExtension() {
|
||||
GetAllExpressions()["int"].SetFunctionName("Math.round");
|
||||
GetAllExpressions()["rint"].SetFunctionName("Math.round");
|
||||
GetAllExpressions()["round"].SetFunctionName("Math.round");
|
||||
GetAllExpressions()["roundTo"].SetFunctionName("gdjs.evtTools.common.roundTo");
|
||||
GetAllExpressions()["trunc"].SetFunctionName("gdjs.evtTools.common.trunc");
|
||||
GetAllExpressions()["lerp"].SetFunctionName("gdjs.evtTools.common.lerp");
|
||||
GetAllExpressions()["XFromAngleAndDistance"].SetFunctionName("gdjs.evtTools.common.getXFromAngleAndDistance");
|
||||
|
@@ -55,9 +55,9 @@ MouseExtension::MouseExtension() {
|
||||
"gdjs.evtTools.input.getMouseY"); // Deprecated
|
||||
|
||||
GetAllConditions()["PopStartedTouch"].SetFunctionName(
|
||||
"gdjs.evtTools.input.popStartedTouch");
|
||||
"gdjs.evtTools.input.popStartedTouch"); // Deprecated
|
||||
GetAllConditions()["PopEndedTouch"].SetFunctionName(
|
||||
"gdjs.evtTools.input.popEndedTouch");
|
||||
"gdjs.evtTools.input.popEndedTouch"); // Deprecated
|
||||
|
||||
GetAllConditions()["TouchX"].SetFunctionName("gdjs.evtTools.input.getTouchX");
|
||||
GetAllConditions()["TouchY"].SetFunctionName("gdjs.evtTools.input.getTouchY");
|
||||
@@ -67,9 +67,18 @@ MouseExtension::MouseExtension() {
|
||||
"gdjs.evtTools.input.getTouchY");
|
||||
|
||||
GetAllExpressions()["LastTouchId"].SetFunctionName(
|
||||
"gdjs.evtTools.input.getLastTouchId");
|
||||
"gdjs.evtTools.input.getLastTouchId"); // Deprecated
|
||||
GetAllExpressions()["LastEndedTouchId"].SetFunctionName(
|
||||
"gdjs.evtTools.input.getLastEndedTouchId");
|
||||
"gdjs.evtTools.input.getLastEndedTouchId"); // Deprecated
|
||||
|
||||
GetAllConditions()["HasAnyTouchStarted"].SetFunctionName(
|
||||
"gdjs.evtTools.input.hasAnyTouchStarted");
|
||||
GetAllConditions()["HasTouchEnded"].SetFunctionName(
|
||||
"gdjs.evtTools.input.hasTouchEnded");
|
||||
GetAllExpressions()["StartedTouchCount"].SetFunctionName(
|
||||
"gdjs.evtTools.input.getStartedTouchCount");
|
||||
GetAllExpressions()["StartedTouchId"].SetFunctionName(
|
||||
"gdjs.evtTools.input.getStartedTouchIdentifier");
|
||||
|
||||
GetAllExpressions()["MouseWheelDelta"].SetFunctionName(
|
||||
"gdjs.evtTools.input.getMouseWheelDelta");
|
||||
|
@@ -27,6 +27,8 @@ TimeExtension::TimeExtension() {
|
||||
"gdjs.evtTools.runtimeScene.unpauseTimer");
|
||||
GetAllActions()["RemoveTimer"].SetFunctionName(
|
||||
"gdjs.evtTools.runtimeScene.removeTimer");
|
||||
GetAllActions()["Wait"].SetFunctionName(
|
||||
"gdjs.evtTools.runtimeScene.wait");
|
||||
GetAllConditions()["TimeScale"].SetFunctionName(
|
||||
"gdjs.evtTools.runtimeScene.getTimeScale");
|
||||
GetAllActions()["ChangeTimeScale"].SetFunctionName(
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user