Compare commits

...

90 Commits

Author SHA1 Message Date
AlexandreS
656255a662 Bump newIDE version (#5475) 2023-07-12 11:56:23 +02:00
AlexandreS
ea7b7a778e Improve messages visibility in collision masks dialog (#5473)
Don't show in changelog
2023-07-12 10:00:37 +02:00
AlexandreS
9b6de5affd Add possibility to subscribe to a startup plan from the profile (#5472) 2023-07-11 16:31:25 +02:00
Clément Pasteau
0c03659314 Fix Node.js 18 compatibility, upgrade to create-react-app v5 and make mac build universal (#5270)
* only show in developer changelog
2023-07-11 15:03:33 +02:00
github-actions[bot]
6b08c0f033 Update translations [skip ci] (#5466)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2023-07-11 14:10:20 +02:00
AlexandreS
a1dcf03a5b Fix the editor hanging when opening a scene with hundreds of instances of 3D model objects (#5470) 2023-07-10 17:31:29 +02:00
D8H
556d13c881 Fix the community warning that wasn't showing up in documentation (#5468)
Don't show in changelog
2023-07-09 19:31:28 +02:00
D8H
0d6c42a9bf Filter private actions and conditions from the reference page (#5467)
* Don't show in changelog
2023-07-07 14:09:53 +02:00
D8H
690ce16ab4 Add a listing of actions and conditions in community extension reference pages (#5464) 2023-07-07 10:50:47 +02:00
github-actions[bot]
5f51a5e465 Update translations [skip ci] (#5465)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2023-07-06 09:51:54 +02:00
AlexandreS
b7521de138 Add startup plan support in user profile components (#5462) 2023-07-05 09:39:40 +02:00
AlexandreS
acea6fc595 Fix SetPosition action that was missing parenthesis creating math errors (#5458) 2023-07-03 12:07:10 +02:00
github-actions[bot]
d8107fe3d5 Update translations [skip ci] (#5457)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2023-07-03 11:31:55 +02:00
Clément Pasteau
b40b95be99 Remove jimp, use Canvas for image manipulation (#5454)
Do not show in changelog
2023-07-03 11:21:28 +02:00
AlexandreS
6644525dd0 Remove former fix that triggered a bug where values were not persisted after editing expression in event sheet (#5455) 2023-07-03 10:28:43 +02:00
github-actions[bot]
56e66d1c5a Update translations [skip ci] (#5452)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2023-06-30 15:51:19 +02:00
Clément Pasteau
90d8afb5a0 Calculate Sprite collision masks automatically (#5447)
* Sprites now have an option to calculate their collision mask automatically, based on the first image of their first animation
* The generated collision mask consists of the biggest rectangle possible, encapsulating the image and avoiding transparent pixels
* This option is enabled by default for all new sprites, and can be disabled to create a custom collision mask like before
* When enabled, the mask will adapt automatically when the first image is updated
2023-06-30 15:33:50 +02:00
AlexandreS
d4db61a595 Fix autofocus of searchbar on tablets in landscape (#5451) 2023-06-29 22:40:06 +02:00
D8H
90413b842d Move event-based extension metadata generation from newIDE to GDJS (#5255) 2023-06-29 20:18:51 +02:00
github-actions[bot]
43c788acbf Update translations [skip ci] (#5444)
Co-authored-by: 4ian <4ian@users.noreply.github.com>
2023-06-29 11:29:17 +02:00
supertree-wook
ee22b2e4b1 Upgrade CMake minimum version and improve CMake code (#5446)
Only show in developer changelog
2023-06-28 12:01:05 +02:00
AlexandreS
007d56e946 Display the scene editors more conveniently on mobile (#5441) 2023-06-26 18:07:23 +02:00
AlexandreS
577c4adb14 Fix images selectors not updating on Box 3D editor after an image has been created with Piskel (#5442) 2023-06-26 17:53:23 +02:00
AlexandreS
7f17720ff3 Fix: Do not close popover when releasing text selection click outside of popover (#5443) 2023-06-23 16:51:24 +02:00
github-actions[bot]
288db1c941 Update translations [skip ci] (#5434)
Co-authored-by: 4ian <4ian@users.noreply.github.com>
2023-06-23 16:32:13 +02:00
Florian Rival
2496fc3eef Revert "Add extension to support Steamworks integration of games made with GDevelop (#5401)" (#5438)
This reverts commit 3c43f28966.
2023-06-22 12:58:00 +02:00
AlexandreS
b43d5ec425 Improve copy regarding faces orientation of the 3D box (#5432) 2023-06-22 09:27:06 +02:00
Arthur Pacaud
3c43f28966 Add extension to support Steamworks integration of games made with GDevelop (#5401) 2023-06-22 09:16:20 +02:00
Clément Pasteau
a3f7c5782e Fix creating project properties from template to be set properly (#5436) 2023-06-22 09:14:46 +02:00
AlexandreS
8dec6dfa28 Bump newIDE version (#5433) 2023-06-22 09:13:01 +02:00
D8H
4eb49bdeb2 Use the object type for 3D model assets (#5431)
* Don't show in changelog
2023-06-21 20:14:46 +02:00
Clément Pasteau
813cadbd6e Improve prompt generator to hint on game type for better results (#5430)
Do not show in changelog
2023-06-21 16:04:01 +02:00
github-actions[bot]
58dd2c1a7b Update translations [skip ci] (#5428)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2023-06-21 15:57:23 +02:00
AlexandreS
104c27ebc8 Improve guided lessons framework (#5426)
- Improve tooltip placement
- Fix z order setting step sometimes blocked
2023-06-21 14:48:39 +02:00
D8H
318099504c Handle 3D models in the asset store (#5427) 2023-06-21 14:46:34 +02:00
supertree-wook
8851be03a3 Fix typos here and there (#5253)
Only show in developer changelog
2023-06-21 12:41:17 +02:00
github-actions[bot]
a9a126ab0d Update translations [skip ci] (#5422)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2023-06-21 11:20:33 +02:00
AlexandreS
19e46fedc8 Fix scroll on autocompletion displayer on mobile (#5425) 2023-06-21 11:12:07 +02:00
Arthur Pacaud
ff987a0751 Suggest the authenticated user's username by default in inputs showing usernames (#5423) 2023-06-21 08:21:44 +02:00
AlexandreS
0c0ab65b1a Display more info on missing action/condition placeholder (#5415) 2023-06-20 09:43:18 +02:00
AlexandreS
52a5908d7e Rename 3D editor preference to enable 3D editor for everyone (#5421) 2023-06-20 09:37:22 +02:00
github-actions[bot]
49926a89a2 Update translations [skip ci] (#5417)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2023-06-20 09:25:08 +02:00
D8H
b63b91f33d Fix out-of-limits dragging of animation in sprite editor (#5413)
Also:
- Show duplicated animation name errors directly on the field instead of a popup

---------

Co-authored-by: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com>
2023-06-19 17:13:26 +02:00
supertree-wook
67ea361416 Remove duplicate cache registration code (#5411) 2023-06-16 17:37:58 +02:00
github-actions[bot]
3b9078c6b3 Update translations [skip ci] (#5408)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2023-06-16 14:12:34 +02:00
D8H
3d9e3f997e Clear 3D animation name errors when they are moved (#5416) 2023-06-16 12:27:40 +02:00
D8H
3c34866faa Fix the dragging of the first 3D animation (#5414)
* Don't show in changelog
2023-06-15 16:42:51 +02:00
AlexandreS
69cd2784c4 Add alert message when changing the 3D rendering in scene editor (#5412)
Do not show in changelog
2023-06-15 09:27:37 +02:00
AlexandreS
5b7e419a41 Improve user experience with users autocomplete (#5410) 2023-06-14 19:03:37 +02:00
AlexandreS
7773460d35 Autodetect webgl support to define 3D instances showing preference (#5409)
Don't show in changelog
2023-06-14 15:30:27 +02:00
AlexandreS
9262266480 Fix wrongly set flag (#5406)
Do not show in changelog
2023-06-14 14:59:42 +02:00
AlexandreS
84f2b4ca68 Bump newIDE version (#5407) 2023-06-14 14:58:38 +02:00
AlexandreS
19ae7a378c Prevent empty Algolia search at app start (#5405)
only show in developer changelog
2023-06-14 14:57:47 +02:00
github-actions[bot]
f9ca330add Update translations [skip ci] (#5403) 2023-06-14 14:10:30 +02:00
D8H
5ef990ac7d Fix 3D model positions in the 2D editor (#5404)
* Don't show in changelog
2023-06-14 11:34:26 +02:00
D8H
8099820729 Fix double dot in descriptions (#5402)
* Don't show in changelog.
2023-06-14 10:20:25 +02:00
github-actions[bot]
df556f20e9 Update translations [skip ci] (#5399)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2023-06-14 09:37:57 +02:00
Clément Pasteau
2c8f2ab58d New field to create a project from a prompt (#5395)
* New Experimental field in the Create Project Dialog allowing to enter a game description and get a game generated by the AI
2023-06-13 17:15:06 +02:00
D8H
20c3d62c90 Add the support for animations on 3D models (#5302)
- Breaking change: fix 3D models that were mirrored on Y axis.
  - In case some models look upside-down, they can be fixed by adding 180° to the "Rotation around Y axis" property.
- Handle custom origin and center.
2023-06-13 12:42:46 +02:00
github-actions[bot]
0a28981c74 Update translations [skip ci] (#5388)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2023-06-13 10:19:16 +02:00
D8H
c8bb24475c Use the project name when creating a new project file locally (#5396) 2023-06-12 15:17:41 +02:00
AlexandreS
81bce61783 Introduce Education plan (#5382)
It is now possible to subscribe to an education plan to provide gold subscriptions to a pool of anonymised users.
2023-06-12 10:32:21 +02:00
Florian Rival
71d1b6aa1f Refactor handling of prices of asset packs (#5393)
Don't show in changelog
2023-06-11 20:33:42 +02:00
Clément Pasteau
c41974c24b Update fling game (#5391)
Do not show in changelog
2023-06-09 17:52:08 +02:00
D8H
3bee88c6cd Handle 3D models compressed with Draco (#5390) 2023-06-09 17:49:46 +02:00
D8H
4c874dfb7e Automatically set a default operator when adding a new condition or action (#5389) 2023-06-09 14:59:04 +02:00
D8H
65f499f24e Fix the alert message about 3d objects without any light (#5387)
* Don't show in changelog
2023-06-09 10:30:20 +02:00
github-actions[bot]
3265bf7fb4 Update translations [skip ci] (#5386)
Co-authored-by: AlexandreSi <AlexandreSi@users.noreply.github.com>
2023-06-09 10:27:25 +02:00
AlexandreS
5a437dea4e Fix markdown tables rendering (for extension description for instance) (#5384) 2023-06-09 10:00:06 +02:00
github-actions[bot]
19b576e8cc Update translations [skip ci] (#5383)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2023-06-08 16:07:35 +02:00
Clément Pasteau
67747e458e Add new guided lesson: Create a 3D Box (#5376) 2023-06-08 11:37:29 +02:00
github-actions[bot]
260c2b9c8f Update translations [skip ci] (#5380)
Co-authored-by: D8H <D8H@users.noreply.github.com>
2023-06-08 10:30:14 +02:00
D8H
255ef1d8ef Add an antialising setting for 3D (#5381) 2023-06-08 09:57:34 +02:00
D8H
53c633c646 Add an hemisphere light effect for 3D layers (#5379) 2023-06-07 17:21:26 +02:00
github-actions[bot]
cec67a91d4 Update translations [skip ci] (#5370)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2023-06-07 16:59:32 +02:00
Clément Pasteau
4408dfe59d Fix initializing received assets correctly when user is not authenticated (#5374)
* Asset pack web links were not working because of this
2023-06-07 16:59:08 +02:00
Clément Pasteau
c4274d2fc4 Fix default depth of 3D object on scene being correctly initialised (#5378) 2023-06-07 15:13:04 +02:00
Clément Pasteau
b0103f31b7 Fix showing cancel subscription button for legacy plans (#5371) 2023-06-07 10:23:39 +02:00
AlexandreS
18905890d4 Fix dialogue tree loading from scene variable action sentence (#5372) 2023-06-06 19:01:05 +02:00
D8H
6858e0fb59 Render 3D in linear color space, upgrade to Three.js 1.152.0 (#5360)
* 3D model objects will look brighter. Light intensity may need to be reduced.
2023-06-06 12:28:46 +02:00
github-actions[bot]
cf595a7d7d Update translations [skip ci] (#5364)
Co-authored-by: 4ian <4ian@users.noreply.github.com>
2023-06-05 13:42:31 +02:00
Florian Rival
e681d27bb8 Allow to use the 3D editor with a toggle in the preferences 2023-06-03 14:19:00 +02:00
AlexandreS
8941e04390 Fix color 3D model color rendering being darker than the original texture (#5368) 2023-06-02 15:46:27 +02:00
AlexandreS
e186681f39 Display Z coordinate in instance tooltip for instances of 3D objects
- Also fixes some weird behavior around the "Custom size" checkbox in instance properties
2023-06-01 16:12:34 +02:00
Florian Rival
a578fa32e9 Add support for 3D objects in editor (#5357) 2023-06-01 12:17:20 +02:00
supertree-wook
6b40e8309c Fix some extension descriptions in the wiki not having properly formatted lists (#5365) 2023-06-01 11:56:14 +02:00
supertree-wook
5ff51351af Fix typo in description of StrFindLastFrom (#5363) 2023-05-31 09:57:13 +02:00
github-actions[bot]
d66e4e0001 Update translations [skip ci] (#5351)
Co-authored-by: ClementPasteau <ClementPasteau@users.noreply.github.com>
2023-05-30 18:02:33 +02:00
Clément Pasteau
2184eaf70b Fix sprite images selection when opening up the options menu (#5359)
* Fix an issue where opening the options menu of a sprite of a non-selected image would not take it into account for the actions.
2023-05-30 11:18:23 +02:00
AlexandreS
29fc0598f6 Start over from the suffix number when generating a new name (#5355) 2023-05-26 11:36:51 +02:00
428 changed files with 48924 additions and 40129 deletions

View File

@@ -15,7 +15,7 @@ jobs:
# Build the **entire** app for macOS.
build-macos:
macos:
xcode: 12.5.1
xcode: 14.2.0
steps:
- checkout
@@ -64,11 +64,11 @@ jobs:
# Note: Code signing is done using CSC_LINK (see https://www.electron.build/code-signing).
- run:
name: Build GDevelop IDE
command: export NODE_OPTIONS="--max-old-space-size=7168" && cd newIDE/electron-app && npm run build -- --mac --publish=never
command: export NODE_OPTIONS="--max-old-space-size=7168" && cd newIDE/electron-app && CI=false npm run build -- --mac --publish=never
- run:
name: Clean dist folder to keep only installers/binaries.
command: rm -rf "newIDE/electron-app/dist/mac/GDevelop 5.app" && rm -rf "newIDE/electron-app/dist/mac-arm64/GDevelop 5.app"
command: rm -rf "newIDE/electron-app/dist/mac-universal/GDevelop 5.app"
# Upload artifacts (CircleCI)
- store_artifacts:
@@ -101,8 +101,8 @@ jobs:
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
name: Install Python3 dependencies for Emscripten
command: sudo apt install python-is-python3 python3-distutils -y
- run:
name: Install Emscripten (for GDevelop.js)
@@ -178,8 +178,8 @@ jobs:
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
name: Install Python3 dependencies for Emscripten
command: sudo apt install python-is-python3 python3-distutils -y
- run:
name: Install Emscripten (for GDevelop.js)

View File

@@ -1,100 +1,99 @@
#This is the CMake file used to build GDevelop.
#For more information, see the README.md file.
# This is the CMake file used to build GDevelop.
# For more information, see the README.md file.
cmake_minimum_required(VERSION 2.6)
cmake_policy(SET CMP0011 NEW)
cmake_minimum_required(VERSION 3.5)
# Add utility functions
include(scripts/CMakeClangUtils.txt) # To add clang-format and clang-tidy support to a target
# Macro for defining an option
macro(gd_set_option var default type docstring)
if(NOT DEFINED ${var})
set(${var} ${default})
endif()
set(${var} ${${var}} CACHE ${type} ${docstring} FORCE)
if(NOT DEFINED ${var})
set(${var} ${default})
endif()
set(${var} ${${var}} CACHE ${type} ${docstring} FORCE)
endmacro()
# Set options
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 TRUE BOOL "TRUE to build the tests")
# Disable deprecated code
set(NO_GUI TRUE CACHE BOOL "" FORCE) #Force disable old GUI related code.
set(NO_GUI TRUE CACHE BOOL "" FORCE) # Force disable old GUI related code.
#Setting up installation directory, for Linux (has to be done before "project" command).
IF(NOT WIN32)
if (NOT APPLE)
gd_set_option(GD_INSTALL_PREFIX "/opt/gdevelop/" STRING "The directory where GDevelop should be installed")
ELSE()
gd_set_option(GD_INSTALL_PREFIX "." STRING "The directory where GDevelop should be installed")
ENDIF()
# Setting up installation directory, for Linux (has to be done before "project" command).
if(NOT WIN32)
if(NOT APPLE)
gd_set_option(GD_INSTALL_PREFIX "/opt/gdevelop/" STRING "The directory where GDevelop should be installed")
else()
gd_set_option(GD_INSTALL_PREFIX "." STRING "The directory where GDevelop should be installed")
endif()
#As we embed SFML, prevent it to be installed system-wide
# As we embed SFML, prevent it to be installed system-wide
set(CMAKE_INSTALL_PREFIX "${GD_INSTALL_PREFIX}/useless")
ENDIF()
endif()
project(GDevelop)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
IF(NOT WIN32 AND NOT APPLE AND NOT BUILD_TESTS)
SET(CMAKE_SKIP_BUILD_RPATH TRUE) #Avoid errors when packaging for linux.
ENDIF()
IF(APPLE)
if(NOT WIN32 AND NOT APPLE AND NOT BUILD_TESTS)
set(CMAKE_SKIP_BUILD_RPATH TRUE) # Avoid errors when packaging for linux.
endif()
if(APPLE)
set(CMAKE_MACOSX_RPATH 1)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
set(CMAKE_INSTALL_RPATH ".")
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_WCHAR_H_CPLUSPLUS_98_CONFORMANCE_")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-potentially-evaluated-expression")
ENDIF()
#Sanity checks
IF ("${CMAKE_BUILD_TYPE}" STREQUAL "")
message( "CMAKE_BUILD_TYPE is empty, assuming build type is Release" )
add_compile_options(
-D_WCHAR_H_CPLUSPLUS_98_CONFORMANCE_
-Wno-potentially-evaluated-expression)
endif()
# Sanity checks
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
message(STATUS "CMAKE_BUILD_TYPE is empty, assuming build type is Release")
set(CMAKE_BUILD_TYPE Release)
ENDIF()
endif()
IF("${CMAKE_BUILD_TYPE}" STREQUAL "Release" AND NOT WIN32 AND CMAKE_COMPILER_IS_GNUCXX)
SET(CMAKE_SHARED_LINKER_FLAGS "-s") #Force stripping to avoid errors when packaging for linux.
ENDIF()
if("${CMAKE_BUILD_TYPE}" STREQUAL "Release" AND NOT WIN32 AND CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_SHARED_LINKER_FLAGS "-s") # Force stripping to avoid errors when packaging for linux.
endif()
#Activate C++11
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=gnu++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=gnu++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
elseif(COMPILER_SUPPORTS_CXX0X)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x")
else()
message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support (with GNU extensions). Please use a different C++ compiler.")
endif()
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Mark some warnings as errors
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
# Activate as much warnings as possible to avoid errors like
# uninitialized variables or other hard to debug bugs.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-warning-option")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-reorder-ctor -Wno-reorder -Wno-pessimizing-move -Wno-unused-variable -Wno-unused-private-field")
add_compile_options(
-Wall
-Wno-unknown-warning-option
-Wno-reorder-ctor
-Wno-reorder
-Wno-pessimizing-move
-Wno-unused-variable
-Wno-unused-private-field
# Make as much warnings considered as errors as possible (only one for now).
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=return-stack-address")
# Make as much warnings considered as errors as possible (only one for now).
-Werror=return-stack-address)
endif()
#Define common directories:
# Define common directories:
set(GD_base_dir ${CMAKE_CURRENT_SOURCE_DIR})
#Add all the CMakeLists:
ADD_SUBDIRECTORY(ExtLibs)
IF(BUILD_CORE)
ADD_SUBDIRECTORY(Core)
ENDIF()
IF(BUILD_GDJS)
ADD_SUBDIRECTORY(GDJS)
ENDIF()
IF(EMSCRIPTEN)
ADD_SUBDIRECTORY(GDevelop.js)
ENDIF()
IF(BUILD_EXTENSIONS)
ADD_SUBDIRECTORY(Extensions)
ENDIF()
# Add all the CMakeLists:
add_subdirectory(ExtLibs)
if(BUILD_CORE)
add_subdirectory(Core)
endif()
if(BUILD_GDJS)
add_subdirectory(GDJS)
endif()
if(EMSCRIPTEN)
add_subdirectory(GDevelop.js)
endif()
if(BUILD_EXTENSIONS)
add_subdirectory(Extensions)
endif()

View File

@@ -1,83 +1,98 @@
cmake_minimum_required(VERSION 2.6)
cmake_policy(SET CMP0015 NEW)
cmake_minimum_required(VERSION 3.5)
project(GDCore)
SET(CMAKE_C_USE_RESPONSE_FILE_FOR_OBJECTS 1) #Force use response file: useful for Ninja build system on Windows.
SET(CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS 1)
SET(CMAKE_C_USE_RESPONSE_FILE_FOR_INCLUDES 1)
SET(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES 1)
set(CMAKE_C_USE_RESPONSE_FILE_FOR_OBJECTS 1) # Force use response file: useful for Ninja build system on Windows.
set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS 1)
set(CMAKE_C_USE_RESPONSE_FILE_FOR_INCLUDES 1)
set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES 1)
#Define common directories:
# Define common directories:
set(GDCORE_include_dir ${GD_base_dir}/Core PARENT_SCOPE)
set(GDCORE_lib_dir ${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME} PARENT_SCOPE)
#Dependencies on external libraries:
###
# Dependencies on external libraries:
#
#Defines
###
add_definitions( -DGD_IDE_ONLY )
IF (EMSCRIPTEN)
add_definitions( -DEMSCRIPTEN )
ENDIF()
IF(CMAKE_BUILD_TYPE MATCHES "Debug")
add_definitions( -DDEBUG )
ELSE()
add_definitions( -DRELEASE )
ENDIF()
# Defines
#
add_definitions(-DGD_IDE_ONLY)
if(EMSCRIPTEN)
add_definitions(-DEMSCRIPTEN)
endif()
if("${CMAKE_BUILD_TYPE}" MATCHES "Debug")
add_definitions(-DDEBUG)
else()
add_definitions(-DRELEASE)
endif()
IF(WIN32)
add_definitions( -DWINDOWS )
add_definitions( "-DGD_CORE_API=__declspec(dllexport)" )
add_definitions( -D__GNUWIN32__ )
ELSE()
IF(APPLE)
add_definitions( -DMACOS )
ELSE()
add_definitions( -DLINUX )
ENDIF()
add_definitions( -DGD_API= )
add_definitions( -DGD_CORE_API= )
ENDIF(WIN32)
if(WIN32)
add_definitions(-DWINDOWS)
add_definitions("-DGD_CORE_API=__declspec(dllexport)")
add_definitions(-D__GNUWIN32__)
else()
if(APPLE)
add_definitions(-DMACOS)
else()
add_definitions(-DLINUX)
endif()
add_definitions(-DGD_API=)
add_definitions(-DGD_CORE_API=)
endif()
#The target
###
# The target
#
include_directories(.)
file(GLOB_RECURSE source_files GDCore/*)
file(
GLOB_RECURSE
source_files
GDCore/*)
file(GLOB_RECURSE formatted_source_files tests/* GDCore/Events/* GDCore/Extensions/* GDCore/IDE/* GDCore/Project/* GDCore/Serialization/* GDCore/Tools/*)
list(REMOVE_ITEM formatted_source_files "${CMAKE_CURRENT_SOURCE_DIR}/GDCore/IDE/Dialogs/GDCoreDialogs.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/GDCore/IDE/Dialogs/GDCoreDialogs.h" "${CMAKE_CURRENT_SOURCE_DIR}/GDCore/IDE/Dialogs/GDCoreDialogs_dialogs_bitmaps.cpp")
file(
GLOB_RECURSE
formatted_source_files
tests/*
GDCore/Events/*
GDCore/Extensions/*
GDCore/IDE/*
GDCore/Project/*
GDCore/Serialization/*
GDCore/Tools/*)
list(
REMOVE_ITEM
formatted_source_files
"${CMAKE_CURRENT_SOURCE_DIR}/GDCore/IDE/Dialogs/GDCoreDialogs.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GDCore/IDE/Dialogs/GDCoreDialogs.h"
"${CMAKE_CURRENT_SOURCE_DIR}/GDCore/IDE/Dialogs/GDCoreDialogs_dialogs_bitmaps.cpp")
gd_add_clang_utils(GDCore "${formatted_source_files}")
IF(EMSCRIPTEN)
if(EMSCRIPTEN)
# Emscripten treats all libraries as static libraries
add_library(GDCore STATIC ${source_files})
ELSE()
else()
add_library(GDCore SHARED ${source_files})
ENDIF()
IF(EMSCRIPTEN)
endif()
if(EMSCRIPTEN)
set_target_properties(GDCore PROPERTIES SUFFIX ".bc")
ELSEIF(WIN32)
elseif(WIN32)
set_target_properties(GDCore PROPERTIES PREFIX "")
ELSE()
else()
set_target_properties(GDCore PROPERTIES PREFIX "lib")
ENDIF()
endif()
set(LIBRARY_OUTPUT_PATH ${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME})
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})
#Tests
###
# Tests
#
if(BUILD_TESTS)
file(
GLOB_RECURSE
test_source_files
tests/*
)
GLOB_RECURSE
test_source_files
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.
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 ${CMAKE_DL_LIBS})
endif()

View File

@@ -267,11 +267,11 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
return "/* Unknown instruction - skipped. */";
}
AddIncludeFiles(instrInfos.codeExtraInformation.GetIncludeFiles());
AddIncludeFiles(instrInfos.GetIncludeFiles());
maxConditionsListsSize =
std::max(maxConditionsListsSize, condition.GetSubInstructions().size());
if (instrInfos.codeExtraInformation.HasCustomCodeGenerator()) {
if (instrInfos.HasCustomCodeGenerator()) {
context.EnterCustomCondition();
conditionCode += instrInfos.codeExtraInformation.customCodeGenerator(
condition, *this, context);
@@ -459,9 +459,9 @@ gd::String EventsCodeGenerator::GenerateActionCode(
return "/* Unknown instruction - skipped. */";
}
AddIncludeFiles(instrInfos.codeExtraInformation.GetIncludeFiles());
AddIncludeFiles(instrInfos.GetIncludeFiles());
if (instrInfos.codeExtraInformation.HasCustomCodeGenerator()) {
if (instrInfos.HasCustomCodeGenerator()) {
return instrInfos.codeExtraInformation.customCodeGenerator(
action, *this, context);
}
@@ -1019,15 +1019,15 @@ gd::String EventsCodeGenerator::GenerateFreeCondition(
bool conditionInverted,
gd::EventsCodeGenerationContext& context) {
// Generate call
gd::String predicat;
gd::String predicate;
if (instrInfos.codeExtraInformation.type == "number" ||
instrInfos.codeExtraInformation.type == "string") {
predicat = GenerateRelationalOperatorCall(
predicate = GenerateRelationalOperatorCall(
instrInfos,
arguments,
instrInfos.codeExtraInformation.functionCallName);
} else {
predicat = instrInfos.codeExtraInformation.functionCallName + "(" +
predicate = instrInfos.codeExtraInformation.functionCallName + "(" +
GenerateArgumentsList(arguments, 0) + ")";
}
@@ -1040,10 +1040,10 @@ gd::String EventsCodeGenerator::GenerateFreeCondition(
conditionAlreadyTakeCareOfInversion = true;
}
if (!conditionAlreadyTakeCareOfInversion && conditionInverted)
predicat = GenerateNegatedPredicat(predicat);
predicate = GenerateNegatedPredicate(predicate);
// Generate condition code
return returnBoolean + " = " + predicat + ";\n";
return returnBoolean + " = " + predicate + ";\n";
}
gd::String EventsCodeGenerator::GenerateObjectCondition(
@@ -1065,18 +1065,18 @@ gd::String EventsCodeGenerator::GenerateObjectCondition(
instrInfos.codeExtraInformation.functionCallName;
// Create call
gd::String predicat;
gd::String predicate;
if ((instrInfos.codeExtraInformation.type == "number" ||
instrInfos.codeExtraInformation.type == "string")) {
predicat = GenerateRelationalOperatorCall(
predicate = GenerateRelationalOperatorCall(
instrInfos, arguments, objectFunctionCallNamePart, 1);
} else {
predicat = objectFunctionCallNamePart + "(" +
predicate = objectFunctionCallNamePart + "(" +
GenerateArgumentsList(arguments, 1) + ")";
}
if (conditionInverted) predicat = GenerateNegatedPredicat(predicat);
if (conditionInverted) predicate = GenerateNegatedPredicate(predicate);
return "For each picked object \"" + objectName + "\", check " + predicat +
return "For each picked object \"" + objectName + "\", check " + predicate +
".\n";
}
@@ -1090,16 +1090,16 @@ gd::String EventsCodeGenerator::GenerateBehaviorCondition(
bool conditionInverted,
gd::EventsCodeGenerationContext& context) {
// Create call
gd::String predicat;
gd::String predicate;
if ((instrInfos.codeExtraInformation.type == "number" ||
instrInfos.codeExtraInformation.type == "string")) {
predicat = GenerateRelationalOperatorCall(instrInfos, arguments, "", 2);
predicate = GenerateRelationalOperatorCall(instrInfos, arguments, "", 2);
} else {
predicat = "(" + GenerateArgumentsList(arguments, 2) + ")";
predicate = "(" + GenerateArgumentsList(arguments, 2) + ")";
}
if (conditionInverted) predicat = GenerateNegatedPredicat(predicat);
if (conditionInverted) predicate = GenerateNegatedPredicate(predicate);
return "For each picked object \"" + objectName + "\", check " + predicat +
return "For each picked object \"" + objectName + "\", check " + predicate +
" for behavior \"" + behaviorName + "\".\n";
}

View File

@@ -668,13 +668,13 @@ class GD_CORE_API EventsCodeGenerator {
};
/**
* \brief Must negate a predicat.
* \brief Must negate a predicate.
*
* The default implementation generates C-style code : It wraps the predicat
* The default implementation generates C-style code : It wraps the predicate
* inside parenthesis and add a !.
*/
virtual gd::String GenerateNegatedPredicat(const gd::String& predicat) const {
return "!(" + predicat + ")";
virtual gd::String GenerateNegatedPredicate(const gd::String& predicate) const {
return "!(" + predicate + ")";
};
virtual gd::String GenerateFreeCondition(

View File

@@ -216,10 +216,10 @@ gd::String ExpressionCodeGenerator::GenerateFreeFunctionCode(
const std::vector<std::unique_ptr<ExpressionNode>>& parameters,
const ExpressionMetadata& expressionMetadata) {
codeGenerator.AddIncludeFiles(
expressionMetadata.codeExtraInformation.GetIncludeFiles());
expressionMetadata.GetIncludeFiles());
// Launch custom code generator if needed
if (expressionMetadata.codeExtraInformation.HasCustomCodeGenerator()) {
if (expressionMetadata.HasCustomCodeGenerator()) {
return expressionMetadata.codeExtraInformation.customCodeGenerator(
PrintParameters(parameters), codeGenerator, context);
}
@@ -242,10 +242,10 @@ gd::String ExpressionCodeGenerator::GenerateObjectFunctionCode(
codeGenerator.GetObjectsAndGroups();
codeGenerator.AddIncludeFiles(
expressionMetadata.codeExtraInformation.GetIncludeFiles());
expressionMetadata.GetIncludeFiles());
// Launch custom code generator if needed
if (expressionMetadata.codeExtraInformation.HasCustomCodeGenerator()) {
if (expressionMetadata.HasCustomCodeGenerator()) {
return expressionMetadata.codeExtraInformation.customCodeGenerator(
PrintParameters(parameters), codeGenerator, context);
}
@@ -300,10 +300,10 @@ gd::String ExpressionCodeGenerator::GenerateBehaviorFunctionCode(
codeGenerator.GetObjectsAndGroups();
codeGenerator.AddIncludeFiles(
expressionMetadata.codeExtraInformation.GetIncludeFiles());
expressionMetadata.GetIncludeFiles());
// Launch custom code generator if needed
if (expressionMetadata.codeExtraInformation.HasCustomCodeGenerator()) {
if (expressionMetadata.HasCustomCodeGenerator()) {
return expressionMetadata.codeExtraInformation.customCodeGenerator(
PrintParameters(parameters), codeGenerator, context);
}

View File

@@ -17,7 +17,7 @@ const gd::String& EventsCodeNameMangler::GetMangledObjectsListName(
return it->second;
}
gd::String partiallyMangledName = originalObjectName;
gd::String partiallyMangledName = GetMangledNameWithForbiddenUnderscore(originalObjectName);
static const gd::String allowedCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
@@ -43,7 +43,15 @@ const gd::String& EventsCodeNameMangler::GetExternalEventsFunctionMangledName(
return it->second;
}
gd::String partiallyMangledName = externalEventsName;
gd::String partiallyMangledName = GetMangledNameWithForbiddenUnderscore(externalEventsName);
mangledExternalEventsNames[externalEventsName] = "GDExternalEvents" + partiallyMangledName;
return mangledExternalEventsNames[externalEventsName];
}
gd::String EventsCodeNameMangler::GetMangledNameWithForbiddenUnderscore(
const gd::String &name) {
gd::String partiallyMangledName = name;
static const gd::String allowedCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
@@ -57,11 +65,30 @@ const gd::String& EventsCodeNameMangler::GetExternalEventsFunctionMangledName(
partiallyMangledName.replace(i, 1, "_" + gd::String::From(unallowedChar));
}
}
mangledExternalEventsNames[externalEventsName] = "GDExternalEvents" + partiallyMangledName;
return mangledExternalEventsNames[externalEventsName];
return partiallyMangledName;
}
gd::String EventsCodeNameMangler::GetMangledName(
const gd::String &name) {
gd::String partiallyMangledName = name;
static const gd::String allowedCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
for (size_t i = 0; i < partiallyMangledName.size();
++i) // Replace all unallowed letter by an underscore and the ascii
// number of the letter
{
if (allowedCharacters.find_first_of(
std::u32string(1, partiallyMangledName[i])) == gd::String::npos) {
char32_t unallowedChar = partiallyMangledName[i];
partiallyMangledName.replace(i, 1, "_" + gd::String::From(unallowedChar));
}
}
return partiallyMangledName;
}
const gd::String& ManObjListName(const gd::String &objectName) {
return EventsCodeNameMangler::Get()->GetMangledObjectsListName(objectName);
}

View File

@@ -36,6 +36,8 @@ class GD_CORE_API EventsCodeNameMangler {
const gd::String &GetExternalEventsFunctionMangledName(
const gd::String &externalEventsName);
static gd::String GetMangledName(const gd::String &name);
static EventsCodeNameMangler *Get();
static void DestroySingleton();
@@ -44,6 +46,9 @@ class GD_CORE_API EventsCodeNameMangler {
virtual ~EventsCodeNameMangler(){};
static EventsCodeNameMangler *_singleton;
// This method is inlined to avoid to copy the returned string.
static inline gd::String GetMangledNameWithForbiddenUnderscore(const gd::String &name);
std::unordered_map<gd::String, gd::String>
mangledObjectNames; ///< Memoized results of mangling for objects
std::unordered_map<gd::String, gd::String>

View File

@@ -110,11 +110,11 @@ void Direction::UnserializeFrom(const gd::SerializerElement& element) {
.GetBoolAttribute("automatic", true));
if (spriteElement.HasChild("CustomCollisionMask"))
sprite.SetCollisionMaskAutomatic(
sprite.SetFullImageCollisionMask(
!spriteElement.GetChild("CustomCollisionMask")
.GetBoolAttribute("custom", false));
else
sprite.SetCollisionMaskAutomatic(
sprite.SetFullImageCollisionMask(
!spriteElement.GetBoolAttribute("hasCustomCollisionMask", false));
std::vector<Polygon2d> mask;
@@ -173,7 +173,7 @@ void SaveSpritesDirection(const vector<Sprite>& sprites,
.SetAttribute("automatic", sprites[i].IsDefaultCenterPoint());
spriteElement.SetAttribute("hasCustomCollisionMask",
!sprites[i].IsCollisionMaskAutomatic());
!sprites[i].IsFullImageCollisionMask());
gd::SerializerElement& collisionMaskElement =
spriteElement.AddChild("customCollisionMask");

View File

@@ -4,7 +4,9 @@
* reserved. This project is released under the MIT License.
*/
#include "GDCore/Extensions/Builtin/SpriteExtension/Sprite.h"
#include <iostream>
#include "GDCore/Extensions/Builtin/SpriteExtension/Polygon2d.h"
using namespace std;
@@ -14,11 +16,10 @@ namespace gd {
Point Sprite::badPoint("");
Sprite::Sprite()
: automaticCollisionMask(true),
: fullImageCollisionMask(false),
origine("origine"),
centre("centre"),
automaticCentre(true) {
}
automaticCentre(true) {}
Sprite::~Sprite(){};

View File

@@ -7,6 +7,7 @@
#ifndef SPRITE_H
#define SPRITE_H
#include <memory>
#include "GDCore/Extensions/Builtin/SpriteExtension/Point.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/Polygon2d.h"
#include "GDCore/String.h"
@@ -43,7 +44,7 @@ class GD_CORE_API Sprite {
/**
* \brief Get the collision mask (custom or automatically generated owing to
* IsCollisionMaskAutomatic())
* IsFullImageCollisionMask())
*
* \warning If the image has not been loaded ( using LoadImage ) and the
* collision mask is set as automatic, the returned mask won't be correct.
@@ -66,7 +67,7 @@ class GD_CORE_API Sprite {
/**
* \brief Set the custom collision mask.
* Call then `SetCollisionMaskAutomatic(false)` to use it.
* Call then `SetFullImageCollisionMask(false)` to use it.
*/
void SetCustomCollisionMask(const std::vector<Polygon2d>& collisionMask);
@@ -74,15 +75,15 @@ class GD_CORE_API Sprite {
* \brief Return true if the collision mask is a bounding box, false if a
* custom collision mask is used.
*/
inline bool IsCollisionMaskAutomatic() const {
return automaticCollisionMask;
inline bool IsFullImageCollisionMask() const {
return fullImageCollisionMask;
}
/**
* \brief Un/set use of the custom collision mask.
*/
inline void SetCollisionMaskAutomatic(bool enabled) {
automaticCollisionMask = enabled;
inline void SetFullImageCollisionMask(bool enabled) {
fullImageCollisionMask = enabled;
};
/**
@@ -161,9 +162,9 @@ class GD_CORE_API Sprite {
private:
gd::String image; ///< Name of the image to be loaded in Image Manager.
bool automaticCollisionMask; ///< True to use the custom collision mask.
///< Otherwise, a basic bounding box is returned
///< by GetCollisionMask()
bool fullImageCollisionMask; ///< True to use a bounding box wrapping the
///< whole image as collision mask. If false,
///< custom collision mask is used.
std::vector<Polygon2d> customCollisionMask; ///< Custom collision mask
std::vector<Point> points; ///< List of the points used by the sprite

View File

@@ -287,7 +287,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
obj.AddCondition("AnimationName",
_("Current animation name"),
_("Check the animation by played by the object."),
_("Check the animation played by the object."),
_("The animation of _PARAM0_ is _PARAM1_"),
_("Animations and images"),
"res/conditions/animation24.png",

View File

@@ -25,13 +25,16 @@ namespace gd {
Animation SpriteObject::badAnimation;
SpriteObject::SpriteObject() : updateIfNotVisible(false) {}
SpriteObject::SpriteObject()
: updateIfNotVisible(false), adaptCollisionMaskAutomatically(true) {}
SpriteObject::~SpriteObject(){};
void SpriteObject::DoUnserializeFrom(gd::Project& project,
const gd::SerializerElement& element) {
updateIfNotVisible = element.GetBoolAttribute("updateIfNotVisible", true);
adaptCollisionMaskAutomatically =
element.GetBoolAttribute("adaptCollisionMaskAutomatically", false);
RemoveAllAnimations();
const gd::SerializerElement& animationsElement =
@@ -80,6 +83,8 @@ void SpriteObject::DoUnserializeFrom(gd::Project& project,
void SpriteObject::DoSerializeTo(gd::SerializerElement& element) const {
element.SetAttribute("updateIfNotVisible", updateIfNotVisible);
element.SetAttribute("adaptCollisionMaskAutomatically",
adaptCollisionMaskAutomatically);
// Animations
gd::SerializerElement& animationsElement = element.AddChild("animations");

View File

@@ -47,8 +47,7 @@ class GD_CORE_API SpriteObject : public gd::ObjectConfiguration {
void ExposeResources(gd::ArbitraryResourceWorker& worker) override;
std::map<gd::String, gd::PropertyDescriptor> GetProperties() const override;
bool UpdateProperty(const gd::String& name,
const gd::String& value) override;
bool UpdateProperty(const gd::String& name, const gd::String& value) override;
std::map<gd::String, gd::PropertyDescriptor> GetInitialInstanceProperties(
const gd::InitialInstance& position,
@@ -118,14 +117,30 @@ class GD_CORE_API SpriteObject : public gd::ObjectConfiguration {
const std::vector<Animation>& GetAllAnimations() const { return animations; }
/**
* \brief Set if the object animation should be played even if the object is hidden
* or far from the camera.
* @brief Check if the collision mask adapts automatically to the animation.
*/
void SetUpdateIfNotVisible(bool updateIfNotVisible_) { updateIfNotVisible = updateIfNotVisible_; }
bool AdaptCollisionMaskAutomatically() const {
return adaptCollisionMaskAutomatically;
}
/**
* \brief Check if the object animation should be played even if the object is hidden
* or far from the camera (false by default).
* @brief Set if the collision mask adapts automatically to the animation.
*/
void SetAdaptCollisionMaskAutomatically(bool enable) {
adaptCollisionMaskAutomatically = enable;
}
/**
* \brief Set if the object animation should be played even if the object is
* hidden or far from the camera.
*/
void SetUpdateIfNotVisible(bool updateIfNotVisible_) {
updateIfNotVisible = updateIfNotVisible_;
}
/**
* \brief Check if the object animation should be played even if the object
* is hidden or far from the camera (false by default).
*/
bool GetUpdateIfNotVisible() const { return updateIfNotVisible; }
///@}
@@ -137,11 +152,15 @@ class GD_CORE_API SpriteObject : public gd::ObjectConfiguration {
mutable std::vector<Animation> animations;
bool updateIfNotVisible; ///< If set to true, ask the game engine to play
///< object animation even if hidden or far from the
///< screen.
///< object animation even if hidden or far from
///< the screen.
static Animation badAnimation; //< Bad animation when an out of bound
// animation is requested.
static Animation badAnimation; //< Bad animation when an out of bound
// animation is requested.
bool adaptCollisionMaskAutomatically; ///< If set to true, the collision
///< mask will be automatically
///< adapted to the animation of the
///< object.
};
} // namespace gd

View File

@@ -172,7 +172,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
_("Search the last occurrence in a text, starting from a position"),
_("Search in a text the last occurrence, starting from a position "
"(return "
" the position of the result, from the beginning of the string, or "
"the position of the result, from the beginning of the string, or "
"-1 if not found)"),
"",
"res/conditions/toujours24_black.png")

View File

@@ -0,0 +1,135 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include <algorithm>
#include <functional>
#include <map>
#include <memory>
#include "GDCore/Events/Instruction.h"
#include "GDCore/String.h"
#include "ParameterMetadata.h"
#include "ParameterOptions.h"
namespace gd {
class Project;
class Layout;
class EventsCodeGenerator;
class EventsCodeGenerationContext;
class SerializerElement;
} // namespace gd
namespace gd {
/**
* \brief Describe user-friendly information about an expression or an
* instruction (action or condition), its parameters and the function name as
* well as other information for code generation.
*
* \ingroup Events
*/
class GD_CORE_API AbstractFunctionMetadata {
public:
AbstractFunctionMetadata(){};
virtual ~AbstractFunctionMetadata(){};
/**
* \see gd::InstructionMetadata::AddParameter
*/
virtual AbstractFunctionMetadata &
AddParameter(const gd::String &type, const gd::String &label,
const gd::String &supplementaryInformation = "",
bool parameterIsOptional = false) = 0;
/**
* \see gd::InstructionMetadata::AddCodeOnlyParameter
*/
virtual AbstractFunctionMetadata &
AddCodeOnlyParameter(const gd::String &type,
const gd::String &supplementaryInformation) = 0;
/**
* \see gd::InstructionMetadata::SetDefaultValue
*/
virtual AbstractFunctionMetadata &
SetDefaultValue(const gd::String &defaultValue) = 0;
/**
* \see gd::InstructionMetadata::SetParameterExtraInfo
*/
virtual AbstractFunctionMetadata &
SetParameterExtraInfo(const gd::String &defaultValue) = 0;
/**
* \see gd::InstructionMetadata::SetParameterLongDescription
*/
virtual AbstractFunctionMetadata &
SetParameterLongDescription(const gd::String &longDescription) = 0;
/**
* \see gd::InstructionMetadata::SetHidden
*/
virtual AbstractFunctionMetadata &SetHidden() = 0;
/**
* Set that the instruction is private - it can't be used outside of the
* object/ behavior that it is attached too.
*/
virtual AbstractFunctionMetadata &SetPrivate() = 0;
/**
* Set that the instruction can be used in layouts or external events.
*/
virtual AbstractFunctionMetadata &SetRelevantForLayoutEventsOnly() = 0;
/**
* Set that the instruction can be used in function events.
*/
virtual AbstractFunctionMetadata &SetRelevantForFunctionEventsOnly() = 0;
/**
* Set that the instruction can be used in asynchronous function events.
*/
virtual AbstractFunctionMetadata &
SetRelevantForAsynchronousFunctionEventsOnly() = 0;
/**
* Set that the instruction can be used in custom object events.
*/
virtual AbstractFunctionMetadata &SetRelevantForCustomObjectEventsOnly() = 0;
/**
* \brief Set the function that should be called when generating the source
* code from events.
* \param functionName the name of the function to call
* \note Shortcut for `codeExtraInformation.SetFunctionName`.
*/
virtual AbstractFunctionMetadata &
SetFunctionName(const gd::String &functionName) = 0;
/**
* \brief Erase any existing include file and add the specified include.
*/
virtual AbstractFunctionMetadata &
SetIncludeFile(const gd::String &includeFile) = 0;
/**
* \brief Add a file to the already existing include files.
*/
virtual AbstractFunctionMetadata &
AddIncludeFile(const gd::String &includeFile) = 0;
/**
* \brief Get the files that must be included to use the instruction.
*/
virtual const std::vector<gd::String> &GetIncludeFiles() const = 0;
private:
};
} // namespace gd

View File

@@ -3,8 +3,10 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef BEHAVIORMETADATA_H
#define BEHAVIORMETADATA_H
#pragma once
#include "InstructionOrExpressionContainerMetadata.h"
#include <map>
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
@@ -25,7 +27,7 @@ namespace gd {
*
* \ingroup Events
*/
class GD_CORE_API BehaviorMetadata {
class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMetadata {
public:
BehaviorMetadata(
const gd::String& extensionNamespace,
@@ -67,7 +69,7 @@ class GD_CORE_API BehaviorMetadata {
const gd::String& sentence_,
const gd::String& group_,
const gd::String& icon_,
const gd::String& smallicon_);
const gd::String& smallicon_) override;
/**
* Declare a new action as being part of the behavior.
@@ -80,7 +82,7 @@ class GD_CORE_API BehaviorMetadata {
const gd::String& sentence_,
const gd::String& group_,
const gd::String& icon_,
const gd::String& smallicon_);
const gd::String& smallicon_) override;
/**
* Declare a new condition as being part of the behavior.
@@ -91,7 +93,7 @@ class GD_CORE_API BehaviorMetadata {
const gd::String& sentence_,
const gd::String& group_,
const gd::String& icon_,
const gd::String& smallicon_);
const gd::String& smallicon_) override;
/**
* Declare a new action as being part of the behavior.
@@ -102,7 +104,7 @@ class GD_CORE_API BehaviorMetadata {
const gd::String& sentence_,
const gd::String& group_,
const gd::String& icon_,
const gd::String& smallicon_);
const gd::String& smallicon_) override;
/**
* Declare a new action as being part of the extension.
*/
@@ -110,7 +112,7 @@ class GD_CORE_API BehaviorMetadata {
const gd::String& fullname_,
const gd::String& description_,
const gd::String& group_,
const gd::String& smallicon_);
const gd::String& smallicon_) override;
/**
* Declare a new string expression as being part of the extension.
@@ -119,7 +121,7 @@ class GD_CORE_API BehaviorMetadata {
const gd::String& fullname_,
const gd::String& description_,
const gd::String& group_,
const gd::String& smallicon_);
const gd::String& smallicon_) override;
/**
* \brief Declare a new expression and condition as being part of the
@@ -134,7 +136,7 @@ class GD_CORE_API BehaviorMetadata {
const gd::String& description,
const gd::String& sentenceName,
const gd::String& group,
const gd::String& icon);
const gd::String& icon) override;
/**
* \brief Declare a new expression, condition and action as being part of the
@@ -151,7 +153,7 @@ class GD_CORE_API BehaviorMetadata {
const gd::String& description,
const gd::String& sentenceName,
const gd::String& group,
const gd::String& icon);
const gd::String& icon) override;
/**
* \brief Create a new action which is the duplicate of the specified one.
@@ -160,7 +162,7 @@ class GD_CORE_API BehaviorMetadata {
* one.
*/
gd::InstructionMetadata& AddDuplicatedAction(
const gd::String& newActionName, const gd::String& copiedActionName);
const gd::String& newActionName, const gd::String& copiedActionName) override;
/**
* \brief Create a new condition which is the duplicate of the specified one.
@@ -170,7 +172,7 @@ class GD_CORE_API BehaviorMetadata {
*/
gd::InstructionMetadata& AddDuplicatedCondition(
const gd::String& newConditionName,
const gd::String& copiedConditionName);
const gd::String& copiedConditionName) override;
/**
* \brief Create a new expression which is the duplicate of the specified one.
@@ -193,9 +195,9 @@ class GD_CORE_API BehaviorMetadata {
const gd::String& newExpressionName,
const gd::String& copiedExpressionName);
BehaviorMetadata& SetFullName(const gd::String& fullname_);
BehaviorMetadata& SetFullName(const gd::String& fullname_) override;
BehaviorMetadata& SetDefaultName(const gd::String& defaultName_);
BehaviorMetadata& SetDescription(const gd::String& description_);
BehaviorMetadata& SetDescription(const gd::String& description_) override;
BehaviorMetadata& SetGroup(const gd::String& group_);
/**
@@ -203,12 +205,12 @@ class GD_CORE_API BehaviorMetadata {
* \note The requirement may vary depending on the platform: Most of the time,
* the include file contains the declaration of the behavior.
*/
BehaviorMetadata& SetIncludeFile(const gd::String& includeFile);
BehaviorMetadata& SetIncludeFile(const gd::String& includeFile) override;
/**
* \brief Add a file to the already existing include files.
*/
BehaviorMetadata& AddIncludeFile(const gd::String& includeFile);
BehaviorMetadata& AddIncludeFile(const gd::String& includeFile) override;
/**
* \brief Add a file to the already existing required files.
@@ -221,7 +223,7 @@ class GD_CORE_API BehaviorMetadata {
* Get the help path of the behavior, relative to the GDevelop documentation
* root.
*/
const gd::String& GetHelpPath() const { return helpPath; }
const gd::String& GetHelpPath() const override { return helpPath; }
/**
* Set the help path of the behavior, relative to the GDevelop documentation
@@ -230,17 +232,17 @@ class GD_CORE_API BehaviorMetadata {
* The behavior instructions will have this help path set by
* default, unless you call SetHelpPath on them.
*/
BehaviorMetadata& SetHelpPath(const gd::String& path) {
BehaviorMetadata& SetHelpPath(const gd::String& path) override {
helpPath = path;
return *this;
}
const gd::String& GetName() const;
const gd::String& GetFullName() const { return fullname; }
const gd::String& GetName() const override;
const gd::String& GetFullName() const override { return fullname; }
const gd::String& GetDefaultName() const { return defaultName; }
const gd::String& GetDescription() const { return description; }
const gd::String& GetDescription() const override { return description; }
const gd::String& GetGroup() const { return group; }
const gd::String& GetIconFilename() const { return iconFilename; }
const gd::String& GetIconFilename() const override { return iconFilename; }
/**
* \brief Set the type of the object that this behavior can be used on.
@@ -293,22 +295,22 @@ class GD_CORE_API BehaviorMetadata {
* \brief Return a reference to a map containing the names of the actions
* (as keys) and the metadata associated with (as values).
*/
std::map<gd::String, gd::InstructionMetadata>& GetAllActions() { return actionsInfos; };
std::map<gd::String, gd::InstructionMetadata>& GetAllActions() override { return actionsInfos; };
/**
* \see gd::PlatformExtension::GetAllActions
*/
std::map<gd::String, gd::InstructionMetadata>& GetAllConditions() { return conditionsInfos; };
std::map<gd::String, gd::InstructionMetadata>& GetAllConditions() override { return conditionsInfos; };
/**
* \see gd::PlatformExtension::GetAllActions
*/
std::map<gd::String, gd::ExpressionMetadata>& GetAllExpressions() { return expressionsInfos; };
std::map<gd::String, gd::ExpressionMetadata>& GetAllExpressions() override { return expressionsInfos; };
/**
* \see gd::PlatformExtension::GetAllActions
*/
std::map<gd::String, gd::ExpressionMetadata>& GetAllStrExpressions() { return strExpressionsInfos; };
std::map<gd::String, gd::ExpressionMetadata>& GetAllStrExpressions() override { return strExpressionsInfos; };
std::map<gd::String, gd::InstructionMetadata> conditionsInfos;
std::map<gd::String, gd::InstructionMetadata> actionsInfos;
@@ -337,5 +339,3 @@ class GD_CORE_API BehaviorMetadata {
};
} // namespace gd
#endif // BEHAVIORMETADATA_H

View File

@@ -3,9 +3,10 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef EXPRESSIONMETADATA_H
#define EXPRESSIONMETADATA_H
#if defined(GD_IDE_ONLY)
#pragma once
#include "AbstractFunctionMetadata.h"
#include <functional>
#include <memory>
@@ -17,7 +18,6 @@ class Layout;
}
namespace gd {
/**
* \brief Information about how generate code for an expression
*/
@@ -27,79 +27,7 @@ class ExpressionCodeGenerationInformation {
: staticFunction(false), hasCustomCodeGenerator(false){};
virtual ~ExpressionCodeGenerationInformation(){};
/**
* \brief Set the function name which will be used when generating the code.
* \param functionName the name of the function to call
*/
ExpressionCodeGenerationInformation& SetFunctionName(
const gd::String& functionName) {
functionCallName = functionName;
return *this;
}
/**
* \brief Set that the function is static
*/
ExpressionCodeGenerationInformation& SetStatic() {
staticFunction = true;
return *this;
}
/**
* \brief Erase any existing include file and add the specified include.
*/
ExpressionCodeGenerationInformation& SetIncludeFile(
const gd::String& includeFile) {
includeFiles.clear();
includeFiles.push_back(includeFile);
return *this;
}
/**
* \brief Add a file to the already existing include files.
*/
ExpressionCodeGenerationInformation& AddIncludeFile(
const gd::String& includeFile) {
if (std::find(includeFiles.begin(), includeFiles.end(), includeFile) ==
includeFiles.end())
includeFiles.push_back(includeFile);
return *this;
}
/**
* \brief Get the files that must be included to use the instruction.
*/
const std::vector<gd::String>& GetIncludeFiles() const {
return includeFiles;
};
/**
* \brief Set that the function must be generated using a custom code
* generator.
*/
ExpressionCodeGenerationInformation& SetCustomCodeGenerator(
std::function<gd::String(const std::vector<gd::Expression>& parameters,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context)>
codeGenerator) {
hasCustomCodeGenerator = true;
customCodeGenerator = codeGenerator;
return *this;
}
ExpressionCodeGenerationInformation& RemoveCustomCodeGenerator() {
hasCustomCodeGenerator = false;
std::function<gd::String(const std::vector<gd::Expression>& parameters,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context)>
emptyFunction;
customCodeGenerator = emptyFunction;
return *this;
}
bool HasCustomCodeGenerator() const { return hasCustomCodeGenerator; }
// TODO Move these attributes to ExpressionMetadata.
bool staticFunction;
gd::String functionCallName;
bool hasCustomCodeGenerator;
@@ -107,8 +35,6 @@ class ExpressionCodeGenerationInformation {
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context)>
customCodeGenerator;
private:
std::vector<gd::String> includeFiles;
};
@@ -118,7 +44,7 @@ class ExpressionCodeGenerationInformation {
*
* \ingroup Events
*/
class GD_CORE_API ExpressionMetadata {
class GD_CORE_API ExpressionMetadata : public gd::AbstractFunctionMetadata {
public:
/**
* Construct a new expression metadata.
@@ -144,7 +70,7 @@ class GD_CORE_API ExpressionMetadata {
/**
* \brief Set the expression as not shown in the IDE.
*/
ExpressionMetadata& SetHidden();
ExpressionMetadata& SetHidden() override;
/**
* \brief Set the group of the instruction in the IDE.
@@ -179,7 +105,7 @@ class GD_CORE_API ExpressionMetadata {
* Set that the instruction is private - it can't be used outside of the
* object/ behavior that it is attached too.
*/
ExpressionMetadata& SetPrivate() {
ExpressionMetadata& SetPrivate() override {
isPrivate = true;
return *this;
}
@@ -216,7 +142,7 @@ class GD_CORE_API ExpressionMetadata {
/**
* Set that the instruction can be used in layouts or external events.
*/
ExpressionMetadata &SetRelevantForLayoutEventsOnly() {
ExpressionMetadata &SetRelevantForLayoutEventsOnly() override {
relevantContext = "Layout";
return *this;
}
@@ -224,7 +150,7 @@ class GD_CORE_API ExpressionMetadata {
/**
* Set that the instruction can be used in function events.
*/
ExpressionMetadata &SetRelevantForFunctionEventsOnly() {
ExpressionMetadata &SetRelevantForFunctionEventsOnly() override {
relevantContext = "Function";
return *this;
}
@@ -232,7 +158,7 @@ class GD_CORE_API ExpressionMetadata {
/**
* Set that the instruction can be used in asynchronous function events.
*/
ExpressionMetadata &SetRelevantForAsynchronousFunctionEventsOnly() {
ExpressionMetadata &SetRelevantForAsynchronousFunctionEventsOnly() override {
relevantContext = "AsynchronousFunction";
return *this;
}
@@ -240,7 +166,7 @@ class GD_CORE_API ExpressionMetadata {
/**
* Set that the instruction can be used in custom object events.
*/
ExpressionMetadata &SetRelevantForCustomObjectEventsOnly() {
ExpressionMetadata &SetRelevantForCustomObjectEventsOnly() override {
relevantContext = "Object";
return *this;
}
@@ -248,17 +174,17 @@ class GD_CORE_API ExpressionMetadata {
/**
* \see gd::InstructionMetadata::AddParameter
*/
gd::ExpressionMetadata& AddParameter(
const gd::String& type,
const gd::String& description,
const gd::String& supplementaryInformation = "",
bool parameterIsOptional = false);
gd::ExpressionMetadata &
AddParameter(const gd::String &type, const gd::String &label,
const gd::String &supplementaryInformation = "",
bool parameterIsOptional = false) override;
/**
* \see gd::InstructionMetadata::AddCodeOnlyParameter
*/
gd::ExpressionMetadata& AddCodeOnlyParameter(
const gd::String& type, const gd::String& supplementaryInformation);
gd::ExpressionMetadata &
AddCodeOnlyParameter(const gd::String &type,
const gd::String &supplementaryInformation) override;
/**
* Set the default value used in editor (or if an optional parameter is empty
@@ -266,8 +192,9 @@ class GD_CORE_API ExpressionMetadata {
*
* \see AddParameter
*/
ExpressionMetadata& SetDefaultValue(gd::String defaultValue_) {
if (!parameters.empty()) parameters.back().SetDefaultValue(defaultValue_);
ExpressionMetadata &SetDefaultValue(const gd::String &defaultValue) override {
if (!parameters.empty())
parameters.back().SetDefaultValue(defaultValue);
return *this;
};
@@ -277,7 +204,8 @@ class GD_CORE_API ExpressionMetadata {
*
* \see AddParameter
*/
ExpressionMetadata& SetParameterLongDescription(gd::String longDescription) {
ExpressionMetadata &
SetParameterLongDescription(const gd::String &longDescription) override {
if (!parameters.empty())
parameters.back().SetLongDescription(longDescription);
return *this;
@@ -290,7 +218,8 @@ class GD_CORE_API ExpressionMetadata {
*
* \see AddParameter
*/
ExpressionMetadata &SetParameterExtraInfo(const gd::String &extraInfo) {
ExpressionMetadata &SetParameterExtraInfo(
const gd::String &extraInfo) override {
if (!parameters.empty()) parameters.back().SetExtraInfo(extraInfo);
return *this;
}
@@ -312,50 +241,6 @@ class GD_CORE_API ExpressionMetadata {
return requiredBaseObjectCapability;
};
/**
* \brief Set the function that should be called when generating the source
* code from events.
* \param functionName the name of the function to call
* \note Shortcut for `codeExtraInformation.SetFunctionName`.
*/
ExpressionCodeGenerationInformation& SetFunctionName(
const gd::String& functionName) {
return codeExtraInformation.SetFunctionName(functionName);
}
/**
* \brief Return the structure containing the information about code
* generation for the expression.
*/
ExpressionCodeGenerationInformation& GetCodeExtraInformation() {
return codeExtraInformation;
}
/**
* \brief Erase any existing include file and add the specified include.
*/
ExpressionMetadata &SetIncludeFile(const gd::String &includeFile) {
codeExtraInformation.SetIncludeFile(includeFile);
return *this;
}
/**
* \brief Add a file to the already existing include files.
*/
ExpressionMetadata &AddIncludeFile(const gd::String &includeFile) {
codeExtraInformation.AddIncludeFile(includeFile);
return *this;
}
/**
* \brief Get the files that must be included to use the instruction.
*/
const std::vector<gd::String>& GetIncludeFiles() const {
return codeExtraInformation.GetIncludeFiles();
}
ExpressionCodeGenerationInformation codeExtraInformation;
bool IsShown() const { return shown; }
const gd::String& GetReturnType() const { return returnType; }
const gd::String& GetFullName() const { return fullname; }
@@ -375,6 +260,99 @@ class GD_CORE_API ExpressionMetadata {
std::vector<gd::ParameterMetadata> parameters;
/**
* \brief Set the function name which will be used when generating the code.
* \param functionName the name of the function to call
*/
ExpressionMetadata& SetFunctionName(
const gd::String& functionName) override {
codeExtraInformation.functionCallName = functionName;
return *this;
}
/**
* \brief Return the name of the function which will be called in the generated code.
*/
const gd::String &GetFunctionName() {
return codeExtraInformation.functionCallName;
}
/**
* \brief Set that the function is static
*/
ExpressionMetadata& SetStatic() {
codeExtraInformation.staticFunction = true;
return *this;
}
/**
* \brief Erase any existing include file and add the specified include.
*/
ExpressionMetadata& SetIncludeFile(
const gd::String& includeFile) override {
codeExtraInformation.includeFiles.clear();
codeExtraInformation.includeFiles.push_back(includeFile);
return *this;
}
/**
* \brief Add a file to the already existing include files.
*/
ExpressionMetadata& AddIncludeFile(
const gd::String& includeFile) override {
if (std::find(codeExtraInformation.includeFiles.begin(), codeExtraInformation.includeFiles.end(), includeFile) ==
codeExtraInformation.includeFiles.end())
codeExtraInformation.includeFiles.push_back(includeFile);
return *this;
}
/**
* \brief Get the files that must be included to use the instruction.
*/
const std::vector<gd::String>& GetIncludeFiles() const override {
return codeExtraInformation.includeFiles;
};
/**
* \brief Set that the function must be generated using a custom code
* generator.
*/
ExpressionMetadata& SetCustomCodeGenerator(
std::function<gd::String(const std::vector<gd::Expression>& parameters,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context)>
codeGenerator) {
codeExtraInformation.hasCustomCodeGenerator = true;
codeExtraInformation.customCodeGenerator = codeGenerator;
return *this;
}
ExpressionMetadata& RemoveCustomCodeGenerator() {
codeExtraInformation.hasCustomCodeGenerator = false;
std::function<gd::String(const std::vector<gd::Expression>& parameters,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context)>
emptyFunction;
codeExtraInformation.customCodeGenerator = emptyFunction;
return *this;
}
bool HasCustomCodeGenerator() const { return codeExtraInformation.hasCustomCodeGenerator; }
/**
* \brief Return the structure containing the information about code
* generation for the expression.
*
* \deprecated
*/
ExpressionMetadata& GetCodeExtraInformation() {
return *this;
}
ExpressionCodeGenerationInformation codeExtraInformation;
private:
gd::String returnType;
gd::String fullname;
@@ -391,6 +369,3 @@ class GD_CORE_API ExpressionMetadata {
};
} // namespace gd
#endif
#endif // EXPRESSIONMETADATA_H

View File

@@ -4,8 +4,10 @@
* reserved. This project is released under the MIT License.
*/
#ifndef INSTRUCTIONMETADATA_H
#define INSTRUCTIONMETADATA_H
#pragma once
#include "AbstractFunctionMetadata.h"
#include <algorithm>
#include <functional>
#include <map>
@@ -33,7 +35,7 @@ namespace gd {
*
* \ingroup Events
*/
class GD_CORE_API InstructionMetadata {
class GD_CORE_API InstructionMetadata : public gd::AbstractFunctionMetadata {
public:
/**
* Construct a new instruction metadata.
@@ -96,7 +98,7 @@ class GD_CORE_API InstructionMetadata {
* Set that the instruction is private - it can't be used outside of the
* object/ behavior that it is attached too.
*/
InstructionMetadata &SetPrivate() {
InstructionMetadata &SetPrivate() override {
isPrivate = true;
return *this;
}
@@ -133,7 +135,7 @@ class GD_CORE_API InstructionMetadata {
/**
* Set that the instruction can be used in layouts or external events.
*/
InstructionMetadata &SetRelevantForLayoutEventsOnly() {
InstructionMetadata &SetRelevantForLayoutEventsOnly() override {
relevantContext = "Layout";
return *this;
}
@@ -141,7 +143,7 @@ class GD_CORE_API InstructionMetadata {
/**
* Set that the instruction can be used in function events.
*/
InstructionMetadata &SetRelevantForFunctionEventsOnly() {
InstructionMetadata &SetRelevantForFunctionEventsOnly() override {
relevantContext = "Function";
return *this;
}
@@ -149,7 +151,7 @@ class GD_CORE_API InstructionMetadata {
/**
* Set that the instruction can be used in asynchronous function events.
*/
InstructionMetadata &SetRelevantForAsynchronousFunctionEventsOnly() {
InstructionMetadata &SetRelevantForAsynchronousFunctionEventsOnly() override {
relevantContext = "AsynchronousFunction";
return *this;
}
@@ -157,7 +159,7 @@ class GD_CORE_API InstructionMetadata {
/**
* Set that the instruction can be used in custom object events.
*/
InstructionMetadata &SetRelevantForCustomObjectEventsOnly() {
InstructionMetadata &SetRelevantForCustomObjectEventsOnly() override {
relevantContext = "Object";
return *this;
}
@@ -192,7 +194,7 @@ class GD_CORE_API InstructionMetadata {
*
* Used mainly when an instruction is deprecated.
*/
InstructionMetadata &SetHidden() {
InstructionMetadata &SetHidden() override {
hidden = true;
return *this;
}
@@ -231,7 +233,7 @@ class GD_CORE_API InstructionMetadata {
const gd::String &type,
const gd::String &label,
const gd::String &supplementaryInformation = "",
bool parameterIsOptional = false);
bool parameterIsOptional = false) override;
/**
* \brief Add a parameter not displayed in editor.
@@ -245,7 +247,7 @@ class GD_CORE_API InstructionMetadata {
* \see EventsCodeGenerator::GenerateParametersCodes
*/
InstructionMetadata &AddCodeOnlyParameter(
const gd::String &type, const gd::String &supplementaryInformation);
const gd::String &type, const gd::String &supplementaryInformation) override;
/**
* \brief Set the default value used in editor (or if an optional parameter is
@@ -253,7 +255,7 @@ class GD_CORE_API InstructionMetadata {
*
* \see AddParameter
*/
InstructionMetadata &SetDefaultValue(const gd::String &defaultValue_) {
InstructionMetadata &SetDefaultValue(const gd::String &defaultValue_) override {
if (!parameters.empty()) parameters.back().SetDefaultValue(defaultValue_);
return *this;
};
@@ -265,7 +267,7 @@ class GD_CORE_API InstructionMetadata {
* \see AddParameter
*/
InstructionMetadata &SetParameterLongDescription(
const gd::String &longDescription) {
const gd::String &longDescription) override {
if (!parameters.empty())
parameters.back().SetLongDescription(longDescription);
return *this;
@@ -278,7 +280,7 @@ class GD_CORE_API InstructionMetadata {
*
* \see AddParameter
*/
InstructionMetadata &SetParameterExtraInfo(const gd::String &extraInfo) {
InstructionMetadata &SetParameterExtraInfo(const gd::String &extraInfo) override {
if (!parameters.empty()) parameters.back().SetExtraInfo(extraInfo);
return *this;
}
@@ -382,128 +384,13 @@ class GD_CORE_API InstructionMetadata {
/**
* \brief Defines information about how generate the code for an instruction
*/
class ExtraInformation {
class ExtraInformation {
public:
enum AccessType { Reference, MutatorAndOrAccessor, Mutators };
ExtraInformation() : accessType(Reference), hasCustomCodeGenerator(false){};
virtual ~ExtraInformation(){};
/**
* Set the name of the function which will be called in the generated code.
* \param functionName the name of the function to call.
*/
ExtraInformation &SetFunctionName(const gd::String &functionName_) {
functionCallName = functionName_;
return *this;
}
/**
* Set the name of the function, doing asynchronous work, which will be
* called in the generated code. This function should return an asynchronous
* task (i.e: `gdjs.AsyncTask` in the JavaScript runtime).
*
* \param functionName the name of the function doing asynchronous work to
* call.
*/
ExtraInformation &SetAsyncFunctionName(const gd::String &functionName_) {
asyncFunctionCallName = functionName_;
return *this;
}
/**
* Declare if the instruction being declared is somewhat manipulating in a
* standard way.
*/
ExtraInformation &SetManipulatedType(const gd::String &type_) {
type = type_;
return *this;
}
/**
* If InstructionMetadata::ExtraInformation::SetManipulatedType was called
* with "number" or "string", this function will tell the code generator the
* name of the getter function used to retrieve the data value.
*
* Usage example:
* \code
* obj.AddAction("String",
* _("Change the string"),
* _("Change the string of a text"),
* _("the string"),
* _("Text"),
* "CppPlatform/Extensions/text24.png",
* "CppPlatform/Extensions/text_black.png");
*
* .AddParameter("object", _("Object"), "Text", false)
* .AddParameter("operator", _("Modification operator"), "string")
* .AddParameter("string", _("String"))
* .SetFunctionName("SetString").SetManipulatedType("string").SetGetter("GetString");
*
* DECLARE_END_OBJECT_ACTION()
* \endcode
*/
ExtraInformation &SetGetter(const gd::String &getter) {
optionalAssociatedInstruction = getter;
accessType = MutatorAndOrAccessor;
return *this;
}
ExtraInformation &SetMutators(
const std::map<gd::String, gd::String> &mutators) {
optionalMutators = mutators;
accessType = Mutators;
return *this;
}
/**
* \brief Erase any existing include file and add the specified include.
*/
ExtraInformation &SetIncludeFile(const gd::String &includeFile) {
includeFiles.clear();
includeFiles.push_back(includeFile);
return *this;
}
/**
* \brief Add a file to the already existing include files.
*/
ExtraInformation &AddIncludeFile(const gd::String &includeFile) {
if (std::find(includeFiles.begin(), includeFiles.end(), includeFile) ==
includeFiles.end())
includeFiles.push_back(includeFile);
return *this;
}
/**
* \brief Get the files that must be included to use the instruction.
*/
const std::vector<gd::String> &GetIncludeFiles() const {
return includeFiles;
};
ExtraInformation &SetCustomCodeGenerator(
std::function<gd::String(Instruction &instruction,
gd::EventsCodeGenerator &codeGenerator,
gd::EventsCodeGenerationContext &context)>
codeGenerator) {
hasCustomCodeGenerator = true;
customCodeGenerator = codeGenerator;
return *this;
}
ExtraInformation &RemoveCustomCodeGenerator() {
hasCustomCodeGenerator = false;
std::function<gd::String(Instruction & instruction,
gd::EventsCodeGenerator & codeGenerator,
gd::EventsCodeGenerationContext & context)>
emptyFunction;
customCodeGenerator = emptyFunction;
return *this;
}
bool HasCustomCodeGenerator() const { return hasCustomCodeGenerator; }
// TODO Move these attributes to InstructionMetadata.
gd::String functionCallName;
gd::String asyncFunctionCallName;
gd::String type;
@@ -512,75 +399,156 @@ class GD_CORE_API InstructionMetadata {
std::map<gd::String, gd::String> optionalMutators;
bool hasCustomCodeGenerator;
std::function<gd::String(Instruction &instruction,
gd::EventsCodeGenerator &codeGenerator,
gd::EventsCodeGenerationContext &context)>
gd::EventsCodeGenerator &codeGenerator,
gd::EventsCodeGenerationContext &context)>
customCodeGenerator;
private:
std::vector<gd::String> includeFiles;
};
ExtraInformation codeExtraInformation; ///< Information about how generate
///< code for the instruction
/**
* \brief Return the structure containing the information about code
* generation for the instruction.
*/
ExtraInformation &GetCodeExtraInformation() { return codeExtraInformation; }
/**
* \brief Declare if the instruction being declared is somewhat manipulating
* in a standard way. \param type "number" or "string" \note Shortcut for
* `codeExtraInformation.SetManipulatedType(type)`.
*/
ExtraInformation &SetManipulatedType(const gd::String &type_) {
return codeExtraInformation.SetManipulatedType(type_);
}
/**
* Set the name of the function which will be called in the generated code.
* \param functionName the name of the function to call.
* \note Shortcut for `codeExtraInformation.SetFunctionName`.
*/
ExtraInformation &SetFunctionName(const gd::String &functionName) {
return codeExtraInformation.SetFunctionName(functionName);
InstructionMetadata &SetFunctionName(const gd::String &functionName_) override {
codeExtraInformation.functionCallName = functionName_;
return *this;
}
/**
* Set the name of the function, doing asynchronous work, which will be called
* in the generated code. This function should return an asynchronous task
* (i.e: `gdjs.AsyncTask` in the JavaScript runtime).
* Set the name of the function, doing asynchronous work, which will be
* called in the generated code. This function should return an asynchronous
* task (i.e: `gdjs.AsyncTask` in the JavaScript runtime).
*
* \param functionName the name of the function doing asynchronous work to
* call. \note Shortcut for `codeExtraInformation.SetAsyncFunctionName`.
* call.
*/
ExtraInformation &SetAsyncFunctionName(const gd::String &functionName) {
return codeExtraInformation.SetAsyncFunctionName(functionName);
InstructionMetadata &SetAsyncFunctionName(const gd::String &functionName_) {
codeExtraInformation.asyncFunctionCallName = functionName_;
return *this;
}
/**
* Return the name of the function which will be called in the generated code.
*/
const gd::String &GetFunctionName() {
return codeExtraInformation.functionCallName;
}
/**
* Return the name of the function, doing asynchronous work, which will be
* called in the generated code. This function should return an asynchronous
* task (i.e: `gdjs.AsyncTask` in the JavaScript runtime).
*/
const gd::String &GetAsyncFunctionName() {
return codeExtraInformation.asyncFunctionCallName;
}
/**
* \brief Declare if the instruction being declared is somewhat manipulating
* in a standard way.
*
* \param type "number" or "string"
*/
InstructionMetadata &SetManipulatedType(const gd::String &type_) {
codeExtraInformation.type = type_;
return *this;
}
/**
* If InstructionMetadata::ExtraInformation::SetManipulatedType was called
* with "number" or "string", this function will tell the code generator the
* name of the getter function used to retrieve the data value.
*
* Usage example:
* \code
* obj.AddAction("String",
* _("Change the string"),
* _("Change the string of a text"),
* _("the string"),
* _("Text"),
* "CppPlatform/Extensions/text24.png",
* "CppPlatform/Extensions/text_black.png");
*
* .AddParameter("object", _("Object"), "Text", false)
* .AddParameter("operator", _("Modification operator"), "string")
* .AddParameter("string", _("String"))
* .SetFunctionName("SetString").SetManipulatedType("string").SetGetter("GetString");
*
* DECLARE_END_OBJECT_ACTION()
* \endcode
*/
InstructionMetadata &SetGetter(const gd::String &getter) {
codeExtraInformation.optionalAssociatedInstruction = getter;
codeExtraInformation.accessType = codeExtraInformation.MutatorAndOrAccessor;
return *this;
}
InstructionMetadata &SetMutators(
const std::map<gd::String, gd::String> &mutators) {
codeExtraInformation.optionalMutators = mutators;
codeExtraInformation.accessType = codeExtraInformation.Mutators;
return *this;
}
/**
* \brief Erase any existing include file and add the specified include.
*/
InstructionMetadata &SetIncludeFile(const gd::String &includeFile) {
codeExtraInformation.SetIncludeFile(includeFile);
InstructionMetadata &SetIncludeFile(const gd::String &includeFile) override {
codeExtraInformation.includeFiles.clear();
codeExtraInformation.includeFiles.push_back(includeFile);
return *this;
}
/**
* \brief Add a file to the already existing include files.
*/
InstructionMetadata &AddIncludeFile(const gd::String &includeFile) {
codeExtraInformation.AddIncludeFile(includeFile);
InstructionMetadata &AddIncludeFile(const gd::String &includeFile) override {
if (std::find(codeExtraInformation.includeFiles.begin(), codeExtraInformation.includeFiles.end(), includeFile) ==
codeExtraInformation.includeFiles.end())
codeExtraInformation.includeFiles.push_back(includeFile);
return *this;
}
/**
* \brief Get the files that must be included to use the instruction.
*/
const std::vector<gd::String> &GetIncludeFiles() const {
return codeExtraInformation.GetIncludeFiles();
const std::vector<gd::String> &GetIncludeFiles() const override {
return codeExtraInformation.includeFiles;
};
InstructionMetadata &SetCustomCodeGenerator(
std::function<gd::String(Instruction &instruction,
gd::EventsCodeGenerator &codeGenerator,
gd::EventsCodeGenerationContext &context)>
codeGenerator) {
codeExtraInformation.hasCustomCodeGenerator = true;
codeExtraInformation.customCodeGenerator = codeGenerator;
return *this;
}
InstructionMetadata &RemoveCustomCodeGenerator() {
codeExtraInformation.hasCustomCodeGenerator = false;
std::function<gd::String(Instruction & instruction,
gd::EventsCodeGenerator & codeGenerator,
gd::EventsCodeGenerationContext & context)>
emptyFunction;
codeExtraInformation.customCodeGenerator = emptyFunction;
return *this;
}
bool HasCustomCodeGenerator() const { return codeExtraInformation.hasCustomCodeGenerator; }
/**
* \brief Return the structure containing the information about code
* generation for the instruction.
*
* \deprecated
*/
InstructionMetadata &GetCodeExtraInformation() { return *this; }
std::vector<ParameterMetadata> parameters;
private:
@@ -604,5 +572,3 @@ class GD_CORE_API InstructionMetadata {
};
} // namespace gd
#endif // INSTRUCTIONMETADATA_H

View File

@@ -0,0 +1,201 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include <map>
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/String.h"
namespace gd {
class Behavior;
class BehaviorsSharedData;
class MultipleInstructionMetadata;
class InstructionMetadata;
class ExpressionMetadata;
} // namespace gd
namespace gd {
/**
* \brief Contains user-friendly information about instructions and expressions
* (usually for a behavior or an object).
*
* \ingroup Events
*/
class GD_CORE_API InstructionOrExpressionContainerMetadata {
public:
InstructionOrExpressionContainerMetadata(){};
virtual ~InstructionOrExpressionContainerMetadata(){};
/**
* Declare a new condition as being part of the behavior or object.
* \deprecated Prefer using `AddScopedCondition`, to properly namespace
* the condition.
*/
virtual gd::InstructionMetadata &
AddCondition(const gd::String &name_, const gd::String &fullname_,
const gd::String &description_, const gd::String &sentence_,
const gd::String &group_, const gd::String &icon_,
const gd::String &smallicon_) = 0;
/**
* Declare a new action as being part of the behavior or object.
* \deprecated Prefer using `AddScopedAction`, to properly namespace
* the action.
*/
virtual gd::InstructionMetadata &
AddAction(const gd::String &name_, const gd::String &fullname_,
const gd::String &description_, const gd::String &sentence_,
const gd::String &group_, const gd::String &icon_,
const gd::String &smallicon_) = 0;
/**
* Declare a new condition as being part of the behavior or object.
*/
virtual gd::InstructionMetadata &
AddScopedCondition(const gd::String &name_, const gd::String &fullname_,
const gd::String &description_,
const gd::String &sentence_, const gd::String &group_,
const gd::String &icon_, const gd::String &smallicon_) = 0;
/**
* Declare a new action as being part of the behavior or object.
*/
virtual gd::InstructionMetadata &
AddScopedAction(const gd::String &name_, const gd::String &fullname_,
const gd::String &description_, const gd::String &sentence_,
const gd::String &group_, const gd::String &icon_,
const gd::String &smallicon_) = 0;
/**
* Declare a new action as being part of the extension.
*/
virtual gd::ExpressionMetadata &
AddExpression(const gd::String &name_, const gd::String &fullname_,
const gd::String &description_, const gd::String &group_,
const gd::String &smallicon_) = 0;
/**
* Declare a new string expression as being part of the extension.
*/
virtual gd::ExpressionMetadata &
AddStrExpression(const gd::String &name_, const gd::String &fullname_,
const gd::String &description_, const gd::String &group_,
const gd::String &smallicon_) = 0;
/**
* \brief Declare a new expression and condition as being part of the
* behavior.
* \note It's recommended to use this function to avoid declaring twice a
* similar expression/condition.
*/
virtual gd::MultipleInstructionMetadata AddExpressionAndCondition(
const gd::String &type, const gd::String &name,
const gd::String &fullname, const gd::String &description,
const gd::String &sentenceName, const gd::String &group,
const gd::String &icon) = 0;
/**
* \brief Declare a new expression, condition and action as being part of the
* behavior.
* \note The action name is prefixed by "Set" (and the namespace, as the
* condition).
* \note It's recommended to use this function to avoid declaring 3 times a
* similar expression/condition/action.
*/
virtual gd::MultipleInstructionMetadata AddExpressionAndConditionAndAction(
const gd::String &type, const gd::String &name,
const gd::String &fullname, const gd::String &description,
const gd::String &sentenceName, const gd::String &group,
const gd::String &icon) = 0;
/**
* \brief Create a new action which is the duplicate of the specified one.
*
* Useful for handling a deprecated action that is just a "copy" of the new
* one.
*/
virtual gd::InstructionMetadata &
AddDuplicatedAction(const gd::String &newActionName,
const gd::String &copiedActionName) = 0;
/**
* \brief Create a new condition which is the duplicate of the specified one.
*
* Useful for handling a deprecated condition that is just a "copy" of the new
* one.
*/
virtual gd::InstructionMetadata &
AddDuplicatedCondition(const gd::String &newConditionName,
const gd::String &copiedConditionName) = 0;
virtual InstructionOrExpressionContainerMetadata &
SetFullName(const gd::String &fullname_) = 0;
virtual InstructionOrExpressionContainerMetadata &
SetDescription(const gd::String &description_) = 0;
/**
* \brief Erase any existing include file and add the specified include.
* \note The requirement may vary depending on the platform: Most of the time,
* the include file contains the declaration of the behavior.
*/
virtual InstructionOrExpressionContainerMetadata &
SetIncludeFile(const gd::String &includeFile) = 0;
/**
* \brief Add a file to the already existing include files.
*/
virtual InstructionOrExpressionContainerMetadata &
AddIncludeFile(const gd::String &includeFile) = 0;
/**
* Get the help path of the behavior, relative to the GDevelop documentation
* root.
*/
virtual const gd::String &GetHelpPath() const = 0;
/**
* Set the help path of the behavior, relative to the GDevelop documentation
* root.
*
* The behavior instructions will have this help path set by
* default, unless you call SetHelpPath on them.
*/
virtual InstructionOrExpressionContainerMetadata &
SetHelpPath(const gd::String &path) = 0;
virtual const gd::String &GetName() const = 0;
virtual const gd::String &GetFullName() const = 0;
virtual const gd::String &GetDescription() const = 0;
virtual const gd::String &GetIconFilename() const = 0;
/**
* \brief Return a reference to a map containing the names of the actions
* (as keys) and the metadata associated with (as values).
*/
virtual std::map<gd::String, gd::InstructionMetadata> &GetAllActions() = 0;
/**
* \see gd::PlatformExtension::GetAllActions
*/
virtual std::map<gd::String, gd::InstructionMetadata> &GetAllConditions() = 0;
/**
* \see gd::PlatformExtension::GetAllActions
*/
virtual std::map<gd::String, gd::ExpressionMetadata> &GetAllExpressions() = 0;
/**
* \see gd::PlatformExtension::GetAllActions
*/
virtual std::map<gd::String, gd::ExpressionMetadata> &
GetAllStrExpressions() = 0;
private:
};
} // namespace gd

View File

@@ -135,11 +135,11 @@ MetadataProvider::GetExtensionAndConditionMetadata(const gd::Platform& platform,
const auto& objects = extension->GetExtensionObjectsTypes();
for (const gd::String& extObjectType : objects) {
const auto& allObjetsConditions =
const auto& allObjectsConditions =
extension->GetAllConditionsForObject(extObjectType);
if (allObjetsConditions.find(conditionType) != allObjetsConditions.end())
if (allObjectsConditions.find(conditionType) != allObjectsConditions.end())
return ExtensionAndMetadata<InstructionMetadata>(
*extension, allObjetsConditions.find(conditionType)->second);
*extension, allObjectsConditions.find(conditionType)->second);
}
const auto& autos = extension->GetBehaviorsTypes();

View File

@@ -1,12 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "MultipleInstructionMetadata.h"
#include "InstructionMetadata.h"
namespace gd {
} // namespace gd

View File

@@ -3,8 +3,8 @@
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef MULTIPLEINSTRUCTIONSMETADATA_H
#define MULTIPLEINSTRUCTIONSMETADATA_H
#pragma once
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/String.h"
@@ -21,7 +21,7 @@ namespace gd {
*
* \ingroup PlatformDefinition
*/
class GD_CORE_API MultipleInstructionMetadata {
class GD_CORE_API MultipleInstructionMetadata : public AbstractFunctionMetadata {
public:
static MultipleInstructionMetadata WithExpressionAndCondition(
gd::ExpressionMetadata &expression, gd::InstructionMetadata &condition) {
@@ -45,7 +45,7 @@ class GD_CORE_API MultipleInstructionMetadata {
const gd::String &type,
const gd::String &label,
const gd::String &supplementaryInformation = "",
bool parameterIsOptional = false) {
bool parameterIsOptional = false) override {
if (expression)
expression->AddParameter(
type, label, supplementaryInformation, parameterIsOptional);
@@ -62,7 +62,7 @@ class GD_CORE_API MultipleInstructionMetadata {
* \see gd::InstructionMetadata::AddCodeOnlyParameter
*/
MultipleInstructionMetadata &AddCodeOnlyParameter(
const gd::String &type, const gd::String &supplementaryInformation) {
const gd::String &type, const gd::String &supplementaryInformation) override {
if (expression)
expression->AddCodeOnlyParameter(type, supplementaryInformation);
if (condition)
@@ -74,7 +74,7 @@ class GD_CORE_API MultipleInstructionMetadata {
/**
* \see gd::InstructionMetadata::SetDefaultValue
*/
MultipleInstructionMetadata &SetDefaultValue(const gd::String &defaultValue) {
MultipleInstructionMetadata &SetDefaultValue(const gd::String &defaultValue) override {
if (expression) expression->SetDefaultValue(defaultValue);
if (condition) condition->SetDefaultValue(defaultValue);
if (action) action->SetDefaultValue(defaultValue);
@@ -85,7 +85,7 @@ class GD_CORE_API MultipleInstructionMetadata {
* \see gd::InstructionMetadata::SetParameterExtraInfo
*/
MultipleInstructionMetadata &SetParameterExtraInfo(
const gd::String &defaultValue) {
const gd::String &defaultValue) override {
if (expression) expression->SetParameterExtraInfo(defaultValue);
if (condition) condition->SetParameterExtraInfo(defaultValue);
if (action) action->SetParameterExtraInfo(defaultValue);
@@ -96,7 +96,7 @@ class GD_CORE_API MultipleInstructionMetadata {
* \see gd::InstructionMetadata::SetParameterLongDescription
*/
MultipleInstructionMetadata &SetParameterLongDescription(
const gd::String &longDescription) {
const gd::String &longDescription) override {
if (expression) expression->SetParameterLongDescription(longDescription);
if (condition) condition->SetParameterLongDescription(longDescription);
if (action) action->SetParameterLongDescription(longDescription);
@@ -106,7 +106,7 @@ class GD_CORE_API MultipleInstructionMetadata {
/**
* \see gd::InstructionMetadata::SetHidden
*/
MultipleInstructionMetadata &SetHidden() {
MultipleInstructionMetadata &SetHidden() override {
if (expression) expression->SetHidden();
if (condition) condition->SetHidden();
if (action) action->SetHidden();
@@ -136,47 +136,47 @@ class GD_CORE_API MultipleInstructionMetadata {
return *this;
}
MultipleInstructionMetadata &SetFunctionName(const gd::String &functionName) {
MultipleInstructionMetadata &SetFunctionName(const gd::String &functionName) override {
if (expression) expression->SetFunctionName(functionName);
if (condition) condition->SetFunctionName(functionName);
if (action) action->GetCodeExtraInformation().SetFunctionName(functionName);
if (action) action->SetFunctionName(functionName);
return *this;
}
MultipleInstructionMetadata &SetGetter(const gd::String &getter) {
if (expression) expression->SetFunctionName(getter);
if (condition) condition->SetFunctionName(getter);
if (action) action->GetCodeExtraInformation().SetGetter(getter);
if (action) action->SetGetter(getter);
return *this;
}
MultipleInstructionMetadata &SetIncludeFile(const gd::String &includeFile) {
MultipleInstructionMetadata &SetIncludeFile(const gd::String &includeFile) override {
if (expression)
expression->GetCodeExtraInformation().SetIncludeFile(includeFile);
expression->SetIncludeFile(includeFile);
if (condition)
condition->GetCodeExtraInformation().SetIncludeFile(includeFile);
if (action) action->GetCodeExtraInformation().SetIncludeFile(includeFile);
condition->SetIncludeFile(includeFile);
if (action) action->SetIncludeFile(includeFile);
return *this;
}
MultipleInstructionMetadata &AddIncludeFile(const gd::String &includeFile) {
MultipleInstructionMetadata &AddIncludeFile(const gd::String &includeFile) override {
if (expression)
expression->GetCodeExtraInformation().AddIncludeFile(includeFile);
if (condition)
condition->GetCodeExtraInformation().AddIncludeFile(includeFile);
if (action) action->GetCodeExtraInformation().AddIncludeFile(includeFile);
condition->AddIncludeFile(includeFile);
if (action) action->AddIncludeFile(includeFile);
return *this;
}
/**
* \brief Get the files that must be included to use the instruction.
*/
const std::vector<gd::String> &GetIncludeFiles() const {
const std::vector<gd::String> &GetIncludeFiles() const override {
if (expression)
return expression->GetCodeExtraInformation().GetIncludeFiles();
if (condition)
return condition->GetCodeExtraInformation().GetIncludeFiles();
if (action) return action->GetCodeExtraInformation().GetIncludeFiles();
return condition->GetIncludeFiles();
if (action) return action->GetIncludeFiles();
// It can't actually happen.
throw std::logic_error("no instruction metadata");
}
@@ -184,7 +184,7 @@ class GD_CORE_API MultipleInstructionMetadata {
/**
* \see gd::InstructionMetadata::SetPrivate
*/
MultipleInstructionMetadata &SetPrivate() {
MultipleInstructionMetadata &SetPrivate() override {
if (expression) expression->SetPrivate();
if (condition) condition->SetPrivate();
if (action) action->SetPrivate();
@@ -218,6 +218,42 @@ class GD_CORE_API MultipleInstructionMetadata {
return *this;
}
/**
* Set that the instruction can be used in layouts or external events.
*/
MultipleInstructionMetadata &SetRelevantForLayoutEventsOnly() override {
if (condition) condition->SetRelevantForLayoutEventsOnly();
if (action) action->SetRelevantForLayoutEventsOnly();
return *this;
}
/**
* Set that the instruction can be used in function events.
*/
MultipleInstructionMetadata &SetRelevantForFunctionEventsOnly() override {
if (condition) condition->SetRelevantForFunctionEventsOnly();
if (action) action->SetRelevantForFunctionEventsOnly();
return *this;
}
/**
* Set that the instruction can be used in asynchronous function events.
*/
MultipleInstructionMetadata &SetRelevantForAsynchronousFunctionEventsOnly() override {
if (condition) condition->SetRelevantForAsynchronousFunctionEventsOnly();
if (action) action->SetRelevantForAsynchronousFunctionEventsOnly();
return *this;
}
/**
* Set that the instruction can be used in custom object events.
*/
MultipleInstructionMetadata &SetRelevantForCustomObjectEventsOnly() override {
if (condition) condition->SetRelevantForCustomObjectEventsOnly();
if (action) action->SetRelevantForCustomObjectEventsOnly();
return *this;
}
/**
* \brief Don't use, only here to fulfill Emscripten bindings requirements.
*/
@@ -242,5 +278,3 @@ class GD_CORE_API MultipleInstructionMetadata {
};
} // namespace gd
#endif // MULTIPLEINSTRUCTIONSMETADATA_H

View File

@@ -3,8 +3,10 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef OBJECTMETADATA_H
#define OBJECTMETADATA_H
#pragma once
#include "InstructionOrExpressionContainerMetadata.h"
#include <functional>
#include <map>
#include <set>
@@ -32,7 +34,7 @@ namespace gd {
*
* \ingroup Events
*/
class GD_CORE_API ObjectMetadata {
class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetadata {
public:
/**
* \brief Construct an object metadata, using a "blueprint" object that will
@@ -79,7 +81,7 @@ class GD_CORE_API ObjectMetadata {
const gd::String& sentence_,
const gd::String& group_,
const gd::String& icon_,
const gd::String& smallicon_);
const gd::String& smallicon_) override;
/**
* \brief Declare a new action as being part of the extension.
@@ -92,7 +94,7 @@ class GD_CORE_API ObjectMetadata {
const gd::String& sentence_,
const gd::String& group_,
const gd::String& icon_,
const gd::String& smallicon_);
const gd::String& smallicon_) override;
/**
* Declare a new condition as being part of the object.
@@ -103,7 +105,7 @@ class GD_CORE_API ObjectMetadata {
const gd::String& sentence_,
const gd::String& group_,
const gd::String& icon_,
const gd::String& smallicon_);
const gd::String& smallicon_) override;
/**
* Declare a new action as being part of the object.
@@ -114,7 +116,7 @@ class GD_CORE_API ObjectMetadata {
const gd::String& sentence_,
const gd::String& group_,
const gd::String& icon_,
const gd::String& smallicon_);
const gd::String& smallicon_) override;
/**
* \brief Declare a new expression as being part of the extension.
@@ -123,7 +125,7 @@ class GD_CORE_API ObjectMetadata {
const gd::String& fullname_,
const gd::String& description_,
const gd::String& group_,
const gd::String& smallicon_);
const gd::String& smallicon_) override;
/**
* \brief Declare a new string expression as being part of the extension.
*/
@@ -131,7 +133,7 @@ class GD_CORE_API ObjectMetadata {
const gd::String& fullname_,
const gd::String& description_,
const gd::String& group_,
const gd::String& smallicon_);
const gd::String& smallicon_) override;
/**
* \brief Declare a new expression and condition as being part of the
@@ -146,7 +148,7 @@ class GD_CORE_API ObjectMetadata {
const gd::String& description,
const gd::String& sentenceName,
const gd::String& group,
const gd::String& icon);
const gd::String& icon) override;
/**
* \brief Declare a new expression, condition and action as being part of the
@@ -163,7 +165,7 @@ class GD_CORE_API ObjectMetadata {
const gd::String& description,
const gd::String& sentenceName,
const gd::String& group,
const gd::String& icon);
const gd::String& icon) override;
/**
* \brief Create a new action which is the duplicate of the specified one.
@@ -172,7 +174,7 @@ class GD_CORE_API ObjectMetadata {
* one.
*/
gd::InstructionMetadata& AddDuplicatedAction(
const gd::String& newActionName, const gd::String& copiedActionName);
const gd::String& newActionName, const gd::String& copiedActionName) override;
/**
* \brief Create a new condition which is the duplicate of the specified one.
@@ -182,23 +184,23 @@ class GD_CORE_API ObjectMetadata {
*/
gd::InstructionMetadata& AddDuplicatedCondition(
const gd::String& newConditionName,
const gd::String& copiedConditionName);
const gd::String& copiedConditionName) override;
/**
* \brief Set the name shown to the user.
*/
ObjectMetadata& SetFullName(const gd::String& fullname_);
ObjectMetadata& SetFullName(const gd::String& fullname_) override;
/**
* \brief Set the description shown to the user.
*/
ObjectMetadata& SetDescription(const gd::String& description_);
ObjectMetadata& SetDescription(const gd::String& description_) override;
/**
* \brief Get the help path of the object, relative to the GDevelop
* documentation root.
*/
const gd::String& GetHelpPath() const { return helpPath; }
const gd::String& GetHelpPath() const override { return helpPath; }
/**
* \brief Set the help path of the object, relative to the GDevelop
@@ -207,7 +209,7 @@ class GD_CORE_API ObjectMetadata {
* The object instructions will have this help path set by
* default, unless you call SetHelpPath on them.
*/
ObjectMetadata& SetHelpPath(const gd::String& path) {
ObjectMetadata& SetHelpPath(const gd::String& path) override {
helpPath = path;
return *this;
}
@@ -248,12 +250,12 @@ class GD_CORE_API ObjectMetadata {
return unsupportedBaseObjectCapabilities.find(capability) != unsupportedBaseObjectCapabilities.end();
}
const gd::String& GetName() const { return name; }
const gd::String& GetFullName() const { return fullname; }
const gd::String& GetName() const override { return name; }
const gd::String& GetFullName() const override { return fullname; }
const gd::String& GetCategoryFullName() const { return categoryFullName; }
const gd::String& GetHelpUrl() const { return helpUrl; }
const gd::String& GetDescription() const { return description; }
const gd::String& GetIconFilename() const { return iconFilename; }
const gd::String& GetDescription() const override { return description; }
const gd::String& GetIconFilename() const override { return iconFilename; }
/**
* \brief Set the URL pointing to the help page about this object
@@ -267,33 +269,33 @@ class GD_CORE_API ObjectMetadata {
* \note The requirement may vary depending on the platform: Most of the time,
* the include file contains the declaration of the object.
*/
ObjectMetadata& SetIncludeFile(const gd::String& includeFile);
ObjectMetadata& SetIncludeFile(const gd::String& includeFile) override;
/**
* \brief Add a file to the already existing include files.
*/
ObjectMetadata& AddIncludeFile(const gd::String& includeFile);
ObjectMetadata& AddIncludeFile(const gd::String& includeFile) override;
/**
* \brief Return a reference to a map containing the names of the actions
* (as keys) and the metadata associated with (as values).
*/
std::map<gd::String, gd::InstructionMetadata>& GetAllActions() { return actionsInfos; };
std::map<gd::String, gd::InstructionMetadata>& GetAllActions() override { return actionsInfos; };
/**
* \see gd::PlatformExtension::GetAllActions
*/
std::map<gd::String, gd::InstructionMetadata>& GetAllConditions() { return conditionsInfos; };
std::map<gd::String, gd::InstructionMetadata>& GetAllConditions() override { return conditionsInfos; };
/**
* \see gd::PlatformExtension::GetAllActions
*/
std::map<gd::String, gd::ExpressionMetadata>& GetAllExpressions() { return expressionsInfos; };
std::map<gd::String, gd::ExpressionMetadata>& GetAllExpressions() override { return expressionsInfos; };
/**
* \see gd::PlatformExtension::GetAllActions
*/
std::map<gd::String, gd::ExpressionMetadata>& GetAllStrExpressions() { return strExpressionsInfos; };
std::map<gd::String, gd::ExpressionMetadata>& GetAllStrExpressions() override { return strExpressionsInfos; };
/**
* \brief Set the object to be hidden in the IDE.
@@ -341,4 +343,3 @@ class GD_CORE_API ObjectMetadata {
};
} // namespace gd
#endif // OBJECTMETADATA_H

View File

@@ -653,7 +653,7 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
GetAllActions().begin();
it != GetAllActions().end();) {
if (it->second.codeExtraInformation.functionCallName.empty() &&
!it->second.codeExtraInformation.HasCustomCodeGenerator()) {
!it->second.HasCustomCodeGenerator()) {
GetAllActions().erase(it++);
} else
++it;
@@ -663,7 +663,7 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
GetAllConditions().begin();
it != GetAllConditions().end();) {
if (it->second.codeExtraInformation.functionCallName.empty() &&
!it->second.codeExtraInformation.HasCustomCodeGenerator()) {
!it->second.HasCustomCodeGenerator()) {
GetAllConditions().erase(it++);
} else
++it;
@@ -673,7 +673,7 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
GetAllExpressions().begin();
it != GetAllExpressions().end();) {
if (it->second.codeExtraInformation.functionCallName.empty() &&
!it->second.codeExtraInformation.HasCustomCodeGenerator()) {
!it->second.HasCustomCodeGenerator()) {
GetAllExpressions().erase(it++);
} else
++it;
@@ -683,7 +683,7 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
GetAllStrExpressions().begin();
it != GetAllStrExpressions().end();) {
if (it->second.codeExtraInformation.functionCallName.empty() &&
!it->second.codeExtraInformation.HasCustomCodeGenerator()) {
!it->second.HasCustomCodeGenerator()) {
GetAllStrExpressions().erase(it++);
} else
++it;
@@ -699,7 +699,7 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
obj.actionsInfos.begin();
it != obj.actionsInfos.end();) {
if (it->second.codeExtraInformation.functionCallName.empty() &&
!it->second.codeExtraInformation.HasCustomCodeGenerator()) {
!it->second.HasCustomCodeGenerator()) {
obj.actionsInfos.erase(it++);
} else
++it;
@@ -709,7 +709,7 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
obj.conditionsInfos.begin();
it != obj.conditionsInfos.end();) {
if (it->second.codeExtraInformation.functionCallName.empty() &&
!it->second.codeExtraInformation.HasCustomCodeGenerator()) {
!it->second.HasCustomCodeGenerator()) {
obj.conditionsInfos.erase(it++);
} else
++it;
@@ -719,7 +719,7 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
obj.expressionsInfos.begin();
it != obj.expressionsInfos.end();) {
if (it->second.codeExtraInformation.functionCallName.empty() &&
!it->second.codeExtraInformation.HasCustomCodeGenerator()) {
!it->second.HasCustomCodeGenerator()) {
obj.expressionsInfos.erase(it++);
} else
++it;
@@ -729,7 +729,7 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
obj.strExpressionsInfos.begin();
it != obj.strExpressionsInfos.end();) {
if (it->second.codeExtraInformation.functionCallName.empty() &&
!it->second.codeExtraInformation.HasCustomCodeGenerator()) {
!it->second.HasCustomCodeGenerator()) {
obj.strExpressionsInfos.erase(it++);
} else
++it;
@@ -746,7 +746,7 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
obj.actionsInfos.begin();
it != obj.actionsInfos.end();) {
if (it->second.codeExtraInformation.functionCallName.empty() &&
!it->second.codeExtraInformation.HasCustomCodeGenerator()) {
!it->second.HasCustomCodeGenerator()) {
obj.actionsInfos.erase(it++);
} else
++it;
@@ -756,7 +756,7 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
obj.conditionsInfos.begin();
it != obj.conditionsInfos.end();) {
if (it->second.codeExtraInformation.functionCallName.empty() &&
!it->second.codeExtraInformation.HasCustomCodeGenerator()) {
!it->second.HasCustomCodeGenerator()) {
obj.conditionsInfos.erase(it++);
} else
++it;
@@ -766,7 +766,7 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
obj.expressionsInfos.begin();
it != obj.expressionsInfos.end();) {
if (it->second.codeExtraInformation.functionCallName.empty() &&
!it->second.codeExtraInformation.HasCustomCodeGenerator()) {
!it->second.HasCustomCodeGenerator()) {
obj.expressionsInfos.erase(it++);
} else
++it;
@@ -776,7 +776,7 @@ void PlatformExtension::StripUnimplementedInstructionsAndExpressions() {
obj.strExpressionsInfos.begin();
it != obj.strExpressionsInfos.end();) {
if (it->second.codeExtraInformation.functionCallName.empty() &&
!it->second.codeExtraInformation.HasCustomCodeGenerator()) {
!it->second.HasCustomCodeGenerator()) {
obj.strExpressionsInfos.erase(it++);
} else
++it;

View File

@@ -642,7 +642,7 @@ std::vector<EventsSearchResult> EventsRefactorer::ReplaceStringInEvents(
return modifiedEvents;
}
gd::String ReplaceAllOccurencesCaseUnsensitive(gd::String context,
gd::String ReplaceAllOccurrencesCaseInsensitive(gd::String context,
gd::String from,
const gd::String& to) {
size_t lookHere = 0;
@@ -673,7 +673,7 @@ bool EventsRefactorer::ReplaceStringInActions(gd::ObjectsContainer& project,
matchCase
? actions[aId].GetParameter(pNb).GetPlainString().FindAndReplace(
toReplace, newString, true)
: ReplaceAllOccurencesCaseUnsensitive(
: ReplaceAllOccurrencesCaseInsensitive(
actions[aId].GetParameter(pNb).GetPlainString(),
toReplace,
newString);
@@ -713,7 +713,7 @@ bool EventsRefactorer::ReplaceStringInConditions(
.GetParameter(pNb)
.GetPlainString()
.FindAndReplace(toReplace, newString, true)
: ReplaceAllOccurencesCaseUnsensitive(
: ReplaceAllOccurrencesCaseInsensitive(
conditions[cId].GetParameter(pNb).GetPlainString(),
toReplace,
newString);
@@ -749,7 +749,7 @@ bool EventsRefactorer::ReplaceStringInEventSearchableStrings(
for (std::size_t sNb = 0; sNb < stringEvent.size(); ++sNb) {
gd::String newStringEvent =
matchCase ? stringEvent[sNb].FindAndReplace(toReplace, newString, true)
: ReplaceAllOccurencesCaseUnsensitive(
: ReplaceAllOccurrencesCaseInsensitive(
stringEvent[sNb], toReplace, newString);
newEventStrings.push_back(newStringEvent);
}

View File

@@ -153,6 +153,8 @@ void CustomObjectConfiguration::ExposeResources(gd::ArbitraryResourceWorker& wor
worker.ExposeTileset(newPropertyValue);
} else if (resourceType == "bitmapFont") {
worker.ExposeBitmapFont(newPropertyValue);
} else if (resourceType == "model3D") {
worker.ExposeModel3D(newPropertyValue);
}
if (newPropertyValue != oldPropertyValue) {

View File

@@ -77,7 +77,7 @@ class GD_CORE_API EventsBasedBehavior: public AbstractEventsBasedEntity {
* \brief Check if the behavior is private - it can't be used outside of its
* extension.
*/
bool IsPrivate() { return isPrivate; }
bool IsPrivate() const { return isPrivate; }
/**
* \brief Set that the behavior is private - it can't be used outside of its

View File

@@ -201,7 +201,7 @@ class GD_CORE_API EventsFunction {
/**
* \brief Returns true if the function is private.
*/
bool IsPrivate() { return isPrivate; }
bool IsPrivate() const { return isPrivate; }
/**
* \brief Sets the privateness of the function.

View File

@@ -207,6 +207,13 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
return dependencies;
};
/**
* \brief Returns the list of dependencies.
*/
const std::vector<gd::DependencyMetadata>& GetAllDependencies() const {
return dependencies;
};
///@}
/** \name Serialization

View File

@@ -9,9 +9,9 @@
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Tools/UUID/UUID.h"
#include "GDCore/Project/PropertyDescriptor.h"
namespace gd {
@@ -21,12 +21,17 @@ InitialInstance::InitialInstance()
: objectName(""),
x(0),
y(0),
z(0),
angle(0),
rotationX(0),
rotationY(0),
zOrder(0),
layer(""),
personalizedSize(false),
customSize(false),
customDepth(false),
width(0),
height(0),
depth(0),
locked(false),
sealed(false),
persistentUuid(UUID::MakeUuid4()) {}
@@ -35,11 +40,20 @@ void InitialInstance::UnserializeFrom(const SerializerElement& element) {
SetObjectName(element.GetStringAttribute("name", "", "nom"));
SetX(element.GetDoubleAttribute("x"));
SetY(element.GetDoubleAttribute("y"));
SetZ(element.GetDoubleAttribute("z", 0));
SetAngle(element.GetDoubleAttribute("angle"));
SetRotationX(element.GetDoubleAttribute("rotationX", 0));
SetRotationY(element.GetDoubleAttribute("rotationY", 0));
SetHasCustomSize(
element.GetBoolAttribute("customSize", false, "personalizedSize"));
SetCustomWidth(element.GetDoubleAttribute("width"));
SetCustomHeight(element.GetDoubleAttribute("height"));
if (element.HasChild("depth") || element.HasAttribute("depth")) {
SetHasCustomDepth(true);
SetCustomDepth(element.GetDoubleAttribute("depth"));
} else {
SetHasCustomDepth(false);
}
SetZOrder(element.GetIntAttribute("zOrder", 0, "plan"));
SetLayer(element.GetStringAttribute("layer"));
SetLocked(element.GetBoolAttribute("locked", false));
@@ -53,9 +67,26 @@ void InitialInstance::UnserializeFrom(const SerializerElement& element) {
element.GetChild("numberProperties", 0, "floatInfos");
numberPropertiesElement.ConsiderAsArrayOf("property", "Info");
for (std::size_t j = 0; j < numberPropertiesElement.GetChildrenCount(); ++j) {
gd::String name = numberPropertiesElement.GetChild(j).GetStringAttribute("name");
double value = numberPropertiesElement.GetChild(j).GetDoubleAttribute("value");
numberProperties[name] = value;
gd::String name =
numberPropertiesElement.GetChild(j).GetStringAttribute("name");
double value =
numberPropertiesElement.GetChild(j).GetDoubleAttribute("value");
// Compatibility with GD <= 5.1.164
if (name == "z") {
SetZ(value);
} else if (name == "rotationX") {
SetRotationX(value);
} else if (name == "rotationY") {
SetRotationY(value);
} else if (name == "depth") {
SetHasCustomDepth(true);
SetCustomDepth(value);
}
// end of compatibility code
else {
numberProperties[name] = value;
}
}
stringProperties.clear();
@@ -77,21 +108,26 @@ void InitialInstance::SerializeTo(SerializerElement& element) const {
element.SetAttribute("name", GetObjectName());
element.SetAttribute("x", GetX());
element.SetAttribute("y", GetY());
if (GetZ() != 0) element.SetAttribute("z", GetZ());
element.SetAttribute("zOrder", GetZOrder());
element.SetAttribute("layer", GetLayer());
element.SetAttribute("angle", GetAngle());
if (GetRotationX() != 0) element.SetAttribute("rotationX", GetRotationX());
if (GetRotationY() != 0) element.SetAttribute("rotationY", GetRotationY());
element.SetAttribute("customSize", HasCustomSize());
element.SetAttribute("width", GetCustomWidth());
element.SetAttribute("height", GetCustomHeight());
if (HasCustomDepth()) element.SetAttribute("depth", GetCustomDepth());
if (IsLocked()) element.SetAttribute("locked", IsLocked());
if (IsSealed()) element.SetAttribute("sealed", IsSealed());
if (persistentUuid.empty()) persistentUuid = UUID::MakeUuid4();
element.SetStringAttribute("persistentUuid", persistentUuid);
SerializerElement& numberPropertiesElement = element.AddChild("numberProperties");
SerializerElement& numberPropertiesElement =
element.AddChild("numberProperties");
numberPropertiesElement.ConsiderAsArrayOf("property");
for (const auto& property: numberProperties) {
for (const auto& property : numberProperties) {
numberPropertiesElement.AddChild("property")
.SetAttribute("name", property.first)
.SetAttribute("value", property.second);
@@ -99,7 +135,7 @@ void InitialInstance::SerializeTo(SerializerElement& element) const {
SerializerElement& stringPropElement = element.AddChild("stringProperties");
stringPropElement.ConsiderAsArrayOf("property");
for (const auto& property: stringProperties) {
for (const auto& property : stringProperties) {
stringPropElement.AddChild("property")
.SetAttribute("name", property.first)
.SetAttribute("value", property.second);
@@ -117,10 +153,12 @@ std::map<gd::String, gd::PropertyDescriptor>
InitialInstance::GetCustomProperties(gd::Project& project, gd::Layout& layout) {
// Find an object
if (layout.HasObjectNamed(GetObjectName()))
return layout.GetObject(GetObjectName()).GetConfiguration()
return layout.GetObject(GetObjectName())
.GetConfiguration()
.GetInitialInstanceProperties(*this, project, layout);
else if (project.HasObjectNamed(GetObjectName()))
return project.GetObject(GetObjectName()).GetConfiguration()
return project.GetObject(GetObjectName())
.GetConfiguration()
.GetInitialInstanceProperties(*this, project, layout);
std::map<gd::String, gd::PropertyDescriptor> nothing;
@@ -132,10 +170,12 @@ bool InitialInstance::UpdateCustomProperty(const gd::String& name,
gd::Project& project,
gd::Layout& layout) {
if (layout.HasObjectNamed(GetObjectName()))
return layout.GetObject(GetObjectName()).GetConfiguration()
return layout.GetObject(GetObjectName())
.GetConfiguration()
.UpdateInitialInstanceProperty(*this, name, value, project, layout);
else if (project.HasObjectNamed(GetObjectName()))
return project.GetObject(GetObjectName()).GetConfiguration()
return project.GetObject(GetObjectName())
.GetConfiguration()
.UpdateInitialInstanceProperty(*this, name, value, project, layout);
return false;
@@ -154,7 +194,8 @@ const gd::String& InitialInstance::GetRawStringProperty(
return it != stringProperties.end() ? it->second : *badStringProperyValue;
}
void InitialInstance::SetRawDoubleProperty(const gd::String& name, double value) {
void InitialInstance::SetRawDoubleProperty(const gd::String& name,
double value) {
numberProperties[name] = value;
}

View File

@@ -73,22 +73,52 @@ class GD_CORE_API InitialInstance {
void SetY(double y_) { y = y_; }
/**
* \brief Get the rotation of the instance, in radians.
* \brief Get the Z position of the instance
*/
double GetZ() const { return z; }
/**
* \brief Set the Z position of the instance
*/
void SetZ(double z_) { z = z_; }
/**
* \brief Get the rotation of the instance on Z axis, in radians.
*/
double GetAngle() const { return angle; }
/**
* \brief Set the rotation of the instance, in radians.
* \brief Set the rotation of the instance on Z axis, in radians.
*/
void SetAngle(double angle_) { angle = angle_; }
/**
* \brief Get the Z order of the instance.
* \brief Get the rotation of the instance on X axis, in radians.
*/
double GetRotationX() const { return rotationX; }
/**
* \brief Set the rotation of the instance on X axis, in radians.
*/
void SetRotationX(double rotationX_) { rotationX = rotationX_; }
/**
* \brief Get the rotation of the instance on Y axis, in radians.
*/
double GetRotationY() const { return rotationY; }
/**
* \brief Set the rotation of the instance on Y axis, in radians.
*/
void SetRotationY(double rotationY_) { rotationY = rotationY_; }
/**
* \brief Get the Z order of the instance (for a 2D object).
*/
int GetZOrder() const { return zOrder; }
/**
* \brief Set the Z order of the instance.
* \brief Set the Z order of the instance (for a 2D object).
*/
void SetZOrder(int zOrder_) { zOrder = zOrder_; }
@@ -103,29 +133,51 @@ class GD_CORE_API InitialInstance {
void SetLayer(const gd::String& layer_) { layer = layer_; }
/**
* \brief Return true if the instance has a size which is different from its
* object default size.
* \brief Return true if the instance has a width/height which is different from its
* object default width/height. This is independent from `HasCustomDepth`.
*
* \see gd::Object
*/
bool HasCustomSize() const { return personalizedSize; }
bool HasCustomSize() const { return customSize; }
/**
* \brief Set whether the instance has a size which is different from its
* object default size or not.
* \brief Return true if the instance has a depth which is different from its
* object default depth. This is independent from `HasCustomSize`.
*
* \param hasCustomSize true if the size is different from the object's
* default size. \see gd::Object
* \see gd::Object
*/
bool HasCustomDepth() const { return customDepth; }
/**
* \brief Set whether the instance has a width/height which is different from its
* object default width/height or not.
* This is independent from `SetHasCustomDepth`.
*
* \see gd::Object
*/
void SetHasCustomSize(bool hasCustomSize_) {
personalizedSize = hasCustomSize_;
customSize = hasCustomSize_;
}
/**
* \brief Set whether the instance has a depth which is different from its
* object default depth or not.
* This is independent from `SetHasCustomSize`.
*
* \param hasCustomSize true if the depth is different from the object's
* default depth.
* \see gd::Object
*/
void SetHasCustomDepth(bool hasCustomDepth_) {
customDepth = hasCustomDepth_;
}
double GetCustomWidth() const { return width; }
void SetCustomWidth(double width_) { width = width_; }
double GetCustomHeight() const { return height; }
void SetCustomHeight(double height_) { height = height_; }
double GetCustomDepth() const { return depth; }
void SetCustomDepth(double depth_) { depth = depth_; }
/**
* \brief Return true if the instance is locked and cannot be moved in the
@@ -272,14 +324,19 @@ class GD_CORE_API InitialInstance {
stringProperties; ///< More data which can be used by the object
gd::String objectName; ///< Object name
double x; ///< Object initial X position
double y; ///< Object initial Y position
double angle; ///< Object initial angle
int zOrder; ///< Object initial Z order
gd::String layer; ///< Object initial layer
bool personalizedSize; ///< True if object has a custom size
double width; ///< Object custom width
double height; ///< Object custom height
double x; ///< Instance X position
double y; ///< Instance Y position
double z; ///< Instance Z position (for a 3D object)
double angle; ///< Instance angle on Z axis
double rotationX; ///< Instance angle on X axis (for a 3D object)
double rotationY; ///< Instance angle on Y axis (for a 3D object)
int zOrder; ///< Instance Z order (for a 2D object)
gd::String layer; ///< Instance layer
bool customSize; ///< True if object has a custom width and height
bool customDepth; ///< True if object has a custom depth
double width; ///< Instance custom width
double height; ///< Instance custom height
double depth; ///< Instance custom depth
gd::VariablesContainer initialVariables; ///< Instance specific variables
bool locked; ///< True if the instance is locked
bool sealed; ///< True if the instance is sealed

View File

@@ -68,14 +68,14 @@ gd::InitialInstance& InitialInstancesContainer::InsertNewInitialInstance() {
}
void InitialInstancesContainer::RemoveInstanceIf(
std::function<bool(const gd::InitialInstance&)> predicat) {
std::function<bool(const gd::InitialInstance&)> predicate) {
// Note that we can't use eraseremove idiom here because remove_if would
// move the instances, and the container must guarantee that
// iterators/pointers to instances always remain valid.
for (std::list<gd::InitialInstance>::iterator it = initialInstances.begin(),
end = initialInstances.end();
it != end;) {
if (predicat(*it))
if (predicate(*it))
it = initialInstances.erase(it);
else
++it;

View File

@@ -178,7 +178,7 @@ class GD_CORE_API InitialInstancesContainer {
private:
void RemoveInstanceIf(
std::function<bool(const gd::InitialInstance &)> predicat);
std::function<bool(const gd::InitialInstance &)> predicate);
std::list<gd::InitialInstance> initialInstances;

View File

@@ -127,6 +127,10 @@ class GD_CORE_API Object {
/** \brief Return the tags of the object.
*/
const gd::String& GetTags() const { return tags; }
/** \brief Shortcut to check if the object is a 3D object.
*/
bool Is3DObject() const { return configuration->Is3DObject(); }
///@}
/** \name Behaviors management

View File

@@ -20,7 +20,7 @@ namespace gd {
ObjectConfiguration::~ObjectConfiguration() {}
ObjectConfiguration::ObjectConfiguration() {}
ObjectConfiguration::ObjectConfiguration(): is3DObject(false) {}
std::map<gd::String, gd::PropertyDescriptor> ObjectConfiguration::GetProperties() const {
std::map<gd::String, gd::PropertyDescriptor> nothing;

View File

@@ -61,12 +61,22 @@ class GD_CORE_API ObjectConfiguration {
/** \brief Change the type of the object.
*/
void SetType(const gd::String& type_) { type = type_; }
void SetType(const gd::String& type_) {
type = type_;
// For now, as a shortcut, consider only the objects from the built-in 3D extension
// to be 3D object.
is3DObject = type.find("Scene3D::") == 0;
}
/** \brief Return the type of the object.
*/
const gd::String& GetType() const { return type; }
/** \brief Shortcut to check if the object is a 3D object.
*/
bool Is3DObject() const { return is3DObject; }
/** \name Object properties
* Reading and updating object configuration properties
*/
@@ -170,6 +180,7 @@ class GD_CORE_API ObjectConfiguration {
protected:
gd::String type; ///< Which type of object is represented by this
///< configuration.
bool is3DObject;
/**
* \brief Derived object configuration can redefine this method to load

View File

@@ -65,6 +65,8 @@ Project::Project()
pixelsRounding(false),
adaptGameResolutionAtRuntime(true),
sizeOnStartupMode("adaptWidth"),
antialiasingMode("MSAA"),
isAntialisingEnabledOnMobile(false),
projectUuid(""),
useDeprecatedZeroAsDefaultZOrder(false),
useExternalSourceFiles(false),
@@ -628,6 +630,8 @@ void Project::UnserializeFrom(const SerializerElement& element) {
SetAdaptGameResolutionAtRuntime(
propElement.GetBoolAttribute("adaptGameResolutionAtRuntime", false));
SetSizeOnStartupMode(propElement.GetStringAttribute("sizeOnStartupMode", ""));
SetAntialiasingMode(propElement.GetStringAttribute("antialiasingMode", "MSAA"));
SetAntialisingEnabledOnMobile(propElement.GetBoolAttribute("antialisingEnabledOnMobile", false));
SetProjectUuid(propElement.GetStringAttribute("projectUuid", ""));
SetAuthor(propElement.GetChild("author", 0, "Auteur").GetValue().GetString());
SetPackageName(propElement.GetStringAttribute("packageName"));
@@ -882,6 +886,8 @@ void Project::SerializeTo(SerializerElement& element) const {
propElement.SetAttribute("adaptGameResolutionAtRuntime",
adaptGameResolutionAtRuntime);
propElement.SetAttribute("sizeOnStartupMode", sizeOnStartupMode);
propElement.SetAttribute("antialiasingMode", antialiasingMode);
propElement.SetAttribute("antialisingEnabledOnMobile", isAntialisingEnabledOnMobile);
propElement.SetAttribute("projectUuid", projectUuid);
propElement.SetAttribute("folderProject", folderProject);
propElement.SetAttribute("packageName", packageName);
@@ -1113,6 +1119,8 @@ void Project::Init(const gd::Project& game) {
pixelsRounding = game.pixelsRounding;
adaptGameResolutionAtRuntime = game.adaptGameResolutionAtRuntime;
sizeOnStartupMode = game.sizeOnStartupMode;
antialiasingMode = game.antialiasingMode;
isAntialisingEnabledOnMobile = game.isAntialisingEnabledOnMobile;
projectUuid = game.projectUuid;
useDeprecatedZeroAsDefaultZOrder = game.useDeprecatedZeroAsDefaultZOrder;

View File

@@ -383,6 +383,26 @@ class GD_CORE_API Project : public ObjectsContainer {
*/
void SetPixelsRounding(bool enable) { pixelsRounding = enable; }
/**
* Return the antialiasing mode used by the game ("none" or "MSAA").
*/
const gd::String& GetAntialiasingMode() const { return antialiasingMode; }
/**
* Set the antialiasing mode used by the game ("none" or "MSAA").
*/
void SetAntialiasingMode(const gd::String& antialiasingMode_) { antialiasingMode = antialiasingMode_; }
/**
* Return true if antialising is enabled on mobiles.
*/
bool IsAntialisingEnabledOnMobile() const { return isAntialisingEnabledOnMobile; }
/**
* Set whether antialising is enabled on mobiles or not.
*/
void SetAntialisingEnabledOnMobile(bool enable) { isAntialisingEnabledOnMobile = enable; }
/**
* \brief Return if the project should set 0 as Z-order for objects created
* from events (which is deprecated) - instead of the highest Z order that was
@@ -1040,6 +1060,8 @@ class GD_CORE_API Project : public ObjectsContainer {
gd::String
sizeOnStartupMode; ///< How to adapt the game size to the screen. Can be
///< "adaptWidth", "adaptHeight" or empty
gd::String antialiasingMode;
bool isAntialisingEnabledOnMobile;
gd::String projectUuid; ///< UUID useful to identify the game in online
///< services or database that would require it.
bool useDeprecatedZeroAsDefaultZOrder; ///< If true, objects created from

View File

@@ -686,6 +686,16 @@ String GD_CORE_API operator+(const char *lhs, const String &rhs)
return str;
}
const String& GD_CORE_API operator||(const String& lhs, const String &rhs)
{
return lhs.empty() ? rhs : lhs;
}
String GD_CORE_API operator||(String lhs, const char *rhs)
{
return lhs.empty() ? rhs : lhs;
}
bool GD_CORE_API operator==( const String &lhs, const String &rhs )
{
return (lhs.compare(rhs) == 0);

View File

@@ -699,6 +699,10 @@ String GD_CORE_API operator+(String lhs, const char *rhs);
*/
String GD_CORE_API operator+(const char *lhs, const String &rhs);
const String& GD_CORE_API operator||(const String &lhs, const String &rhs);
String GD_CORE_API operator||(String lhs, const char *rhs);
/**
* \}
*/

View File

@@ -0,0 +1 @@

View File

@@ -108,19 +108,8 @@ namespace gdjs {
this.setWidth(initialInstanceData.width);
this.setHeight(initialInstanceData.height);
}
initialInstanceData.numberProperties.forEach((property) => {
if (property.name === 'z') {
this.setZ(property.value);
} else if (property.name === 'depth') {
if (initialInstanceData.customSize) {
this.setDepth(property.value);
}
} else if (property.name === 'rotationX') {
this.setRotationX(property.value);
} else if (property.name === 'rotationY') {
this.setRotationY(property.value);
}
});
if (initialInstanceData.depth !== undefined)
this.setDepth(initialInstanceData.depth);
}
setX(x: float): void {

View File

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

View File

@@ -0,0 +1,106 @@
namespace gdjs {
gdjs.PixiFiltersTools.registerFilterCreator(
'Scene3D::HemisphereLight',
new (class implements gdjs.PixiFiltersTools.FilterCreator {
makeFilter(
target: EffectsTarget,
effectData: EffectData
): gdjs.PixiFiltersTools.Filter {
return new (class implements gdjs.PixiFiltersTools.Filter {
light: THREE.HemisphereLight;
rotationObject: THREE.Group;
_isEnabled: boolean = false;
top: string = 'Y-';
elevation: float = 45;
rotation: float = 0;
constructor() {
this.light = new THREE.HemisphereLight();
this.light.position.set(1, 0, 0);
this.rotationObject = new THREE.Group();
this.rotationObject.add(this.light);
this.updateRotation();
}
isEnabled(target: EffectsTarget): boolean {
return this._isEnabled;
}
setEnabled(target: EffectsTarget, enabled: boolean): boolean {
if (this._isEnabled === enabled) {
return true;
}
if (enabled) {
return this.applyEffect(target);
} else {
return this.removeEffect(target);
}
}
applyEffect(target: EffectsTarget): boolean {
const scene = target.get3DRendererObject() as
| THREE.Scene
| null
| undefined;
if (!scene) {
return false;
}
scene.add(this.rotationObject);
this._isEnabled = true;
return true;
}
removeEffect(target: EffectsTarget): boolean {
const scene = target.get3DRendererObject() as
| THREE.Scene
| null
| undefined;
if (!scene) {
return false;
}
scene.remove(this.rotationObject);
this._isEnabled = false;
return true;
}
updatePreRender(target: gdjs.EffectsTarget): any {}
updateDoubleParameter(parameterName: string, value: number): void {
if (parameterName === 'intensity') {
this.light.intensity = value;
} else if (parameterName === 'elevation') {
this.elevation = value;
this.updateRotation();
} else if (parameterName === 'rotation') {
this.rotation = value;
this.updateRotation();
}
}
updateStringParameter(parameterName: string, value: string): void {
if (parameterName === 'skyColor') {
this.light.color = new THREE.Color(
gdjs.PixiFiltersTools.rgbOrHexToHexNumber(value)
);
}
if (parameterName === 'groundColor') {
this.light.groundColor = new THREE.Color(
gdjs.PixiFiltersTools.rgbOrHexToHexNumber(value)
);
}
if (parameterName === 'top') {
this.top = value;
this.updateRotation();
}
}
updateBooleanParameter(parameterName: string, value: boolean): void {}
updateRotation() {
if (this.top === 'Z+') {
// 0° is a light from the right of the screen.
this.rotationObject.rotation.z = gdjs.toRad(this.rotation);
this.rotationObject.rotation.y = -gdjs.toRad(this.elevation);
} else {
// 0° becomes a light from Z+.
this.rotationObject.rotation.y = gdjs.toRad(this.rotation) - 90;
this.rotationObject.rotation.z = -gdjs.toRad(this.elevation);
}
}
})();
}
})()
);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,292 @@
/**
GDevelop - Particle System Extension
Copyright (c) 2010-2016 Florian Rival (Florian.Rival@gmail.com)
This project is released under the MIT License.
*/
#include "Model3DObjectConfiguration.h"
#include "GDCore/CommonTools.h"
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
#include "GDCore/Project/InitialInstance.h"
#include "GDCore/Project/MeasurementUnit.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Tools/Localization.h"
using namespace std;
Model3DObjectConfiguration::Model3DObjectConfiguration()
: width(100), height(100), depth(100), rotationX(0), rotationY(0),
rotationZ(0), modelResourceName(""), materialType("Basic"),
originLocation("ModelOrigin"), centerLocation("ModelOrigin"),
keepAspectRatio(true) {}
bool Model3DObjectConfiguration::UpdateProperty(const gd::String &propertyName,
const gd::String &newValue) {
if (propertyName == "width") {
width = newValue.To<double>();
return true;
}
if (propertyName == "height") {
height = newValue.To<double>();
return true;
}
if (propertyName == "depth") {
depth = newValue.To<double>();
return true;
}
if (propertyName == "rotationX") {
rotationX = newValue.To<double>();
return true;
}
if (propertyName == "rotationY") {
rotationY = newValue.To<double>();
return true;
}
if (propertyName == "rotationZ") {
rotationZ = newValue.To<double>();
return true;
}
if (propertyName == "modelResourceName") {
modelResourceName = newValue;
return true;
}
if (propertyName == "materialType") {
materialType = newValue;
return true;
}
if (propertyName == "originLocation") {
originLocation = newValue;
return true;
}
if (propertyName == "centerLocation") {
centerLocation = newValue;
return true;
}
if (propertyName == "keepAspectRatio") {
keepAspectRatio = newValue == "1";
return true;
}
return false;
}
std::map<gd::String, gd::PropertyDescriptor>
Model3DObjectConfiguration::GetProperties() const {
std::map<gd::String, gd::PropertyDescriptor> objectProperties;
objectProperties["width"]
.SetValue(gd::String::From(width))
.SetType("number")
.SetLabel(_("Width"))
.SetMeasurementUnit(gd::MeasurementUnit::GetPixel())
.SetGroup(_("Default size"));
objectProperties["height"]
.SetValue(gd::String::From(height))
.SetType("number")
.SetLabel(_("Height"))
.SetMeasurementUnit(gd::MeasurementUnit::GetPixel())
.SetGroup(_("Default size"));
objectProperties["depth"]
.SetValue(gd::String::From(depth))
.SetType("number")
.SetLabel(_("Depth"))
.SetMeasurementUnit(gd::MeasurementUnit::GetPixel())
.SetGroup(_("Default size"));
objectProperties["keepAspectRatio"]
.SetValue(keepAspectRatio ? "true" : "false")
.SetType("boolean")
.SetLabel(_("Reduce initial dimensions to keep aspect ratio"))
.SetGroup(_("Default size"));
objectProperties["rotationX"]
.SetValue(gd::String::From(rotationX))
.SetType("number")
.SetLabel(_("Rotation around X axis"))
.SetMeasurementUnit(gd::MeasurementUnit::GetDegreeAngle())
.SetGroup(_("Default orientation"));
objectProperties["rotationY"]
.SetValue(gd::String::From(rotationY))
.SetType("number")
.SetLabel(_("Rotation around Y axis"))
.SetMeasurementUnit(gd::MeasurementUnit::GetDegreeAngle())
.SetGroup(_("Default orientation"));
objectProperties["rotationZ"]
.SetValue(gd::String::From(rotationZ))
.SetType("number")
.SetLabel(_("Rotation around Z axis"))
.SetMeasurementUnit(gd::MeasurementUnit::GetDegreeAngle())
.SetGroup(_("Default orientation"));
objectProperties["modelResourceName"]
.SetValue(modelResourceName)
.SetType("resource")
.AddExtraInfo("model3D")
.SetLabel(_("3D model"));
objectProperties["materialType"]
.SetValue(materialType.empty() ? "Basic" : materialType)
.SetType("choice")
.AddExtraInfo("Basic")
.AddExtraInfo("StandardWithoutMetalness")
.AddExtraInfo("KeepOriginal")
.SetLabel(_("Material modifier"));
objectProperties["originLocation"]
.SetValue(originLocation.empty() ? "TopLeft" : originLocation)
.SetType("choice")
.AddExtraInfo("ModelOrigin")
.AddExtraInfo("TopLeft")
.AddExtraInfo("ObjectCenter")
.AddExtraInfo("BottomCenterZ")
.AddExtraInfo("BottomCenterY")
.SetLabel(_("Origin point"));
objectProperties["centerLocation"]
.SetValue(centerLocation.empty() ? "ObjectCenter" : centerLocation)
.SetType("choice")
.AddExtraInfo("ModelOrigin")
.AddExtraInfo("ObjectCenter")
.AddExtraInfo("BottomCenterZ")
.AddExtraInfo("BottomCenterY")
.SetLabel(_("Center point"));
return objectProperties;
}
bool Model3DObjectConfiguration::UpdateInitialInstanceProperty(
gd::InitialInstance &instance, const gd::String &propertyName,
const gd::String &newValue, gd::Project &project, gd::Layout &layout) {
return false;
}
std::map<gd::String, gd::PropertyDescriptor>
Model3DObjectConfiguration::GetInitialInstanceProperties(
const gd::InitialInstance &instance, gd::Project &project,
gd::Layout &layout) {
std::map<gd::String, gd::PropertyDescriptor> instanceProperties;
return instanceProperties;
}
void Model3DObjectConfiguration::DoUnserializeFrom(
gd::Project &project, const gd::SerializerElement &element) {
auto &content = element.GetChild("content");
width = content.GetDoubleAttribute("width");
height = content.GetDoubleAttribute("height");
depth = content.GetDoubleAttribute("depth");
rotationX = content.GetDoubleAttribute("rotationX");
rotationY = content.GetDoubleAttribute("rotationY");
rotationZ = content.GetDoubleAttribute("rotationZ");
modelResourceName = content.GetStringAttribute("modelResourceName");
materialType = content.GetStringAttribute("materialType");
originLocation = content.GetStringAttribute("originLocation");
centerLocation = content.GetStringAttribute("centerLocation");
keepAspectRatio = content.GetBoolAttribute("keepAspectRatio");
RemoveAllAnimations();
auto &animationsElement = content.GetChild("animations");
animationsElement.ConsiderAsArrayOf("animation");
for (std::size_t i = 0; i < animationsElement.GetChildrenCount(); ++i) {
auto &animationElement = animationsElement.GetChild(i);
Model3DAnimation animation;
animation.SetName(animationElement.GetStringAttribute("name", ""));
animation.SetSource(animationElement.GetStringAttribute("source", ""));
animation.SetShouldLoop(animationElement.GetBoolAttribute("loop", false));
AddAnimation(animation);
}
}
void Model3DObjectConfiguration::DoSerializeTo(
gd::SerializerElement &element) const {
auto &content = element.AddChild("content");
content.SetAttribute("width", width);
content.SetAttribute("height", height);
content.SetAttribute("depth", depth);
content.SetAttribute("rotationX", rotationX);
content.SetAttribute("rotationY", rotationY);
content.SetAttribute("rotationZ", rotationZ);
content.SetAttribute("modelResourceName", modelResourceName);
content.SetAttribute("materialType", materialType);
content.SetAttribute("originLocation", originLocation);
content.SetAttribute("centerLocation", centerLocation);
content.SetAttribute("keepAspectRatio", keepAspectRatio);
auto &animationsElement = content.AddChild("animations");
animationsElement.ConsiderAsArrayOf("animation");
for (auto &animation : animations) {
auto &animationElement = animationsElement.AddChild("animation");
animationElement.SetAttribute("name", animation.GetName());
animationElement.SetAttribute("source", animation.GetSource());
animationElement.SetAttribute("loop", animation.ShouldLoop());
}
}
void Model3DObjectConfiguration::ExposeResources(
gd::ArbitraryResourceWorker &worker) {
worker.ExposeModel3D(modelResourceName);
}
Model3DAnimation Model3DObjectConfiguration::badAnimation;
const Model3DAnimation &
Model3DObjectConfiguration::GetAnimation(std::size_t nb) const {
if (nb >= animations.size())
return badAnimation;
return animations[nb];
}
Model3DAnimation &Model3DObjectConfiguration::GetAnimation(std::size_t nb) {
if (nb >= animations.size())
return badAnimation;
return animations[nb];
}
bool Model3DObjectConfiguration::HasAnimationNamed(
const gd::String &name) const {
return !name.empty() && (find_if(animations.begin(), animations.end(),
[&name](const Model3DAnimation &animation) {
return animation.GetName() == name;
}) != animations.end());
}
void Model3DObjectConfiguration::AddAnimation(
const Model3DAnimation &animation) {
animations.push_back(animation);
}
bool Model3DObjectConfiguration::RemoveAnimation(std::size_t nb) {
if (nb >= GetAnimationsCount())
return false;
animations.erase(animations.begin() + nb);
return true;
}
void Model3DObjectConfiguration::SwapAnimations(std::size_t firstIndex,
std::size_t secondIndex) {
if (firstIndex < animations.size() && secondIndex < animations.size() &&
firstIndex != secondIndex)
std::swap(animations[firstIndex], animations[secondIndex]);
}
void Model3DObjectConfiguration::MoveAnimation(std::size_t oldIndex,
std::size_t newIndex) {
if (oldIndex >= animations.size() || newIndex >= animations.size())
return;
auto animation = animations[oldIndex];
animations.erase(animations.begin() + oldIndex);
animations.insert(animations.begin() + newIndex, animation);
}

View File

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

View File

@@ -1,4 +1,6 @@
namespace gdjs {
type Model3DAnimation = { name: string; source: string; loop: boolean };
/** Base parameters for {@link gdjs.Cube3DRuntimeObject} */
export interface Model3DObjectData extends Object3DData {
/** The base parameters of the Model3D object */
@@ -9,9 +11,40 @@ namespace gdjs {
rotationZ: number;
keepAspectRatio: boolean;
materialType: 'Basic' | 'StandardWithoutMetalness' | 'KeepOriginal';
originLocation:
| 'ModelOrigin'
| 'ObjectCenter'
| 'BottomCenterZ'
| 'BottomCenterY'
| 'TopLeft';
centerLocation:
| 'ModelOrigin'
| 'ObjectCenter'
| 'BottomCenterZ'
| 'BottomCenterY';
animations: Model3DAnimation[];
};
}
type FloatPoint3D = [float, float, float];
const getPointForLocation = (location: string): FloatPoint3D | null => {
switch (location) {
case 'ModelOrigin':
return null;
case 'ObjectCenter':
return [0.5, 0.5, 0.5];
case 'BottomCenterZ':
return [0.5, 0.5, 0];
case 'BottomCenterY':
return [0.5, 1, 0.5];
case 'TopLeft':
return [0, 0, 0];
default:
return null;
}
};
/**
* A 3D object which displays a 3D model.
*/
@@ -22,17 +55,61 @@ namespace gdjs {
_materialType: gdjs.Model3DRuntimeObject.MaterialType =
gdjs.Model3DRuntimeObject.MaterialType.Basic;
/**
* The local point of the model that will be at the object position.
*
* Coordinates are between 0 and 1.
*
* Its value is `null` when the point is configured to `"ModelOrigin"`
* because the model origin needs to be evaluated according to the object
* configuration.
* @see gdjs.Model3DRuntimeObject3DRenderer.getOriginPoint
*/
_originPoint: FloatPoint3D | null;
/**
* The local point of the model that is used as rotation center.
*
* Coordinates are between 0 and 1.
*
* Its value is `null` when the point is configured to `"ModelOrigin"`
* because the model origin needs to be evaluated according to the object
* configuration.
* @see gdjs.Model3DRuntimeObject3DRenderer.getCenterPoint
*/
_centerPoint: FloatPoint3D | null;
_animations: Model3DAnimation[];
_currentAnimationIndex: integer = 0;
_animationSpeedScale: float = 1;
_animationPaused: boolean = false;
constructor(
instanceContainer: gdjs.RuntimeInstanceContainer,
objectData: Model3DObjectData
) {
super(instanceContainer, objectData);
this._modelResourceName = objectData.content.modelResourceName;
this._animations = objectData.content.animations;
this._originPoint = getPointForLocation(
objectData.content.originLocation
);
this._centerPoint = getPointForLocation(
objectData.content.centerLocation
);
this._renderer = new gdjs.Model3DRuntimeObjectRenderer(
this,
instanceContainer
);
this._updateMaterialType(objectData);
this._materialType = this._convertMaterialType(
objectData.content.materialType
);
this._updateModel(objectData);
if (this._animations.length > 0) {
this._renderer.playAnimation(
this._animations[0].source,
this._animations[0].loop
);
}
// *ALWAYS* call `this.onCreated()` at the very end of your object constructor.
this.onCreated();
@@ -53,23 +130,42 @@ namespace gdjs {
oldObjectData.content.keepAspectRatio !==
newObjectData.content.keepAspectRatio
) {
this._updateDefaultTransformation(newObjectData);
this._updateModel(newObjectData);
}
if (
oldObjectData.content.materialType !==
newObjectData.content.materialType
) {
this._updateMaterialType(newObjectData);
this._materialType = this._convertMaterialType(
newObjectData.content.materialType
);
this._updateModel(newObjectData);
}
if (
oldObjectData.content.originLocation !==
newObjectData.content.originLocation
) {
this._originPoint = getPointForLocation(
newObjectData.content.originLocation
);
}
if (
oldObjectData.content.centerLocation !==
newObjectData.content.centerLocation
) {
this._centerPoint = getPointForLocation(
newObjectData.content.centerLocation
);
}
return true;
}
_updateDefaultTransformation(objectData: Model3DObjectData) {
_updateModel(objectData: Model3DObjectData) {
const rotationX = objectData.content.rotationX || 0;
const rotationY = objectData.content.rotationY || 0;
const rotationZ = objectData.content.rotationZ || 0;
const keepAspectRatio = objectData.content.keepAspectRatio;
this._renderer._updateDefaultTransformation(
this._renderer._updateModel(
rotationX,
rotationY,
rotationZ,
@@ -96,12 +192,118 @@ namespace gdjs {
}
}
_updateMaterialType(objectData: Model3DObjectData) {
this._materialType = this._convertMaterialType(
objectData.content.materialType
update(instanceContainer: gdjs.RuntimeInstanceContainer): void {
const elapsedTime = this.getElapsedTime() / 1000;
this._renderer.updateAnimation(elapsedTime * this._animationSpeedScale);
}
/**
* Get the index of the animation being played.
* @return The index of the new animation being played
*/
getAnimationIndex(): number {
return this._currentAnimationIndex;
}
/**
* Change the animation being played.
* @param animationIndex The index of the new animation to be played
*/
setAnimationIndex(animationIndex: number): void {
animationIndex = animationIndex | 0;
if (
animationIndex < this._animations.length &&
this._currentAnimationIndex !== animationIndex &&
animationIndex >= 0
) {
const animation = this._animations[animationIndex];
this._currentAnimationIndex = animationIndex;
this._renderer.playAnimation(animation.source, animation.loop);
}
}
/**
* Get the name of the animation being played.
* @return The name of the new animation being played
*/
getAnimationName(): string {
if (this._currentAnimationIndex >= this._animations.length) {
return '';
}
return this._animations[this._currentAnimationIndex].name;
}
/**
* Change the animation being played.
* @param newAnimationName The name of the new animation to be played
*/
setAnimationName(newAnimationName: string): void {
if (!newAnimationName) {
return;
}
const animationIndex = this._animations.findIndex(
(animation) => animation.name === newAnimationName
);
this._renderer._updateMaterials();
this._updateDefaultTransformation(objectData);
if (animationIndex >= 0) {
this.setAnimationIndex(animationIndex);
}
}
isCurrentAnimationName(name: string): boolean {
return this.getAnimationName() === name;
}
/**
* Return true if animation has ended.
* The animation had ended if:
* - it's not configured as a loop;
* - the current frame is the last frame;
* - the last frame has been displayed long enough.
*/
hasAnimationEnded(): boolean {
return this._renderer.hasAnimationEnded();
}
isAnimationPaused() {
return this._animationPaused;
}
pauseAnimation() {
this._animationPaused = true;
return this._renderer.pauseAnimation();
}
resumeAnimation() {
this._animationPaused = false;
return this._renderer.resumeAnimation();
}
getAnimationSpeedScale() {
return this._animationSpeedScale;
}
setAnimationSpeedScale(ratio: float): void {
this._animationSpeedScale = ratio;
}
getCenterX(): float {
const centerPoint = this._renderer.getCenterPoint();
return this.getWidth() * centerPoint[0];
}
getCenterY(): float {
const centerPoint = this._renderer.getCenterPoint();
return this.getHeight() * centerPoint[1];
}
getDrawableX(): float {
const originPoint = this._renderer.getOriginPoint();
return this.getX() - this.getWidth() * originPoint[0];
}
getDrawableY(): float {
const originPoint = this._renderer.getOriginPoint();
return this.getY() - this.getHeight() * originPoint[1];
}
}

View File

@@ -1,38 +1,144 @@
namespace gdjs {
type FloatPoint3D = [float, float, float];
const removeMetalness = (material: THREE.Material): void => {
//@ts-ignore
if (material.metalness) {
//@ts-ignore
material.metalness = 0;
}
};
const removeMetalnessFromMesh = (node: THREE.Object3D<THREE.Event>) => {
const mesh = node as THREE.Mesh;
if (!mesh.material) {
return;
}
if (Array.isArray(mesh.material)) {
for (let index = 0; index < mesh.material.length; index++) {
removeMetalness(mesh.material[index]);
}
} else {
removeMetalness(mesh.material);
}
};
const traverseToRemoveMetalnessFromMeshes = (
node: THREE.Object3D<THREE.Event>
) => node.traverse(removeMetalnessFromMesh);
const convertToBasicMaterial = (
material: THREE.Material
): THREE.MeshBasicMaterial => {
const basicMaterial = new THREE.MeshBasicMaterial();
//@ts-ignore
if (material.color) {
//@ts-ignore
basicMaterial.color = material.color;
}
//@ts-ignore
if (material.map) {
//@ts-ignore
basicMaterial.map = material.map;
}
return basicMaterial;
};
const setBasicMaterialTo = (node: THREE.Object3D<THREE.Event>): void => {
const mesh = node as THREE.Mesh;
if (!mesh.material) {
return;
}
if (Array.isArray(mesh.material)) {
for (let index = 0; index < mesh.material.length; index++) {
mesh.material[index] = convertToBasicMaterial(mesh.material[index]);
}
} else {
mesh.material = convertToBasicMaterial(mesh.material);
}
};
const traverseToSetBasicMaterialFromMeshes = (
node: THREE.Object3D<THREE.Event>
) => node.traverse(setBasicMaterialTo);
class Model3DRuntimeObject3DRenderer extends gdjs.RuntimeObject3DRenderer {
private _model3DRuntimeObject: gdjs.Model3DRuntimeObject;
/**
* The 3D model stretched in a 1x1x1 cube.
*/
private _threeObject: THREE.Object3D;
private _originalModel: THREE_ADDONS.GLTF;
private _animationMixer: THREE.AnimationMixer;
private _action: THREE.AnimationAction | null;
/**
* The model origin evaluated according to the object configuration.
*
* Coordinates are between 0 and 1.
*/
private _modelOriginPoint: FloatPoint3D;
constructor(
runtimeObject: gdjs.Model3DRuntimeObject,
instanceContainer: gdjs.RuntimeInstanceContainer
) {
// @ts-ignore It can't be null if THREE exists.
const originalModelMesh: THREE.Object3D = instanceContainer
// GLB files with skeleton must not have any transformation to work properly.
const originalModel = instanceContainer
.getGame()
.getModel3DManager()
.getModel(runtimeObject._modelResourceName);
const modelObject3D = originalModelMesh.clone();
// _updateModel will actually add a clone of the model.
const model = new THREE.Group();
// Create a group to transform the object according to
// position, angle and dimensions.
const group = new THREE.Group();
group.rotation.order = 'ZYX';
group.add(modelObject3D);
group.add(model);
super(runtimeObject, instanceContainer, group);
this._model3DRuntimeObject = runtimeObject;
this._threeObject = modelObject3D;
this._threeObject = model;
this._originalModel = originalModel;
this._modelOriginPoint = [0, 0, 0];
this.updateSize();
this.updatePosition();
this.updateRotation();
this._animationMixer = new THREE.AnimationMixer(model);
this._action = null;
}
_updateDefaultTransformation(
updateAnimation(timeDelta: float) {
this._animationMixer.update(timeDelta);
}
updatePosition() {
const originPoint = this.getOriginPoint();
const centerPoint = this.getCenterPoint();
this.get3DRendererObject().position.set(
this._object.getX() -
this._object.getWidth() * (originPoint[0] - centerPoint[0]),
this._object.getY() -
this._object.getHeight() * (originPoint[1] - centerPoint[1]),
this._object.getZ() -
this._object.getDepth() * (originPoint[2] - centerPoint[2])
);
}
getOriginPoint() {
return this._model3DRuntimeObject._originPoint || this._modelOriginPoint;
}
getCenterPoint() {
return this._model3DRuntimeObject._centerPoint || this._modelOriginPoint;
}
private _updateDefaultTransformation(
threeObject: THREE.Object3D,
rotationX: float,
rotationY: float,
rotationZ: float,
@@ -41,38 +147,63 @@ namespace gdjs {
originalDepth: float,
keepAspectRatio: boolean
) {
const boundingBox = this._getModelAABB(rotationX, rotationY, rotationZ);
threeObject.rotation.set(
gdjs.toRad(rotationX),
gdjs.toRad(rotationY),
gdjs.toRad(rotationZ)
);
threeObject.updateMatrixWorld(true);
const boundingBox = new THREE.Box3().setFromObject(threeObject);
const modelWidth = boundingBox.max.x - boundingBox.min.x;
const modelHeight = boundingBox.max.y - boundingBox.min.y;
const modelDepth = boundingBox.max.z - boundingBox.min.z;
this._modelOriginPoint[0] = -boundingBox.min.x / modelWidth;
this._modelOriginPoint[1] = -boundingBox.min.y / modelHeight;
this._modelOriginPoint[2] = -boundingBox.min.z / modelDepth;
// The model is flipped on Y axis.
this._modelOriginPoint[1] = 1 - this._modelOriginPoint[1];
// Center the model.
this._threeObject.position.set(
-(boundingBox.min.x + boundingBox.max.x) / 2,
(this._threeObject.position.y =
-(boundingBox.min.y + boundingBox.max.y) / 2),
(this._threeObject.position.z =
-(boundingBox.min.z + boundingBox.max.z) / 2)
);
const centerPoint = this._model3DRuntimeObject._centerPoint;
if (centerPoint) {
threeObject.position.set(
-(
boundingBox.min.x +
(boundingBox.max.x - boundingBox.min.x) * centerPoint[0]
),
// The model is flipped on Y axis.
-(
boundingBox.min.y +
(boundingBox.max.y - boundingBox.min.y) * (1 - centerPoint[1])
),
-(
boundingBox.min.z +
(boundingBox.max.z - boundingBox.min.z) * centerPoint[2]
)
);
}
// Rotate the model.
this._threeObject.scale.set(1, 1, 1);
this._threeObject.rotation.set(
threeObject.scale.set(1, 1, 1);
threeObject.rotation.set(
gdjs.toRad(rotationX),
gdjs.toRad(rotationY),
gdjs.toRad(rotationZ)
);
// Stretch the model in a 1x1x1 cube.
const modelWidth = boundingBox.max.x - boundingBox.min.x;
const modelHeight = boundingBox.max.y - boundingBox.min.y;
const modelDepth = boundingBox.max.z - boundingBox.min.z;
const scaleX = 1 / modelWidth;
const scaleY = 1 / modelHeight;
const scaleZ = 1 / modelDepth;
const scaleMatrix = new THREE.Matrix4();
scaleMatrix.makeScale(scaleX, scaleY, scaleZ);
this._threeObject.updateMatrix();
this._threeObject.applyMatrix4(scaleMatrix);
// Flip on Y because the Y axis is on the opposite side of direct basis.
// It avoids models to be like a mirror refection.
scaleMatrix.makeScale(scaleX, -scaleY, scaleZ);
threeObject.updateMatrix();
threeObject.applyMatrix4(scaleMatrix);
if (keepAspectRatio) {
// Reduce the object dimensions to keep aspect ratio.
@@ -85,98 +216,138 @@ namespace gdjs {
this._object._setOriginalHeight(scaleRatio * modelHeight);
this._object._setOriginalDepth(scaleRatio * modelDepth);
}
this._threeObject.updateMatrix();
}
private _getModelAABB(
_updateModel(
rotationX: float,
rotationY: float,
rotationZ: float
rotationZ: float,
originalWidth: float,
originalHeight: float,
originalDepth: float,
keepAspectRatio: boolean
) {
// The original model is used because `setFromObject` is working in
// world transformation.
// Start from the original model because:
// - _replaceMaterials is destructive
// - _updateDefaultTransformation may need to work with meshes in local space
// @ts-ignore It can't be null if THREE exists.
const originalModelMesh: THREE.Object3D = this._object
.getInstanceContainer()
.getGame()
.getModel3DManager()
.getModel(this._model3DRuntimeObject._modelResourceName);
// This group hold the rotation defined by properties.
const threeObject = new THREE.Group();
threeObject.rotation.order = 'ZYX';
const root = THREE_ADDONS.SkeletonUtils.clone(this._originalModel.scene);
threeObject.add(root);
originalModelMesh.rotation.set(
gdjs.toRad(rotationX),
gdjs.toRad(rotationY),
gdjs.toRad(rotationZ)
this._replaceMaterials(threeObject);
this._updateDefaultTransformation(
threeObject,
rotationX,
rotationY,
rotationZ,
originalWidth,
originalHeight,
originalDepth,
keepAspectRatio
);
const aabb = new THREE.Box3().setFromObject(originalModelMesh);
// Revert changes.
originalModelMesh.rotation.set(0, 0, 0);
return aabb;
}
_updateMaterials() {
// @ts-ignore It can't be null if THREE exists.
const originalModelMesh: THREE.Object3D = this._model3DRuntimeObject
.getInstanceContainer()
.getGame()
.getModel3DManager()
.getModel(this._model3DRuntimeObject._modelResourceName);
const modelObject3D = originalModelMesh.clone();
// Replace the 3D object.
this.get3DRendererObject().remove(this._threeObject);
this.get3DRendererObject().add(modelObject3D);
this.get3DRendererObject().add(threeObject);
this._threeObject = threeObject;
this._threeObject = modelObject3D;
this._replaceMaterials();
// Start the current animation on the new 3D object.
this._animationMixer = new THREE.AnimationMixer(root);
const isAnimationPaused = this._model3DRuntimeObject.isAnimationPaused();
this._model3DRuntimeObject.setAnimationIndex(
this._model3DRuntimeObject.getAnimationIndex()
);
if (isAnimationPaused) {
this.pauseAnimation();
}
}
/**
* Replace materials to better work with lights (or no light).
*/
_replaceMaterials() {
private _replaceMaterials(threeObject: THREE.Object3D) {
if (
this._model3DRuntimeObject._materialType ===
gdjs.Model3DRuntimeObject.MaterialType.StandardWithoutMetalness
) {
this._threeObject.traverse((node) => {
if (node.type === 'Mesh') {
const mesh = node as THREE.Mesh;
const material = mesh.material as THREE.MeshStandardMaterial;
//@ts-ignore
if (material.metalness) {
//@ts-ignore
material.metalness = 0;
}
}
});
traverseToRemoveMetalnessFromMeshes(threeObject);
} else if (
this._model3DRuntimeObject._materialType ===
gdjs.Model3DRuntimeObject.MaterialType.Basic
) {
this._threeObject.traverse((node) => {
if (node.type === 'Mesh') {
const mesh = node as THREE.Mesh;
const basicMaterial = new THREE.MeshBasicMaterial();
//@ts-ignore
if (mesh.material.color) {
//@ts-ignore
basicMaterial.color = mesh.material.color;
}
//@ts-ignore
if (mesh.material.map) {
//@ts-ignore
basicMaterial.map = mesh.material.map;
}
mesh.material = basicMaterial;
}
});
traverseToSetBasicMaterialFromMeshes(threeObject);
}
}
getAnimationCount() {
return this._originalModel.animations.length;
}
getAnimationName(animationIndex: integer) {
return this._originalModel.animations[animationIndex].name;
}
/**
* Return true if animation has ended.
* The animation had ended if:
* - it's not configured as a loop;
* - the current frame is the last frame;
* - the last frame has been displayed long enough.
*/
hasAnimationEnded(): boolean {
if (!this._action) {
return true;
}
return !this._action.isRunning();
}
animationPaused() {
if (!this._action) {
return;
}
return this._action.paused;
}
pauseAnimation() {
if (!this._action) {
return;
}
this._action.paused = true;
}
resumeAnimation() {
if (!this._action) {
return;
}
this._action.paused = false;
}
playAnimation(animationName: string, shouldLoop: boolean) {
this._animationMixer.stopAllAction();
const clip = THREE.AnimationClip.findByName(
this._originalModel.animations,
animationName
);
if (!clip) {
console.error(
`The GLB file: ${this._model3DRuntimeObject._modelResourceName} doesn't have any animation named: ${animationName}`
);
return;
}
this._action = this._animationMixer.clipAction(clip);
this._action.setLoop(
shouldLoop ? THREE.LoopRepeat : THREE.LoopOnce,
Number.POSITIVE_INFINITY
);
this._action.clampWhenFinished = true;
this._action.play();
// Make sure the first frame is displayed.
this._animationMixer.update(0);
}
}
export const Model3DRuntimeObjectRenderer = Model3DRuntimeObject3DRenderer;

View File

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

View File

@@ -1,27 +1,34 @@
#This is the CMake file used to build the C++ extensions.
#For more information, see the README.md file.
# This is the CMake file used to build the C++ extensions.
# For more information, see the README.md file.
cmake_minimum_required(VERSION 2.6)
cmake_policy(SET CMP0011 NEW)
cmake_minimum_required(VERSION 3.5)
project(GD-Extensions)
include(CMakeUtils.txt) #Functions to factor common tasks done in CMakeLists.txt of extensions
include(CMakeUtils.txt) # Functions to factor common tasks done in CMakeLists.txt of extensions
#Add all the CMakeLists (for non pure JS extensions):
ADD_SUBDIRECTORY(AnchorBehavior)
ADD_SUBDIRECTORY(DestroyOutsideBehavior)
ADD_SUBDIRECTORY(DraggableBehavior)
ADD_SUBDIRECTORY(Inventory)
ADD_SUBDIRECTORY(LinkedObjects)
ADD_SUBDIRECTORY(ParticleSystem)
ADD_SUBDIRECTORY(PanelSpriteObject)
ADD_SUBDIRECTORY(PathfindingBehavior)
ADD_SUBDIRECTORY(PhysicsBehavior)
ADD_SUBDIRECTORY(PlatformBehavior)
ADD_SUBDIRECTORY(PrimitiveDrawing)
ADD_SUBDIRECTORY(Shopify)
ADD_SUBDIRECTORY(SystemInfo)
ADD_SUBDIRECTORY(TextEntryObject)
ADD_SUBDIRECTORY(TextObject)
ADD_SUBDIRECTORY(TiledSpriteObject)
ADD_SUBDIRECTORY(TopDownMovementBehavior)
# List of non pure JS extensions
set(
GD_EXTENSIONS
3D
AnchorBehavior
DestroyOutsideBehavior
DraggableBehavior
Inventory
LinkedObjects
PanelSpriteObject
ParticleSystem
PathfindingBehavior
PhysicsBehavior
PlatformBehavior
PrimitiveDrawing
Shopify
SystemInfo
TextEntryObject
TextObject
TiledSpriteObject
TopDownMovementBehavior)
# Automatically add all listed extensions
foreach(extension ${GD_EXTENSIONS})
add_subdirectory(${extension})
endforeach()

View File

@@ -7,79 +7,75 @@ macro(gd_add_extension_includes)
include_directories(${GDCORE_include_dir})
endmacro()
#Add common defines for a target that will be a GD extension
# Add common defines for a target that will be a GD extension
function(gd_add_extension_definitions target_name)
#Define used in GD to check the build type
IF(CMAKE_BUILD_TYPE MATCHES "Debug")
add_definitions( -DDEBUG )
ELSE()
add_definitions( -DRELEASE )
ENDIF()
# Define used in GD to check the build type
if("${CMAKE_BUILD_TYPE}" MATCHES "Debug")
add_definitions(-DDEBUG)
else()
add_definitions(-DRELEASE)
endif()
set(${target_name}_extra_definitions "${${target_name}_extra_definitions} GD_IDE_ONLY=1;" PARENT_SCOPE)
#Defne used in GD to identify the environment
IF (EMSCRIPTEN)
add_definitions( -DEMSCRIPTEN )
ELSEIF(WIN32)
add_definitions( -DWINDOWS )
ELSEIF(APPLE)
add_definitions( -DMACOS )
ELSE()
add_definitions( -DLINUX )
ENDIF()
# Define used in GD to identify the environment
if(EMSCRIPTEN)
add_definitions(-DEMSCRIPTEN)
elseif(WIN32)
add_definitions(-DWINDOWS)
elseif(APPLE)
add_definitions(-DMACOS)
else()
add_definitions(-DLINUX)
endif()
IF(WIN32) #Windows specific defines
add_definitions( "-DGD_CORE_API=__declspec(dllimport)" )
add_definitions( "-DGD_API=__declspec(dllimport)" )
add_definitions( "-DGD_EXTENSION_API=__declspec(dllexport)" )
add_definitions( -D__GNUWIN32__ )
ELSE()
add_definitions( -DGD_API= )
add_definitions( -DGD_CORE_API= )
add_definitions( -DGD_EXTENSION_API= )
ENDIF(WIN32)
if(WIN32) # Windows specific defines
add_definitions("-DGD_API=__declspec(dllimport)")
add_definitions("-DGD_CORE_API=__declspec(dllimport)")
add_definitions("-DGD_EXTENSION_API=__declspec(dllexport)")
add_definitions(-D__GNUWIN32__)
else()
add_definitions(-DGD_API=)
add_definitions(-DGD_CORE_API=)
add_definitions(-DGD_EXTENSION_API=)
endif()
endfunction()
#Add a GD extension target, that will produce the final library file.
# Add a GD extension target, that will produce the final library file.
function(gd_add_extension_target target_name source_files)
IF(target_name STREQUAL "")
MESSAGE(ERROR "You called gd_add_extension_target without specifying a target name")
ENDIF()
if(target_name STREQUAL "")
message(ERROR "You called gd_add_extension_target without specifying a target name")
endif()
SET(platform_directory ${ARGV2})
IF(NOT platform_directory)
SET(platform_directory "CppPlatform")
ENDIF()
set(platform_directory ${ARGV2})
if(NOT platform_directory)
set(platform_directory "CppPlatform")
endif()
IF(EMSCRIPTEN)
if(EMSCRIPTEN)
# Emscripten treats all libraries as static libraries
add_library(${target_name} STATIC ${source_files})
ELSE()
else()
add_library(${target_name} SHARED ${source_files})
ENDIF()
endif()
set_target_properties(${target_name} PROPERTIES PREFIX "")
set_target_properties(${target_name} PROPERTIES COMPILE_DEFINITIONS "${${target_name}_extra_definitions}")
set_target_properties(${target_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME}/${platform_directory}/Extensions")
set_target_properties(${target_name} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME}/${platform_directory}/Extensions")
set_target_properties(${target_name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME}/${platform_directory}/Extensions")
IF(WIN32) #GD extensions have special suffix in their filenames.
if(WIN32) # GD extensions have special suffix in their filenames.
set_target_properties(${target_name} PROPERTIES SUFFIX ".xgdwe")
ELSEIF(EMSCRIPTEN)
elseif(EMSCRIPTEN)
set_target_properties(${target_name} PROPERTIES SUFFIX ".bc")
ELSE()
else()
set_target_properties(${target_name} PROPERTIES SUFFIX ".xgde")
ENDIF()
endif()
endfunction()
#Link default libraries with a target that is a GD extension
# Link default libraries with a target that is a GD extension
function(gd_extension_link_libraries target_name)
IF(EMSCRIPTEN)
#Nothing.
ELSE()
if(NOT EMSCRIPTEN)
target_link_libraries(${target_name} GDCore)
ENDIF()
endif()
endfunction()

View File

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

View File

@@ -46,7 +46,7 @@ module.exports = {
_(
'Load a dialogue data object - Yarn json format, stored in a scene variable. Use this command to load all the Dialogue data at the beginning of the game.'
),
_('Load dialogue data from Scene variable _PARAM1_'),
_('Load dialogue data from Scene variable _PARAM0_'),
'',
'JsPlatform/Extensions/yarn32.png',
'JsPlatform/Extensions/yarn32.png'

View File

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

View File

@@ -41,7 +41,7 @@ namespace gdjs {
/**
* The current authentication status.
*/
export let authentified = false;
export let authenticated = false;
/**
* The logged-in users data.
@@ -345,10 +345,13 @@ namespace gdjs {
};
/**
* Returns true if the user is currently authentified.
* @see authentified
* Returns true if the user is currently authenticated.
* @see authenticated
*/
export const isAuthentified = (): boolean => authentified;
export const isAuthenticated = (): boolean => authenticated;
/** @deprecated Use isAuthenticated instead. */
export const isAuthentified = isAuthenticated;
/**
* Signs the user in with basic email-password authentication.
@@ -442,14 +445,14 @@ namespace gdjs {
firebaseTools.onAppCreated.push(() => {
firebase.auth().onAuthStateChanged((user) => {
if (user) {
authentified = true;
authenticated = true;
currentUser = user;
user.getIdToken().then(
// Prefetch the token
(token) => (_token = token)
);
} else {
authentified = false;
authenticated = false;
currentUser = null;
}
});

View File

@@ -14,7 +14,7 @@ namespace gdjs {
/**
* Uploads a file as string to the firebase storage bucket.
* @param file - The entire file as string.
* @param onlinePath - The path under wich the file will be accessible on the bucket.
* @param onlinePath - The path under which the file will be accessible on the bucket.
* @param [type] - The type/format of the string to upload.
* @param [callbackStateVariable] - The variable where to store if the operation was successful.
* @param [callbackValueVariable] - The variable where to store the result (url to the file).

View File

@@ -395,7 +395,7 @@ module.exports = {
.addIncludeFile('Extensions/Firebase/A_firebasejs/B_firebase-auth.js')
.addIncludeFile('Extensions/Firebase/B_firebasetools/C_firebasetools.js')
.addIncludeFile('Extensions/Firebase/B_firebasetools/D_authtools.js')
.setFunctionName('gdjs.evtTools.firebaseTools.auth.isAuthentified');
.setFunctionName('gdjs.evtTools.firebaseTools.auth.isAuthenticated');
extension
.addStrExpression(

View File

@@ -533,7 +533,7 @@ describeIfOnline('Firebase extension end-to-end tests', function () {
const password2 = `myNewPass${Math.random().toString(16)}${Date.now()}!`;
const expectToNotLogin = async (password) => {
if (gdjs.evtTools.firebaseTools.auth.isAuthentified())
if (gdjs.evtTools.firebaseTools.auth.isAuthenticated())
await firebase.auth().signOut();
let errors = false;
@@ -553,11 +553,11 @@ describeIfOnline('Firebase extension end-to-end tests', function () {
if (!errors)
throw new Error('Expected wrong credentials to prevent login');
expect(gdjs.evtTools.firebaseTools.auth.isAuthentified()).to.not.be.ok();
expect(gdjs.evtTools.firebaseTools.auth.isAuthenticated()).to.not.be.ok();
};
const expectToLogin = async (password) => {
if (gdjs.evtTools.firebaseTools.auth.isAuthentified())
if (gdjs.evtTools.firebaseTools.auth.isAuthenticated())
await firebase.auth().signOut();
await promisifyCallbackVariables((callback) =>
@@ -568,13 +568,13 @@ describeIfOnline('Firebase extension end-to-end tests', function () {
)
);
expect(gdjs.evtTools.firebaseTools.auth.isAuthentified()).to.be.ok();
expect(gdjs.evtTools.firebaseTools.auth.isAuthenticated()).to.be.ok();
};
before(async () => firebase.auth().signOut());
it('let users create accounts', async () => {
expect(gdjs.evtTools.firebaseTools.auth.isAuthentified()).to.not.be.ok();
expect(gdjs.evtTools.firebaseTools.auth.isAuthenticated()).to.not.be.ok();
await promisifyCallbackVariables((callback) =>
gdjs.evtTools.firebaseTools.auth.createAccountWithEmail(
@@ -584,13 +584,13 @@ describeIfOnline('Firebase extension end-to-end tests', function () {
)
);
expect(gdjs.evtTools.firebaseTools.auth.isAuthentified()).to.be.ok();
expect(gdjs.evtTools.firebaseTools.auth.isAuthenticated()).to.be.ok();
});
it('let users log out', async () => {
expect(gdjs.evtTools.firebaseTools.auth.isAuthentified()).to.be.ok();
expect(gdjs.evtTools.firebaseTools.auth.isAuthenticated()).to.be.ok();
await firebase.auth().signOut();
expect(gdjs.evtTools.firebaseTools.auth.isAuthentified()).to.not.be.ok();
expect(gdjs.evtTools.firebaseTools.auth.isAuthenticated()).to.not.be.ok();
});
it('prevents logging in with invalid credentials', async () =>

View File

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

View File

@@ -26,70 +26,57 @@ class InventoryJsExtension : public gd::PlatformExtension {
DeclareInventoryExtension(*this);
GetAllActions()["Inventory::Add"]
.codeExtraInformation
.SetIncludeFile("Extensions/Inventory/inventory.js")
.AddIncludeFile("Extensions/Inventory/inventorytools.js")
.SetFunctionName("gdjs.evtTools.inventory.add");
GetAllActions()["Inventory::Remove"]
.codeExtraInformation
.SetIncludeFile("Extensions/Inventory/inventory.js")
.AddIncludeFile("Extensions/Inventory/inventorytools.js")
.SetFunctionName("gdjs.evtTools.inventory.remove");
GetAllActions()["Inventory::SetMaximum"]
.codeExtraInformation
.SetIncludeFile("Extensions/Inventory/inventory.js")
.AddIncludeFile("Extensions/Inventory/inventorytools.js")
.SetFunctionName("gdjs.evtTools.inventory.setMaximum");
GetAllActions()["Inventory::SetUnlimited"]
.codeExtraInformation
.SetIncludeFile("Extensions/Inventory/inventory.js")
.AddIncludeFile("Extensions/Inventory/inventorytools.js")
.SetFunctionName("gdjs.evtTools.inventory.setUnlimited");
GetAllActions()["Inventory::Equip"]
.codeExtraInformation
.SetIncludeFile("Extensions/Inventory/inventory.js")
.AddIncludeFile("Extensions/Inventory/inventorytools.js")
.SetFunctionName("gdjs.evtTools.inventory.equip");
GetAllActions()["Inventory::SerializeToVariable"]
.codeExtraInformation
.SetIncludeFile("Extensions/Inventory/inventory.js")
.AddIncludeFile("Extensions/Inventory/inventorytools.js")
.SetFunctionName("gdjs.evtTools.inventory.serializeToVariable");
GetAllActions()["Inventory::UnserializeFromVariable"]
.codeExtraInformation
.SetIncludeFile("Extensions/Inventory/inventory.js")
.AddIncludeFile("Extensions/Inventory/inventorytools.js")
.SetFunctionName("gdjs.evtTools.inventory.unserializeFromVariable");
GetAllConditions()["Inventory::Count"]
.codeExtraInformation
.SetIncludeFile("Extensions/Inventory/inventory.js")
.AddIncludeFile("Extensions/Inventory/inventorytools.js")
.SetFunctionName("gdjs.evtTools.inventory.count");
GetAllConditions()["Inventory::Has"]
.codeExtraInformation
.SetIncludeFile("Extensions/Inventory/inventory.js")
.AddIncludeFile("Extensions/Inventory/inventorytools.js")
.SetFunctionName("gdjs.evtTools.inventory.has");
GetAllConditions()["Inventory::IsFull"]
.codeExtraInformation
.SetIncludeFile("Extensions/Inventory/inventory.js")
.AddIncludeFile("Extensions/Inventory/inventorytools.js")
.SetFunctionName("gdjs.evtTools.inventory.isFull");
GetAllConditions()["Inventory::IsEquipped"]
.codeExtraInformation
.SetIncludeFile("Extensions/Inventory/inventory.js")
.AddIncludeFile("Extensions/Inventory/inventorytools.js")
.SetFunctionName("gdjs.evtTools.inventory.isEquipped");
GetAllExpressions()["Inventory::Count"]
.codeExtraInformation
.SetIncludeFile("Extensions/Inventory/inventory.js")
.AddIncludeFile("Extensions/Inventory/inventorytools.js")
.SetFunctionName("gdjs.evtTools.inventory.count");
GetAllExpressions()["Inventory::Maximum"]
.codeExtraInformation
.SetIncludeFile("Extensions/Inventory/inventory.js")
.AddIncludeFile("Extensions/Inventory/inventorytools.js")
.SetFunctionName("gdjs.evtTools.inventory.maximum");

View File

@@ -18,6 +18,7 @@ export type ObjectsRenderingService = {
gd: libGDevelop,
PIXI: any,
THREE: any,
THREE_ADDONS: {SkeletonUtils: any},
RenderedInstance: any,
Rendered3DInstance: any,
registerInstanceRenderer: (objectType: string, renderer: any) => void,

View File

@@ -290,74 +290,31 @@ module.exports = {
.getValue()
);
if (this._radius <= 0) this._radius = 1;
const colorHex = objectsRenderingService.rgbOrHexToHexNumber(
const color = objectsRenderingService.rgbOrHexToHexNumber(
this._associatedObjectConfiguration
.getProperties(this.project)
.get('color')
.getValue()
);
this._color = [
((colorHex >> 16) & 0xff) / 255,
((colorHex >> 8) & 0xff) / 255,
(colorHex & 0xff) / 255,
];
const geometry = new PIXI.Geometry();
const shader = PIXI.Shader.from(
`
precision mediump float;
attribute vec2 aVertexPosition;
// The icon in the middle.
const lightIconSprite = new PIXI.Sprite(PIXI.Texture.from('CppPlatform/Extensions/lightIcon32.png'));
lightIconSprite.anchor.x = 0.5;
lightIconSprite.anchor.y = 0.5;
uniform mat3 translationMatrix;
uniform mat3 projectionMatrix;
varying vec2 vPos;
void main() {
vPos = aVertexPosition;
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
}`,
`
precision mediump float;
uniform vec2 center;
uniform float radius;
uniform vec3 color;
uniform mat3 translationMatrix;
uniform mat3 projectionMatrix;
varying vec2 vPos;
void main() {
float l = length(vPos - center);
float intensity = 0.0;
if(l < radius)
intensity = clamp((radius - l)*(radius - l)/(radius*radius), 0.0, 1.0);
gl_FragColor = vec4(color*intensity, 1.0);
}
`,
{
center: [this._instance.getX(), this._instance.getY()],
radius: this._radius,
color: this._color,
}
// The circle to show the radius of the light.
const radiusBorderWidth = 2;
const radiusGraphics = new PIXI.Graphics();
radiusGraphics.lineStyle(
radiusBorderWidth,
color,
0.8
);
radiusGraphics.drawCircle(0, 0, Math.max(1, this._radius - radiusBorderWidth));
this._vertexBuffer = new Float32Array([
this._instance.getX() - this._radius,
this._instance.getY() + this._radius,
this._instance.getX() + this._radius,
this._instance.getY() + this._radius,
this._instance.getX() + this._radius,
this._instance.getY() - this._radius,
this._instance.getX() - this._radius,
this._instance.getY() - this._radius,
]);
geometry
.addAttribute('aVertexPosition', this._vertexBuffer, 2)
.addIndex([0, 1, 2, 2, 3, 0]);
this._pixiObject = new PIXI.Mesh(geometry, shader);
this._pixiObject.blendMode = PIXI.BLEND_MODES.ADD;
this._pixiObject = new PIXI.Container();
this._pixiObject.addChild(lightIconSprite);
this._pixiObject.addChild(radiusGraphics);
this._pixiContainer.addChild(this._pixiObject);
this.update();
}
@@ -380,37 +337,22 @@ module.exports = {
* This is called to update the PIXI object on the scene editor
*/
RenderedLightObjectInstance.prototype.update = function () {
this._pixiObject.shader.uniforms.center = new Float32Array([
this._instance.getX(),
this._instance.getY(),
]);
this._vertexBuffer[0] = this._instance.getX() - this._radius;
this._vertexBuffer[1] = this._instance.getY() + this._radius;
this._vertexBuffer[2] = this._instance.getX() + this._radius;
this._vertexBuffer[3] = this._instance.getY() + this._radius;
this._vertexBuffer[4] = this._instance.getX() + this._radius;
this._vertexBuffer[5] = this._instance.getY() - this._radius;
this._vertexBuffer[6] = this._instance.getX() - this._radius;
this._vertexBuffer[7] = this._instance.getY() - this._radius;
this._pixiObject.geometry
.getBuffer('aVertexPosition')
.update(this._vertexBuffer);
this._pixiObject.position.x = this._instance.getX();
this._pixiObject.position.y = this._instance.getY();
};
/**
* Return the width of the instance, when it's not resized.
*/
RenderedLightObjectInstance.prototype.getDefaultWidth = function () {
return this._pixiObject.width;
return this._radius * 2;
};
/**
* Return the height of the instance, when it's not resized.
*/
RenderedLightObjectInstance.prototype.getDefaultHeight = function () {
return this._pixiObject.height;
return this._radius * 2;
};
RenderedLightObjectInstance.prototype.getOriginX = function () {

View File

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

View File

@@ -26,23 +26,18 @@ class LinkedObjectsJsExtension : public gd::PlatformExtension {
DeclareLinkedObjectsExtension(*this);
GetAllActions()["LinkedObjects::LinkObjects"]
.codeExtraInformation
.SetIncludeFile("Extensions/LinkedObjects/linkedobjects.js")
.SetFunctionName("gdjs.evtTools.linkedObjects.linkObjects");
GetAllActions()["LinkedObjects::RemoveLinkBetween"]
.codeExtraInformation
.SetIncludeFile("Extensions/LinkedObjects/linkedobjects.js")
.SetFunctionName("gdjs.evtTools.linkedObjects.removeLinkBetween");
GetAllActions()["LinkedObjects::RemoveAllLinksOf"]
.codeExtraInformation
.SetIncludeFile("Extensions/LinkedObjects/linkedobjects.js")
.SetFunctionName("gdjs.evtTools.linkedObjects.removeAllLinksOf");
GetAllActions()["LinkedObjects::PickObjectsLinkedTo"]
.codeExtraInformation
.SetIncludeFile("Extensions/LinkedObjects/linkedobjects.js")
.SetFunctionName("gdjs.evtTools.linkedObjects.pickObjectsLinkedTo");
GetAllConditions()["LinkedObjects::PickObjectsLinkedTo"]
.codeExtraInformation
.SetIncludeFile("Extensions/LinkedObjects/linkedobjects.js")
.SetFunctionName("gdjs.evtTools.linkedObjects.pickObjectsLinkedTo");

View File

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

View File

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

View File

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

View File

@@ -758,7 +758,7 @@ module.exports = {
aut
.addAction(
'SetSleepingaAllowed',
'SetSleepingAllowed',
_('Sleeping allowed'),
_(
'Allow or not an object to sleep. If enabled the object will be able to sleep, improving performance for non-currently-moving objects.'
@@ -774,6 +774,11 @@ module.exports = {
.setDefaultValue('true')
.getCodeExtraInformation()
.setFunctionName('setSleepingAllowed');
// Deprecated action (fixed typo):
aut
.addDuplicatedAction("SetSleepingaAllowed", "SetSleepingAllowed")
.setHidden();
aut
.addCondition(

View File

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

View File

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

View File

@@ -140,7 +140,7 @@ namespace gdjs {
} else if (behaviorData.platformType === 'Jumpthru') {
this._platformType = PlatformRuntimeBehavior.JUMPTHRU;
} else {
this._platformType = PlatformRuntimeBehavior.NORMALPLAFTORM;
this._platformType = PlatformRuntimeBehavior.NORMALPLATFORM;
}
this._canBeGrabbed = behaviorData.canBeGrabbed || false;
this._yGrabOffset = behaviorData.yGrabOffset || 0;
@@ -232,7 +232,7 @@ namespace gdjs {
} else if (platformType === 'Jumpthru') {
this._platformType = PlatformRuntimeBehavior.JUMPTHRU;
} else {
this._platformType = PlatformRuntimeBehavior.NORMALPLAFTORM;
this._platformType = PlatformRuntimeBehavior.NORMALPLATFORM;
}
}
@@ -248,7 +248,9 @@ namespace gdjs {
return this._yGrabOffset;
}
static NORMALPLAFTORM = 0;
static NORMALPLATFORM = 0;
/** @deprecated Use NORMALPLATFORM instead. */
static NORMALPLAFTORM = PlatformRuntimeBehavior.NORMALPLATFORM;
static JUMPTHRU = 1;
static LADDER = 2;

View File

@@ -598,8 +598,8 @@ namespace gdjs {
break;
}
case 'connectionId': {
const messagegeData = messageContent.data;
const connectionId = messagegeData.connectionId;
const messageData = messageContent.data;
const connectionId = messageData.connectionId;
if (!connectionId) {
logger.error('No connectionId received');
return;

View File

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

View File

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

View File

@@ -81,12 +81,10 @@ class ShopifyJsExtension : public gd::PlatformExtension {
DeclareShopifyExtension(*this);
GetAllActions()["Shopify::BuildClient"]
.codeExtraInformation
.SetIncludeFile("Extensions/Shopify/shopify-buy.umd.polyfilled.min.js")
.AddIncludeFile("Extensions/Shopify/shopifytools.js")
.SetFunctionName("gdjs.evtTools.shopify.buildClient");
GetAllActions()["Shopify::GetCheckoutUrlForProduct"]
.codeExtraInformation
.SetIncludeFile("Extensions/Shopify/shopify-buy.umd.polyfilled.min.js")
.AddIncludeFile("Extensions/Shopify/shopifytools.js")
.SetFunctionName("gdjs.evtTools.shopify.getCheckoutUrlForProduct");

View File

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

View File

@@ -25,27 +25,21 @@ class SystemInfoJsExtension : public gd::PlatformExtension {
DeclareSystemInfoExtension(*this);
GetAllConditions()["SystemInfo::IsMobile"]
.codeExtraInformation
.SetIncludeFile("Extensions/SystemInfo/systeminfotools.js")
.SetFunctionName("gdjs.evtTools.systemInfo.isMobile");
GetAllConditions()["SystemInfo::IsNativeMobileApp"]
.codeExtraInformation
.SetIncludeFile("Extensions/SystemInfo/systeminfotools.js")
.SetFunctionName("gdjs.evtTools.systemInfo.isNativeMobileApp");
GetAllConditions()["SystemInfo::IsNativeDesktopApp"]
.codeExtraInformation
.SetIncludeFile("Extensions/SystemInfo/systeminfotools.js")
.SetFunctionName("gdjs.evtTools.systemInfo.isNativeDesktopApp");
GetAllConditions()["SystemInfo::IsWebGLSupported"]
.codeExtraInformation
.SetIncludeFile("Extensions/SystemInfo/systeminfotools.js")
.SetFunctionName("gdjs.evtTools.systemInfo.isWebGLSupported");
GetAllConditions()["SystemInfo::IsPreview"]
.codeExtraInformation
.SetIncludeFile("Extensions/SystemInfo/systeminfotools.js")
.SetFunctionName("gdjs.evtTools.systemInfo.isPreview");
GetAllConditions()["SystemInfo::HasTouchScreen"]
.codeExtraInformation
.SetIncludeFile("Extensions/SystemInfo/systeminfotools.js")
.SetFunctionName("gdjs.evtTools.systemInfo.hasTouchScreen");

View File

@@ -5,47 +5,7 @@
namespace gdjs {
export namespace evtTools {
export namespace systemInfo {
let cachedIsMobile: boolean | null = null;
let cachedHasTouchScreen: boolean | null = null;
const checkIsMobile = (): boolean => {
if (typeof cc !== 'undefined' && cc.sys) {
return cc.sys.isMobile;
}
// @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'Cocoon'.
else if (typeof Cocoon !== 'undefined' && Cocoon.App) {
return true;
} else if (typeof window !== 'undefined' && (window as any).cordova) {
return true;
} else if (typeof window !== 'undefined') {
// Try to detect mobile device browsers.
if (
/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(
navigator.userAgent
) ||
/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(
navigator.userAgent.substr(0, 4)
)
) {
return true;
}
// Try to detect iOS
if (/iPad|iPhone|iPod/.test(navigator.platform)) {
return true;
} else {
if (/MacIntel/.test(navigator.platform)) {
// Work around for recent iPads that are "desktop-class browsing".
// We can still detect them using their touchscreen, but this is a hack.
// If mac laptops start to support touchscreens, this won't work anymore. Hence it's better
// to test for the presence of a touchscreen if needed rather than checking if the device
// is "mobile".
return !!navigator.maxTouchPoints && navigator.maxTouchPoints > 2;
}
}
}
return false;
};
/**
* Check if the game runs on a mobile device (iPhone, iPad, Android).
@@ -54,10 +14,7 @@ namespace gdjs {
* prefer to check if the device has touchscreen support.
*/
export const isMobile = (): boolean => {
if (cachedIsMobile !== null) {
return cachedIsMobile;
}
return (cachedIsMobile = checkIsMobile());
return gdjs.evtTools.common.isMobile();
};
/**

View File

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

View File

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

View File

@@ -387,7 +387,7 @@ const defineTileMap = function (
)
.addParameter('object', _('Tile map'), 'TileMap', false)
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
.setFunctionName('getLevelndex');
.setFunctionName('getLevelIndex');
object
.addCondition(
@@ -1531,7 +1531,7 @@ module.exports = {
this._loadTiledMapWithCallback.bind(this),
tilemapJsonFile,
tilesetJsonFile,
0, // leveIndex
0, // levelIndex
pako,
(tileMap) => {
if (!tileMap) {

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

@@ -1,75 +1,88 @@
cmake_minimum_required(VERSION 2.6)
cmake_policy(SET CMP0015 NEW)
cmake_minimum_required(VERSION 3.5)
project(GDJS)
#Dependencies on external libraries:
###
# Dependencies on external libraries:
#
include_directories(${GDCORE_include_dir})
#Defines
###
add_definitions( -DGD_IDE_ONLY )
IF (EMSCRIPTEN)
add_definitions( -DEMSCRIPTEN )
ENDIF()
IF(CMAKE_BUILD_TYPE MATCHES "Debug")
add_definitions( -DDEBUG )
ELSE()
add_definitions( -DRELEASE )
ENDIF()
# Defines
#
add_definitions(-DGD_IDE_ONLY)
if(EMSCRIPTEN)
add_definitions(-DEMSCRIPTEN)
endif()
if("${CMAKE_BUILD_TYPE}" MATCHES "Debug")
add_definitions(-DDEBUG)
else()
add_definitions(-DRELEASE)
endif()
IF(WIN32)
add_definitions( -DWINDOWS )
add_definitions( "-DGD_API=__declspec(dllexport)" )
add_definitions( "-DGD_CORE_API=__declspec( dllimport )" )
add_definitions( -D__GNUWIN32__ )
ELSE()
IF(APPLE)
add_definitions( -DMACOS )
ELSE()
add_definitions( -DLINUX )
ENDIF()
add_definitions( -DGD_API= )
add_definitions( -DGD_CORE_API= )
ENDIF(WIN32)
if(WIN32)
add_definitions(-DWINDOWS)
add_definitions("-DGD_API=__declspec(dllexport)")
add_definitions("-DGD_CORE_API=__declspec(dllimport)")
add_definitions(-D__GNUWIN32__)
else()
if(APPLE)
add_definitions(-DMACOS)
else()
add_definitions(-DLINUX)
endif()
add_definitions(-DGD_API=)
add_definitions(-DGD_CORE_API=)
endif()
#The target
###
# The target
#
include_directories(.)
file(GLOB f1 GDJS/* GDJS/IDE/* GDJS/IDE/mongoose/*)
file(GLOB_RECURSE f2 GDJS/Extensions/* GDJS/Events/*)
file(
GLOB
f1
GDJS/*
GDJS/IDE/*
GDJS/IDE/mongoose/*)
file(
GLOB_RECURSE
f2
GDJS/Extensions/*
GDJS/Events/*)
set(source_files ${f1} ${f2})
IF(NOT EMSCRIPTEN)
file(GLOB_RECURSE f3 GDJS/IDE/Dialogs/*)
set(source_files ${source_files} ${f3})
ENDIF()
if(NOT EMSCRIPTEN)
file(
GLOB_RECURSE
f3
GDJS/IDE/Dialogs/*)
set(source_files ${source_files} ${f3})
endif()
file(GLOB_RECURSE formatted_source_files GDJS/Events/* GDJS/Extensions/* GDJS/IDE/*)
file(
GLOB_RECURSE
formatted_source_files
GDJS/Events/*
GDJS/Extensions/*
GDJS/IDE/*)
gd_add_clang_utils(GDJS "${formatted_source_files}")
IF(EMSCRIPTEN)
if(EMSCRIPTEN)
# Emscripten treats all libraries as static libraries
add_library(GDJS STATIC ${source_files})
ELSE()
else()
add_library(GDJS SHARED ${source_files})
ENDIF()
IF(EMSCRIPTEN)
endif()
if(EMSCRIPTEN)
set_target_properties(GDJS PROPERTIES SUFFIX ".bc")
ELSEIF(WIN32)
elseif(WIN32)
set_target_properties(GDJS PROPERTIES PREFIX "")
ELSE()
else()
set_target_properties(GDJS PROPERTIES PREFIX "lib")
ENDIF()
endif()
set_target_properties(GDJS PROPERTIES MACOS_RPATH "..")
set(LIBRARY_OUTPUT_PATH ${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME}/JsPlatform)
set(ARCHIVE_OUTPUT_PATH ${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME}/JsPlatform)
set(RUNTIME_OUTPUT_PATH ${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME}/JsPlatform)
#Linker files
###
IF(EMSCRIPTEN)
#Nothing.
ELSE()
# Linker files
#
if(NOT EMSCRIPTEN)
target_link_libraries(GDJS GDCore)
ENDIF()
endif()

View File

@@ -684,15 +684,15 @@ gd::String EventsCodeGenerator::GenerateFreeCondition(
bool conditionInverted,
gd::EventsCodeGenerationContext& context) {
// Generate call
gd::String predicat;
gd::String predicate;
if (instrInfos.codeExtraInformation.type == "number" ||
instrInfos.codeExtraInformation.type == "string") {
predicat = GenerateRelationalOperatorCall(
predicate = GenerateRelationalOperatorCall(
instrInfos,
arguments,
instrInfos.codeExtraInformation.functionCallName);
} else {
predicat = instrInfos.codeExtraInformation.functionCallName + "(" +
predicate = instrInfos.codeExtraInformation.functionCallName + "(" +
GenerateArgumentsList(arguments) + ")";
}
@@ -705,11 +705,11 @@ gd::String EventsCodeGenerator::GenerateFreeCondition(
conditionAlreadyTakeCareOfInversion = true;
}
if (!conditionAlreadyTakeCareOfInversion && conditionInverted)
predicat = GenerateNegatedPredicat(predicat);
predicate = GenerateNegatedPredicate(predicate);
// Generate condition code
return GenerateBooleanFullName(returnBoolean, context) +
" = " + predicat + ";\n";
" = " + predicate + ";\n";
}
gd::String EventsCodeGenerator::GenerateObjectCondition(
@@ -728,22 +728,22 @@ gd::String EventsCodeGenerator::GenerateObjectCondition(
instrInfos.codeExtraInformation.functionCallName;
// Create call
gd::String predicat;
gd::String predicate;
if ((instrInfos.codeExtraInformation.type == "number" ||
instrInfos.codeExtraInformation.type == "string")) {
predicat = GenerateRelationalOperatorCall(
predicate = GenerateRelationalOperatorCall(
instrInfos, arguments, objectFunctionCallNamePart, 1);
} else {
predicat = objectFunctionCallNamePart + "(" +
predicate = objectFunctionCallNamePart + "(" +
GenerateArgumentsList(arguments, 1) + ")";
}
if (conditionInverted) predicat = GenerateNegatedPredicat(predicat);
if (conditionInverted) predicate = GenerateNegatedPredicate(predicate);
// Generate whole condition code
conditionCode +=
"for (var i = 0, k = 0, l = " + GetObjectListName(objectName, context) +
".length;i<l;++i) {\n";
conditionCode += " if ( " + predicat + " ) {\n";
conditionCode += " if ( " + predicate + " ) {\n";
conditionCode += " " +
GenerateBooleanFullName(returnBoolean, context) +
" = true;\n";
@@ -775,16 +775,16 @@ gd::String EventsCodeGenerator::GenerateBehaviorCondition(
instrInfos.codeExtraInformation.functionCallName;
// Create call
gd::String predicat;
gd::String predicate;
if ((instrInfos.codeExtraInformation.type == "number" ||
instrInfos.codeExtraInformation.type == "string")) {
predicat = GenerateRelationalOperatorCall(
predicate = GenerateRelationalOperatorCall(
instrInfos, arguments, objectFunctionCallNamePart, 2);
} else {
predicat = objectFunctionCallNamePart + "(" +
predicate = objectFunctionCallNamePart + "(" +
GenerateArgumentsList(arguments, 2) + ")";
}
if (conditionInverted) predicat = GenerateNegatedPredicat(predicat);
if (conditionInverted) predicate = GenerateNegatedPredicate(predicate);
// Verify that object has behavior.
vector<gd::String> behaviors = gd::GetBehaviorsOfObject(
@@ -798,7 +798,7 @@ gd::String EventsCodeGenerator::GenerateBehaviorCondition(
conditionCode +=
"for (var i = 0, k = 0, l = " + GetObjectListName(objectName, context) +
".length;i<l;++i) {\n";
conditionCode += " if ( " + predicat + " ) {\n";
conditionCode += " if ( " + predicate + " ) {\n";
conditionCode += " " +
GenerateBooleanFullName(returnBoolean, context) +
" = true;\n";

View File

@@ -319,8 +319,8 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
const gd::String& type,
gd::EventsCodeGenerationContext& context);
virtual gd::String GenerateNegatedPredicat(const gd::String& predicat) const {
return "!(" + predicat + ")";
virtual gd::String GenerateNegatedPredicate(const gd::String& predicate) const {
return "!(" + predicate + ")";
};
virtual gd::String GenerateObjectsDeclarationCode(

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,324 @@
/*
* GDevelop Core
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include "GDCore/String.h"
#include <functional>
#include <map>
#include <memory>
#include <vector>
namespace gd {
class PlatformExtension;
class Project;
class EventsFunctionsExtension;
class EventsBasedBehavior;
class BehaviorMetadata;
class EventsBasedObject;
class ObjectMetadata;
class EventsFunction;
class PropertyDescriptor;
class EventsFunctionsContainer;
class AbstractFunctionMetadata;
class InstructionOrExpressionContainerMetadata;
class AbstractEventsBasedEntity;
class NamedPropertyDescriptor;
class ParameterMetadata;
class InstructionMetadata;
class ExpressionMetadata;
class MultipleInstructionMetadata;
} // namespace gd
namespace gdjs {
/**
* \brief This file contains the logic to declare extension metadata from
* events functions or events based behaviors.
* These are basically adapters from gd::EventsFunctionsExtension, and children,
* to a real extension declaration (like in `JsExtension.js` or `Extension.cpp`
* files).
*
* \ingroup IDE
*/
class MetadataDeclarationHelper {
public:
MetadataDeclarationHelper(){};
virtual ~MetadataDeclarationHelper(){};
gd::AbstractFunctionMetadata &GenerateFreeFunctionMetadata(
const gd::Project &project, gd::PlatformExtension &extension,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsFunction &eventsFunction);
static gd::BehaviorMetadata &GenerateBehaviorMetadata(
const gd::Project &project, gd::PlatformExtension &extension,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsBasedBehavior &eventsBasedBehavior,
std::map<gd::String, gd::String> &behaviorMethodMangledNames);
static gd::ObjectMetadata &GenerateObjectMetadata(
const gd::Project &project, gd::PlatformExtension &extension,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsBasedObject &eventsBasedObject,
std::map<gd::String, gd::String> &objectMethodMangledNames);
static gd::String GetFreeFunctionCodeName(
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsFunction &eventsFunction);
/**
* Declare an extension from an events based extension.
*/
static void DeclareExtension(
gd::PlatformExtension &extension,
const gd::EventsFunctionsExtension &eventsFunctionsExtension);
/**
* Check if the name of the function is the name of a lifecycle function (for
* events-based behaviors), that will be called automatically by the game
* engine.
*/
static bool IsBehaviorLifecycleEventsFunction(const gd::String &functionName);
/**
* Check if the name of the function is the name of a lifecycle function (for
* events-based objects), that will be called automatically by the game
* engine.
*/
static bool IsObjectLifecycleEventsFunction(const gd::String &functionName);
/**
* Check if the name of the function is the name of a lifecycle function (for
* events-based extensions), that will be called automatically by the game
* engine.
*/
static bool
IsExtensionLifecycleEventsFunction(const gd::String &functionName);
static gd::String ShiftSentenceParamIndexes(const gd::String &sentence,
const int offset);
private:
static const gd::String &
GetExtensionIconUrl(gd::PlatformExtension &extension);
/**
* Declare the dependencies of an extension from an events based extension.
*/
static void DeclareExtensionDependencies(
gd::PlatformExtension &extension,
const gd::EventsFunctionsExtension &eventsFunctionsExtension);
static void DeclarePropertyInstructionAndExpression(
gd::PlatformExtension &extension,
gd::InstructionOrExpressionContainerMetadata &entityMetadata,
const gd::AbstractEventsBasedEntity &eventsBasedEntity,
const gd::NamedPropertyDescriptor &property,
const gd::String &propertyLabel, const gd::String &expressionName,
const gd::String &conditionName, const gd::String &actionName,
const gd::String &toggleActionName, const gd::String &setterName,
const gd::String &getterName, const gd::String &toggleFunctionName,
const int valueParameterIndex,
std::function<gd::AbstractFunctionMetadata &(
gd::AbstractFunctionMetadata &instructionOrExpression)>
addObjectAndBehaviorParameters);
/**
* Declare the instructions (actions/conditions) and expressions for the
* properties of the given events based behavior.
* This is akin to what would happen by manually declaring a JS extension
* (see `JsExtension.js` files of extensions).
*/
static void DeclareBehaviorPropertiesInstructionAndExpressions(
gd::PlatformExtension &extension, gd::BehaviorMetadata &behaviorMetadata,
const gd::EventsBasedBehavior &eventsBasedBehavior);
/**
* Declare the instructions (actions/conditions) and expressions for the
* properties of the given events based object.
* This is akin to what would happen by manually declaring a JS extension
* (see `JsExtension.js` files of extensions).
*/
static void DeclareObjectPropertiesInstructionAndExpressions(
gd::PlatformExtension &extension, gd::ObjectMetadata &objectMetadata,
const gd::EventsBasedObject &eventsBasedObject);
/**
* Declare the instructions (actions/conditions) and expressions for the
* properties of the given events based object.
* This is akin to what would happen by manually declaring a JS extension
* (see `JsExtension.js` files of extensions).
*/
static void DeclareObjectInternalInstructions(
gd::PlatformExtension &extension, gd::ObjectMetadata &objectMetadata,
const gd::EventsBasedObject &eventsBasedObject);
static const gd::String defaultExtensionIconPath;
/**
* Declare the behavior for the given
* events based behavior.
*/
static gd::BehaviorMetadata &
DeclareBehaviorMetadata(gd::PlatformExtension &extension,
const gd::EventsBasedBehavior &eventsBasedBehavior);
/**
* Declare the object for the given
* events based object.
*/
static gd::ObjectMetadata &
DeclareObjectMetadata(gd::PlatformExtension &extension,
const gd::EventsBasedObject &eventsBasedObject);
static void
AddParameter(gd::AbstractFunctionMetadata &instructionOrExpression,
const gd::ParameterMetadata &parameter);
/**
* Declare the instruction (action/condition) or expression for the given
* (free) events function.
*/
gd::AbstractFunctionMetadata &DeclareInstructionOrExpressionMetadata(
gd::PlatformExtension &extension,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsFunction &eventsFunction);
/**
* Declare the instruction (action/condition) or expression for the given
* (free) events function.
*/
gd::AbstractFunctionMetadata &DeclareExpressionMetadata(
gd::PlatformExtension &extension,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsFunction &eventsFunction);
/**
* Declare the instruction (action/condition) or expression for the given
* (free) events function.
*/
static gd::InstructionMetadata &DeclareInstructionMetadata(
gd::PlatformExtension &extension,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsFunction &eventsFunction);
/**
* Declare the instruction (action/condition) or expression for the given
* behavior events function.
*/
gd::AbstractFunctionMetadata &DeclareBehaviorInstructionOrExpressionMetadata(
gd::PlatformExtension &extension, gd::BehaviorMetadata &behaviorMetadata,
const gd::EventsBasedBehavior &eventsBasedBehavior,
const gd::EventsFunction &eventsFunction,
std::map<gd::String, gd::String> &objectMethodMangledNames);
/**
* Declare the instruction (action/condition) or expression for the given
* behavior events function.
*/
gd::AbstractFunctionMetadata &DeclareBehaviorExpressionMetadata(
gd::PlatformExtension &extension, gd::BehaviorMetadata &behaviorMetadata,
const gd::EventsBasedBehavior &eventsBasedBehavior,
const gd::EventsFunction &eventsFunction);
/**
* Declare the instruction (action/condition) or expression for the given
* behavior events function.
*/
static gd::InstructionMetadata &DeclareBehaviorInstructionMetadata(
gd::PlatformExtension &extension, gd::BehaviorMetadata &behaviorMetadata,
const gd::EventsBasedBehavior &eventsBasedBehavior,
const gd::EventsFunction &eventsFunction);
/**
* Declare the instruction (action/condition) or expression for the given
* object events function.
*/
gd::AbstractFunctionMetadata &DeclareObjectInstructionOrExpressionMetadata(
gd::PlatformExtension &extension, gd::ObjectMetadata &objectMetadata,
const gd::EventsBasedObject &eventsBasedObject,
const gd::EventsFunction &eventsFunction,
std::map<gd::String, gd::String> &objectMethodMangledNames);
/**
* Declare the instruction (action/condition) or expression for the given
* object events function.
*/
gd::AbstractFunctionMetadata &DeclareObjectExpressionMetadata(
gd::PlatformExtension &extension, gd::ObjectMetadata &objectMetadata,
const gd::EventsBasedObject &eventsBasedObject,
const gd::EventsFunction &eventsFunction);
/**
* Declare the instruction (action/condition) or expression for the given
* object events function.
*/
static gd::InstructionMetadata &DeclareObjectInstructionMetadata(
gd::PlatformExtension &extension, gd::ObjectMetadata &objectMetadata,
const gd::EventsBasedObject &eventsBasedObject,
const gd::EventsFunction &eventsFunction);
/**
* Add to the instruction (action/condition) or expression the parameters
* expected by the events function.
*/
static void DeclareEventsFunctionParameters(
const gd::EventsFunctionsContainer &eventsFunctionsContainer,
const gd::EventsFunction &eventsFunction,
gd::ExpressionMetadata &expression,
const int userDefinedFirstParameterIndex);
/**
* Add to the instruction (action/condition) or expression the parameters
* expected by the events function.
*/
static void DeclareEventsFunctionParameters(
const gd::EventsFunctionsContainer &eventsFunctionsContainer,
const gd::EventsFunction &eventsFunction,
gd::InstructionMetadata &instruction,
const int userDefinedFirstParameterIndex);
/**
* Add to the instruction (action/condition) or expression the parameters
* expected by the events function.
*/
static void DeclareEventsFunctionParameters(
const gd::EventsFunctionsContainer &eventsFunctionsContainer,
const gd::EventsFunction &eventsFunction,
gd::MultipleInstructionMetadata &multipleInstructionMetadata,
const int userDefinedFirstParameterIndex);
static gd::String GetExtensionCodeNamespacePrefix(
const gd::EventsFunctionsExtension eventsFunctionsExtension);
/** Generate the namespace for a free function. */
static gd::String
GetFreeFunctionCodeNamespace(const gd::EventsFunction &eventsFunction,
const gd::String &codeNamespacePrefix);
/** Generate the namespace for a behavior function. */
static gd::String GetBehaviorFunctionCodeNamespace(
const gd::EventsBasedBehavior &eventsBasedBehavior,
const gd::String &codeNamespacePrefix);
/** Generate the namespace for an object function. */
static gd::String
GetObjectFunctionCodeNamespace(const gd::EventsBasedObject &eventsBasedObject,
const gd::String &codeNamespacePrefix);
static gd::String RemoveTrailingDot(const gd::String &description);
static gd::String
GetStringifiedExtraInfo(const gd::PropertyDescriptor &property);
static gd::String CapitalizeFirstLetter(const gd::String &string);
static gd::String UncapitalizeFirstLetter(const gd::String &string);
std::vector<gd::MultipleInstructionMetadata> expressionAndConditions;
};
} // namespace gdjs

View File

@@ -18,7 +18,6 @@ AdvancedExtension::AdvancedExtension() {
gd::BuiltinExtensionsImplementer::ImplementsAdvancedExtension(*this);
GetAllActions()["SetReturnNumber"]
.GetCodeExtraInformation()
.SetCustomCodeGenerator([](gd::Instruction& instruction,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context) {
@@ -35,7 +34,6 @@ AdvancedExtension::AdvancedExtension() {
});
GetAllActions()["SetReturnString"]
.GetCodeExtraInformation()
.SetCustomCodeGenerator([](gd::Instruction& instruction,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context) {
@@ -52,7 +50,6 @@ AdvancedExtension::AdvancedExtension() {
});
GetAllActions()["SetReturnBoolean"]
.GetCodeExtraInformation()
.SetCustomCodeGenerator([](gd::Instruction& instruction,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context) {
@@ -67,7 +64,6 @@ AdvancedExtension::AdvancedExtension() {
});
GetAllActions()["CopyArgumentToVariable"]
.GetCodeExtraInformation()
.SetCustomCodeGenerator([](gd::Instruction &instruction,
gd::EventsCodeGenerator &codeGenerator,
gd::EventsCodeGenerationContext &context) {
@@ -86,7 +82,6 @@ AdvancedExtension::AdvancedExtension() {
});
GetAllActions()["CopyVariableToArgument"]
.GetCodeExtraInformation()
.SetCustomCodeGenerator([](gd::Instruction &instruction,
gd::EventsCodeGenerator &codeGenerator,
gd::EventsCodeGenerationContext &context) {
@@ -105,7 +100,6 @@ AdvancedExtension::AdvancedExtension() {
});
GetAllConditions()["GetArgumentAsBoolean"]
.GetCodeExtraInformation()
.SetCustomCodeGenerator([](gd::Instruction& instruction,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context) {
@@ -161,7 +155,6 @@ AdvancedExtension::AdvancedExtension() {
});
GetAllConditions()["CompareArgumentAsNumber"]
.GetCodeExtraInformation()
.SetCustomCodeGenerator([](gd::Instruction &instruction,
gd::EventsCodeGenerator &codeGenerator,
gd::EventsCodeGenerationContext &context) {
@@ -188,7 +181,6 @@ AdvancedExtension::AdvancedExtension() {
});
GetAllConditions()["CompareArgumentAsString"]
.GetCodeExtraInformation()
.SetCustomCodeGenerator([](gd::Instruction &instruction,
gd::EventsCodeGenerator &codeGenerator,
gd::EventsCodeGenerationContext &context) {

View File

@@ -138,12 +138,10 @@ BaseObjectExtension::BaseObjectExtension() {
objectActions["SeparateFromObjects"]
.SetFunctionName("separateFromObjectsList")
.SetIncludeFile("runtimeobject.js");
objectActions["Ecarter"]
.codeExtraInformation // Deprecated
objectActions["Ecarter"] // Deprecated
.SetFunctionName("separateObjectsWithoutForces")
.SetIncludeFile("runtimeobject.js");
objectActions["Rebondir"]
.codeExtraInformation // Deprecated
objectActions["Rebondir"] // Deprecated
.SetFunctionName("separateObjectsWithForces")
.SetIncludeFile("runtimeobject.js");
objectConditions["BehaviorActivated"]
@@ -354,7 +352,7 @@ BaseObjectExtension::BaseObjectExtension() {
.SetFunctionName("getVariableChildCount")
.SetIncludeFile("runtimeobject.js");
GetAllActions()["MoveObjects"].codeExtraInformation.SetCustomCodeGenerator(
GetAllActions()["MoveObjects"].SetCustomCodeGenerator(
[](gd::Instruction &,
gd::EventsCodeGenerator &,
gd::EventsCodeGenerationContext &) {
@@ -365,7 +363,7 @@ BaseObjectExtension::BaseObjectExtension() {
return op == "/" || op == "*" || op == "-" || op == "+";
};
objectActions["MettreXY"].codeExtraInformation.SetCustomCodeGenerator(
objectActions["MettreXY"].SetCustomCodeGenerator(
[&](gd::Instruction &instruction,
gd::EventsCodeGenerator &codeGenerator,
gd::EventsCodeGenerationContext &context) -> gd::String {
@@ -397,16 +395,16 @@ BaseObjectExtension::BaseObjectExtension() {
instruction.GetParameter(0).GetPlainString());
gd::String op1 = instruction.GetParameter(1).GetPlainString();
gd::String newX =
isNotAssignmentOperator(op1)
? (objectListName + "[i].getX() " + op1 + expression1Code)
: expression1Code;
gd::String newX = isNotAssignmentOperator(op1)
? (objectListName + "[i].getX() " + op1 + "(" +
expression1Code + ")")
: expression1Code;
gd::String op2 = instruction.GetParameter(3).GetPlainString();
gd::String newY =
isNotAssignmentOperator(op2)
? (objectListName + "[i].getY() " + op2 + expression2Code)
: expression2Code;
gd::String newY = isNotAssignmentOperator(op2)
? (objectListName + "[i].getY() " + op2 + "(" +
expression2Code + ")")
: expression2Code;
gd::String call =
objectListName + "[i].setPosition(" + newX + "," + newY + ")";
@@ -422,7 +420,7 @@ BaseObjectExtension::BaseObjectExtension() {
return outputCode;
});
objectActions["SetCenter"].codeExtraInformation.SetCustomCodeGenerator(
objectActions["SetCenter"].SetCustomCodeGenerator(
[&](gd::Instruction &instruction,
gd::EventsCodeGenerator &codeGenerator,
gd::EventsCodeGenerationContext &context) -> gd::String {

View File

@@ -46,7 +46,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
GetAllConditions()["BuiltinCommonInstructions::Always"].SetFunctionName(
"gdjs.evtTools.common.logicalNegation");
GetAllConditions()["Egal"].codeExtraInformation.SetCustomCodeGenerator(
GetAllConditions()["Egal"].SetCustomCodeGenerator(
[](gd::Instruction& instruction,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context) {
@@ -76,7 +76,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
GetAllConditions()["BuiltinCommonInstructions::CompareNumbers"]
.codeExtraInformation = GetAllConditions()["Egal"].codeExtraInformation;
GetAllConditions()["StrEqual"].codeExtraInformation.SetCustomCodeGenerator(
GetAllConditions()["StrEqual"].SetCustomCodeGenerator(
[](gd::Instruction& instruction,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context) {
@@ -133,7 +133,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
gd::String conditionsCode = codeGenerator.GenerateConditionsListCode(
event.GetConditions(), context);
gd::String ifPredicat =
gd::String ifPredicate =
event.GetConditions().empty()
? ""
: codeGenerator.GenerateBooleanFullName(
@@ -156,7 +156,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
gd::String outputCode;
outputCode += conditionsCode;
if (!ifPredicat.empty()) outputCode += "if (" + ifPredicat + ") ";
if (!ifPredicate.empty()) outputCode += "if (" + ifPredicate + ") ";
outputCode += "{\n";
outputCode += actionsDeclarationsCode;
outputCode += actionsCode;
@@ -176,7 +176,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
});
GetAllConditions()["BuiltinCommonInstructions::Or"]
.codeExtraInformation.SetCustomCodeGenerator(
.SetCustomCodeGenerator(
[](gd::Instruction& instruction,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& parentContext) {
@@ -307,7 +307,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
});
GetAllConditions()["BuiltinCommonInstructions::And"]
.codeExtraInformation.SetCustomCodeGenerator(
.SetCustomCodeGenerator(
[](gd::Instruction& instruction,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& parentContext) {
@@ -327,7 +327,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
});
GetAllConditions()["BuiltinCommonInstructions::Not"]
.codeExtraInformation.SetCustomCodeGenerator(
.SetCustomCodeGenerator(
[](gd::Instruction &instruction,
gd::EventsCodeGenerator &codeGenerator,
gd::EventsCodeGenerationContext &parentContext) {
@@ -348,7 +348,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
});
GetAllConditions()["BuiltinCommonInstructions::Once"]
.codeExtraInformation.SetCustomCodeGenerator(
.SetCustomCodeGenerator(
[](gd::Instruction& instruction,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context) {
@@ -391,18 +391,18 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
gd::String whileConditionsStr =
codeGenerator.GenerateConditionsListCode(event.GetWhileConditions(),
context);
gd::String whileIfPredicat = "true";
gd::String whileIfPredicate = "true";
if (!event.GetWhileConditions().empty())
whileIfPredicat =
whileIfPredicate =
codeGenerator.GenerateBooleanFullName("isConditionTrue", context);
gd::String conditionsCode = codeGenerator.GenerateConditionsListCode(
event.GetConditions(), context);
gd::String actionsCode =
codeGenerator.GenerateActionsListCode(event.GetActions(), context);
gd::String ifPredicat = "true";
gd::String ifPredicate = "true";
if (!event.GetConditions().empty())
ifPredicat =
ifPredicate =
codeGenerator.GenerateBooleanFullName("isConditionTrue", context);
// Write final code
@@ -412,9 +412,9 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
outputCode += "do {\n";
outputCode += codeGenerator.GenerateObjectsDeclarationCode(context);
outputCode += whileConditionsStr;
outputCode += "if (" + whileIfPredicat + ") {\n";
outputCode += "if (" + whileIfPredicate + ") {\n";
outputCode += conditionsCode;
outputCode += "if (" + ifPredicat + ") {\n";
outputCode += "if (" + ifPredicate + ") {\n";
outputCode += actionsCode;
outputCode += "\n{ //Subevents: \n";
// TODO: check (and heavily test) if sub events should be generated before
@@ -448,7 +448,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
event.GetConditions(), context);
gd::String actionsCode =
codeGenerator.GenerateActionsListCode(event.GetActions(), context);
gd::String ifPredicat = event.GetConditions().empty()
gd::String ifPredicate = event.GetConditions().empty()
? "true"
: codeGenerator.GenerateBooleanFullName(
"isConditionTrue", context);
@@ -524,7 +524,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
// Now do the rest of standard event code generation
outputCode += objectDeclaration;
outputCode += conditionsCode;
outputCode += "if (" + ifPredicat + ")\n";
outputCode += "if (" + ifPredicate + ")\n";
outputCode += "{\n";
outputCode += actionsCode;
if (event.HasSubEvents()) {
@@ -613,9 +613,9 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
event.GetConditions(), context);
gd::String actionsCode =
codeGenerator.GenerateActionsListCode(event.GetActions(), context);
gd::String ifPredicat = "true";
gd::String ifPredicate = "true";
if (!event.GetConditions().empty())
ifPredicat =
ifPredicate =
codeGenerator.GenerateBooleanFullName("isConditionTrue", context);
// Prepare object declaration and sub events
@@ -634,7 +634,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
" < " + repeatCountVar + ";++" + repeatIndexVar + ") {\n";
outputCode += objectDeclaration;
outputCode += conditionsCode;
outputCode += "if (" + ifPredicat + ")\n";
outputCode += "if (" + ifPredicate + ")\n";
outputCode += "{\n";
outputCode += actionsCode;
if (event.HasSubEvents()) {
@@ -677,9 +677,9 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
event.GetConditions(), context);
gd::String actionsCode =
codeGenerator.GenerateActionsListCode(event.GetActions(), context);
gd::String ifPredicat = "true";
gd::String ifPredicate = "true";
if (!event.GetConditions().empty())
ifPredicat =
ifPredicate =
codeGenerator.GenerateBooleanFullName("isConditionTrue", context);
// Prepare object declaration and sub events
@@ -787,7 +787,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
}
outputCode += conditionsCode;
outputCode += "if (" + ifPredicat + ") {\n";
outputCode += "if (" + ifPredicate + ") {\n";
outputCode += actionsCode;
if (event.HasSubEvents()) {
outputCode += "\n{ //Subevents: \n";

View File

@@ -118,7 +118,7 @@ VariablesExtension::VariablesExtension() {
GetAllActions()["GlobalVariableRemoveAt"].SetFunctionName(
"gdjs.evtTools.variable.variableRemoveAt");
GetAllActions()["ModVarScene"].codeExtraInformation.SetCustomCodeGenerator(
GetAllActions()["ModVarScene"].SetCustomCodeGenerator(
[](gd::Instruction& instruction,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context) {
@@ -150,7 +150,7 @@ VariablesExtension::VariablesExtension() {
return gd::String("");
});
GetAllActions()["ModVarSceneTxt"].codeExtraInformation.SetCustomCodeGenerator(
GetAllActions()["ModVarSceneTxt"].SetCustomCodeGenerator(
[](gd::Instruction& instruction,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context) {
@@ -176,7 +176,7 @@ VariablesExtension::VariablesExtension() {
return gd::String("");
});
GetAllActions()["ModVarGlobal"].codeExtraInformation.SetCustomCodeGenerator(
GetAllActions()["ModVarGlobal"].SetCustomCodeGenerator(
[](gd::Instruction& instruction,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context) {
@@ -209,7 +209,7 @@ VariablesExtension::VariablesExtension() {
});
GetAllActions()["ModVarGlobalTxt"]
.codeExtraInformation.SetCustomCodeGenerator(
.SetCustomCodeGenerator(
[](gd::Instruction& instruction,
gd::EventsCodeGenerator& codeGenerator,
gd::EventsCodeGenerationContext& context) {

View File

@@ -686,6 +686,8 @@ void ExporterHelper::AddLibsInclude(bool pixiRenderers,
if (pixiInThreeRenderers) {
InsertUnique(includesFiles, "pixi-renderers/three.js");
InsertUnique(includesFiles, "pixi-renderers/ThreeAddons.js");
InsertUnique(includesFiles, "pixi-renderers/draco/gltf/draco_decoder.wasm");
InsertUnique(includesFiles, "pixi-renderers/draco/gltf/draco_wasm_wrapper.js");
}
if (pixiRenderers) {
InsertUnique(includesFiles, "pixi-renderers/pixi.js");

View File

@@ -16,14 +16,16 @@ namespace gdjs {
/**
* Map associating a resource name to the loaded Three.js model.
*/
private _loadedThreeModels = new Map<String, THREE.Object3D>();
private _loadedThreeModels = new Map<String, THREE_ADDONS.GLTF>();
_resourcesLoader: RuntimeGameResourcesLoader;
_resources: ResourceData[];
_loader: THREE_ADDONS.GLTFLoader | null = null;
_dracoLoader: THREE_ADDONS.DRACOLoader | null = null;
_invalidModel: THREE.Object3D | null = null;
//@ts-ignore Can only be null if THREE is not loaded.
_invalidModel: THREE_ADDONS.GLTF;
/**
* @param resources The resources data of the game.
@@ -39,13 +41,31 @@ namespace gdjs {
if (typeof THREE !== 'undefined') {
this._loader = new THREE_ADDONS.GLTFLoader();
this._dracoLoader = new THREE_ADDONS.DRACOLoader();
this._dracoLoader.setDecoderPath('./pixi-renderers/draco/gltf/');
this._loader.setDRACOLoader(this._dracoLoader);
/**
* The invalid model is a box with magenta (#ff00ff) faces, to be
* easily spotted if rendered on screen.
*/
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: '#ff00ff' });
this._invalidModel = new THREE.Mesh(geometry, material);
const group = new THREE.Group();
group.add(
new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshBasicMaterial({ color: '#ff00ff' })
)
);
this._invalidModel = {
scene: group,
animations: [],
cameras: [],
scenes: [],
asset: {},
userData: {},
//@ts-ignore
parser: null,
};
}
}
@@ -89,9 +109,8 @@ namespace gdjs {
);
this._loader.load(
url,
(gltf) => {
gltf.scene.rotation.order = 'ZYX';
this._loadedThreeModels.set(resource.name, gltf.scene);
(gltf: THREE_ADDONS.GLTF) => {
this._loadedThreeModels.set(resource.name, gltf);
loaded++;
if (loaded === model3DResources.length) {
@@ -123,7 +142,7 @@ namespace gdjs {
* @param resourceName The name of the json resource.
* @returns a 3D model if it exists.
*/
getModel(resourceName: string): THREE.Object3D | null {
getModel(resourceName: string): THREE_ADDONS.GLTF {
return this._loadedThreeModels.get(resourceName) || this._invalidModel;
}
}

View File

@@ -257,8 +257,19 @@ namespace gdjs {
newObject.persistentUuid = instanceData.persistentUuid || null;
}
newObject.setPosition(instanceData.x + xPos, instanceData.y + yPos);
newObject.setZOrder(instanceData.zOrder);
newObject.setAngle(instanceData.angle);
if (
gdjs.RuntimeObject3D &&
newObject instanceof gdjs.RuntimeObject3D
) {
if (instanceData.z !== undefined) newObject.setZ(instanceData.z);
if (instanceData.rotationX !== undefined)
newObject.setRotationX(instanceData.rotationX);
if (instanceData.rotationY !== undefined)
newObject.setRotationY(instanceData.rotationY);
}
newObject.setZOrder(instanceData.zOrder);
newObject.setLayer(instanceData.layer);
newObject
.getVariables()

View File

@@ -1252,6 +1252,29 @@ namespace gdjs {
runtimeObject.setLayer(newInstance.layer);
somethingChanged = true;
}
if (
gdjs.RuntimeObject3D &&
runtimeObject instanceof gdjs.RuntimeObject3D
) {
if (oldInstance.z !== newInstance.z && newInstance.z !== undefined) {
runtimeObject.setZ(newInstance.z);
somethingChanged = true;
}
if (
oldInstance.rotationX !== newInstance.rotationX &&
newInstance.rotationX !== undefined
) {
runtimeObject.setRotationX(newInstance.rotationX);
somethingChanged = true;
}
if (
oldInstance.rotationY !== newInstance.rotationY &&
newInstance.rotationY !== undefined
) {
runtimeObject.setRotationY(newInstance.rotationY);
somethingChanged = true;
}
}
// Check if size changed
let sizeChanged = false;
@@ -1283,6 +1306,28 @@ namespace gdjs {
sizeChanged = true;
}
}
if (
gdjs.RuntimeObject3D &&
runtimeObject instanceof gdjs.RuntimeObject3D
) {
// A custom depth was set or changed
if (
oldInstance.depth !== newInstance.depth &&
newInstance.depth !== undefined
) {
runtimeObject.setDepth(newInstance.depth);
somethingChanged = true;
sizeChanged = true;
} else if (
newInstance.depth === undefined &&
oldInstance.depth !== undefined
) {
// The custom depth was removed. Just flag the depth as changed
// and hope the object will handle this in
// `extraInitializationFromInitialInstance`.
sizeChanged = true;
}
}
// Update variables
this._hotReloadVariablesContainer(

View File

@@ -396,6 +396,60 @@ namespace gdjs {
)
eventsFunctionContext.task.resolve();
};
const checkIsMobile = (): boolean => {
if (typeof cc !== 'undefined' && cc.sys) {
return cc.sys.isMobile;
}
// @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'Cocoon'.
else if (typeof Cocoon !== 'undefined' && Cocoon.App) {
return true;
} else if (typeof window !== 'undefined' && (window as any).cordova) {
return true;
} else if (typeof window !== 'undefined') {
// Try to detect mobile device browsers.
if (
/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(
navigator.userAgent
) ||
/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(
navigator.userAgent.substr(0, 4)
)
) {
return true;
}
// Try to detect iOS
if (/iPad|iPhone|iPod/.test(navigator.platform)) {
return true;
} else {
if (/MacIntel/.test(navigator.platform)) {
// Work around for recent iPads that are "desktop-class browsing".
// We can still detect them using their touchscreen, but this is a hack.
// If mac laptops start to support touchscreens, this won't work anymore. Hence it's better
// to test for the presence of a touchscreen if needed rather than checking if the device
// is "mobile".
return !!navigator.maxTouchPoints && navigator.maxTouchPoints > 2;
}
}
}
return false;
};
let cachedIsMobile: boolean | null = null;
/**
* Check if the game runs on a mobile device (iPhone, iPad, Android).
* Note that the distinction between what is a mobile device and what is not
* is becoming blurry. If you use this for mobile controls,
* prefer to check if the device has touchscreen support.
*/
export const isMobile = (): boolean => {
if (cachedIsMobile !== null) {
return cachedIsMobile;
}
return (cachedIsMobile = checkIsMobile());
};
}
}
}

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