From 09204179b53e864aefe1868a8792b37c5490a824 Mon Sep 17 00:00:00 2001 From: Askou Date: Thu, 3 Jun 2021 15:54:13 +0200 Subject: [PATCH 01/78] basic bot_ia class template --- CMakeLists.txt | 2 + sources/Component/IA/IAComponent.cpp | 37 +++++++++++++++++++ sources/Component/IA/IAComponent.hpp | 55 ++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 sources/Component/IA/IAComponent.cpp create mode 100644 sources/Component/IA/IAComponent.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index fd2543bf..ee6fe4ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,6 +64,8 @@ set(SOURCES sources/Component/Collision/CollisionComponent.hpp sources/System/Collision/CollisionSystem.hpp sources/System/Collision/CollisionSystem.cpp + sources/Component/IA/IAComponent.hpp + sources/Component/IA/IAComponent.cpp ) add_executable(bomberman diff --git a/sources/Component/IA/IAComponent.cpp b/sources/Component/IA/IAComponent.cpp new file mode 100644 index 00000000..063467d6 --- /dev/null +++ b/sources/Component/IA/IAComponent.cpp @@ -0,0 +1,37 @@ +/* +** EPITECH PROJECT, 2021 +** Bomberman +** File description: +** IAComponent +*/ + +#include "IAComponent.hpp" +#include + +namespace BBM +{ + IAComponent::IAComponent(WAL::Entity &entity, std::string scriptPath) + : Component(entity), + _scriptPath(scriptPath) + { } + + IAComponent::IAComponent(WAL::Entity &entity) + : Component(entity), + _scriptPath() + { } + + WAL::Component *IAComponent::clone(WAL::Entity &entity) const + { + return new IAComponent(entity); + } + + Vector3f IAComponent::getPosition(void) const + { + return (this->_pos); + } + + void IAComponent::setPosition(Vector3f &pos) + { + this->_pos = pos; + } +} diff --git a/sources/Component/IA/IAComponent.hpp b/sources/Component/IA/IAComponent.hpp new file mode 100644 index 00000000..fdc1ed4a --- /dev/null +++ b/sources/Component/IA/IAComponent.hpp @@ -0,0 +1,55 @@ +/* +** EPITECH PROJECT, 2021 +** Bomberman +** File description: +** IAComponent +*/ + +#ifndef IACOMPONENT_HPP_ +#define IACOMPONENT_HPP_ + +#include "Component/Component.hpp" +#include "Entity/Entity.hpp" +#include "Models/Vector3.hpp" + +namespace BBM +{ + class IAComponent : public WAL::Component + { + private: + + Vector3f _pos; + const std::string _scriptPath; + + public: + + //! @brief get IA Position + Vector3f getPosition(void) const; + + //! @param pos Position of the player + //! @brief set IA position + void setPosition(Vector3f &); + + //! @inherit + WAL::Component *clone(WAL::Entity &entity) const override; + + //! @brief A IA component can't be instantiated, it should be derived. + explicit IAComponent(WAL::Entity &entity); + + //! @brief Constructor + IAComponent(WAL::Entity &entity, std::string scripPath); + + //! @brief A IA component can't be instantiated, it should be derived. + IAComponent(const IAComponent &) = default; + + //! @brief default destructor + ~IAComponent() override = default; + + //! @brief A IA component can't be assigned + IAComponent &operator=(const IAComponent &) = delete; + protected: + }; +} + + +#endif /* !IACOMPONENT_HPP_ */ From f141a6f4fac69eec2d8ad00807e54f3b37ef7f1e Mon Sep 17 00:00:00 2001 From: Bluub Date: Thu, 3 Jun 2021 17:57:31 +0200 Subject: [PATCH 02/78] compiling with lua in cmake --- CMakeLists.txt | 9 +- lib/lua/Findlua.cmake | 239 +++++++++++++++++++++++++++ sources/Component/IA/IAComponent.cpp | 2 +- 3 files changed, 247 insertions(+), 3 deletions(-) create mode 100644 lib/lua/Findlua.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index cfdc3912..04975fa6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,11 @@ project(bomberman) set(CMAKE_CXX_STANDARD 20) + +# Find Lua +find_package(Lua REQUIRED) #-> CHANGE + +include_directories(bomberman ${LUA_INCLUDE_DIR}) #-> ADDED '{LUA_INCLUDE_DIR}' include_directories(bomberman lib/Ray/sources) include_directories(bomberman lib/wal/sources) include_directories(bomberman sources) @@ -70,14 +75,14 @@ set(SOURCES sources/Component/IA/IAComponent.hpp sources/Component/IA/IAComponent.cpp ) + add_executable(bomberman sources/main.cpp ${SOURCES} ) -target_include_directories(bomberman PUBLIC sources) +target_include_directories(bomberman PUBLIC sources ${LUA_INCLUDE_DIR}) target_link_libraries(bomberman PUBLIC wal ray) - add_executable(unit_tests EXCLUDE_FROM_ALL ${SOURCES} tests/EntityTests.cpp diff --git a/lib/lua/Findlua.cmake b/lib/lua/Findlua.cmake new file mode 100644 index 00000000..2afa3892 --- /dev/null +++ b/lib/lua/Findlua.cmake @@ -0,0 +1,239 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +FindLua +------- + +Locate Lua library. + +.. versionadded:: 3.18 + Support for Lua 5.4. + +This module defines:: + +:: + + LUA_FOUND - if false, do not try to link to Lua + LUA_LIBRARIES - both lua and lualib + LUA_INCLUDE_DIR - where to find lua.h + LUA_VERSION_STRING - the version of Lua found + LUA_VERSION_MAJOR - the major version of Lua + LUA_VERSION_MINOR - the minor version of Lua + LUA_VERSION_PATCH - the patch version of Lua + + + +Note that the expected include convention is + +:: + + #include "lua.h" + +and not + +:: + + #include + +This is because, the lua location is not standardized and may exist in +locations other than lua/ +#]=======================================================================] + +cmake_policy(PUSH) # Policies apply to functions at definition-time +cmake_policy(SET CMP0012 NEW) # For while(TRUE) + +unset(_lua_include_subdirs) +unset(_lua_library_names) +unset(_lua_append_versions) + +# this is a function only to have all the variables inside go away automatically +function(_lua_get_versions) + set(LUA_VERSIONS5 5.4 5.3 5.2 5.1 5.0) + + if (Lua_FIND_VERSION_EXACT) + if (Lua_FIND_VERSION_COUNT GREATER 1) + set(_lua_append_versions ${Lua_FIND_VERSION_MAJOR}.${Lua_FIND_VERSION_MINOR}) + endif () + elseif (Lua_FIND_VERSION) + # once there is a different major version supported this should become a loop + if (NOT Lua_FIND_VERSION_MAJOR GREATER 5) + if (Lua_FIND_VERSION_COUNT EQUAL 1) + set(_lua_append_versions ${LUA_VERSIONS5}) + else () + foreach (subver IN LISTS LUA_VERSIONS5) + if (NOT subver VERSION_LESS ${Lua_FIND_VERSION}) + list(APPEND _lua_append_versions ${subver}) + endif () + endforeach () + # New version -> Search for it (heuristic only! Defines in include might have changed) + if (NOT _lua_append_versions) + set(_lua_append_versions ${Lua_FIND_VERSION_MAJOR}.${Lua_FIND_VERSION_MINOR}) + endif() + endif () + endif () + else () + # once there is a different major version supported this should become a loop + set(_lua_append_versions ${LUA_VERSIONS5}) + endif () + + if (LUA_Debug) + message(STATUS "Considering following Lua versions: ${_lua_append_versions}") + endif() + + set(_lua_append_versions "${_lua_append_versions}" PARENT_SCOPE) +endfunction() + +function(_lua_set_version_vars) + set(_lua_include_subdirs_raw "lua") + + foreach (ver IN LISTS _lua_append_versions) + string(REGEX MATCH "^([0-9]+)\\.([0-9]+)$" _ver "${ver}") + list(APPEND _lua_include_subdirs_raw + lua${CMAKE_MATCH_1}${CMAKE_MATCH_2} + lua${CMAKE_MATCH_1}.${CMAKE_MATCH_2} + lua-${CMAKE_MATCH_1}.${CMAKE_MATCH_2} + ) + endforeach () + + # Prepend "include/" to each path directly after the path + set(_lua_include_subdirs "include") + foreach (dir IN LISTS _lua_include_subdirs_raw) + list(APPEND _lua_include_subdirs "${dir}" "include/${dir}") + endforeach () + + set(_lua_include_subdirs "${_lua_include_subdirs}" PARENT_SCOPE) +endfunction(_lua_set_version_vars) + +function(_lua_get_header_version) + unset(LUA_VERSION_STRING PARENT_SCOPE) + set(_hdr_file "${LUA_INCLUDE_DIR}/lua.h") + + if (NOT EXISTS "${_hdr_file}") + return() + endif () + + # At least 5.[012] have different ways to express the version + # so all of them need to be tested. Lua 5.2 defines LUA_VERSION + # and LUA_RELEASE as joined by the C preprocessor, so avoid those. + file(STRINGS "${_hdr_file}" lua_version_strings + REGEX "^#define[ \t]+LUA_(RELEASE[ \t]+\"Lua [0-9]|VERSION([ \t]+\"Lua [0-9]|_[MR])).*") + + string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_MAJOR[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_MAJOR ";${lua_version_strings};") + if (LUA_VERSION_MAJOR MATCHES "^[0-9]+$") + string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_MINOR[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_MINOR ";${lua_version_strings};") + string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_RELEASE[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_PATCH ";${lua_version_strings};") + set(LUA_VERSION_STRING "${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}.${LUA_VERSION_PATCH}") + else () + string(REGEX REPLACE ".*;#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([0-9.]+)\"[ \t]*;.*" "\\1" LUA_VERSION_STRING ";${lua_version_strings};") + if (NOT LUA_VERSION_STRING MATCHES "^[0-9.]+$") + string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION[ \t]+\"Lua ([0-9.]+)\"[ \t]*;.*" "\\1" LUA_VERSION_STRING ";${lua_version_strings};") + endif () + string(REGEX REPLACE "^([0-9]+)\\.[0-9.]*$" "\\1" LUA_VERSION_MAJOR "${LUA_VERSION_STRING}") + string(REGEX REPLACE "^[0-9]+\\.([0-9]+)[0-9.]*$" "\\1" LUA_VERSION_MINOR "${LUA_VERSION_STRING}") + string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]).*" "\\1" LUA_VERSION_PATCH "${LUA_VERSION_STRING}") + endif () + foreach (ver IN LISTS _lua_append_versions) + if (ver STREQUAL "${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}") + set(LUA_VERSION_MAJOR ${LUA_VERSION_MAJOR} PARENT_SCOPE) + set(LUA_VERSION_MINOR ${LUA_VERSION_MINOR} PARENT_SCOPE) + set(LUA_VERSION_PATCH ${LUA_VERSION_PATCH} PARENT_SCOPE) + set(LUA_VERSION_STRING ${LUA_VERSION_STRING} PARENT_SCOPE) + return() + endif () + endforeach () +endfunction(_lua_get_header_version) + +function(_lua_find_header) + _lua_set_version_vars() + + # Initialize as local variable + set(CMAKE_IGNORE_PATH ${CMAKE_IGNORE_PATH}) + while (TRUE) + # Find the next header to test. Check each possible subdir in order + # This prefers e.g. higher versions as they are earlier in the list + # It is also consistent with previous versions of FindLua + foreach (subdir IN LISTS _lua_include_subdirs) + find_path(LUA_INCLUDE_DIR lua.h + HINTS ENV LUA_DIR + PATH_SUFFIXES ${subdir} + ) + if (LUA_INCLUDE_DIR) + break() + endif() + endforeach() + # Did not found header -> Fail + if (NOT LUA_INCLUDE_DIR) + return() + endif() + _lua_get_header_version() + # Found accepted version -> Ok + if (LUA_VERSION_STRING) + if (LUA_Debug) + message(STATUS "Found suitable version ${LUA_VERSION_STRING} in ${LUA_INCLUDE_DIR}/lua.h") + endif() + return() + endif() + # Found wrong version -> Ignore this path and retry + if (LUA_Debug) + message(STATUS "Ignoring unsuitable version in ${LUA_INCLUDE_DIR}") + endif() + list(APPEND CMAKE_IGNORE_PATH "${LUA_INCLUDE_DIR}") + unset(LUA_INCLUDE_DIR CACHE) + unset(LUA_INCLUDE_DIR) + unset(LUA_INCLUDE_DIR PARENT_SCOPE) + endwhile () +endfunction() + +_lua_get_versions() +_lua_find_header() +_lua_get_header_version() +unset(_lua_append_versions) + +if (LUA_VERSION_STRING) + set(_lua_library_names + lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR} + lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR} + lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR} + lua.${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR} + ) +endif () + +find_library(LUA_LIBRARY + NAMES ${_lua_library_names} lua + NAMES_PER_DIR + HINTS + ENV LUA_DIR + PATH_SUFFIXES lib +) +unset(_lua_library_names) + +if (LUA_LIBRARY) + # include the math library for Unix + if (UNIX AND NOT APPLE AND NOT BEOS) + find_library(LUA_MATH_LIBRARY m) + mark_as_advanced(LUA_MATH_LIBRARY) + set(LUA_LIBRARIES "${LUA_LIBRARY};${LUA_MATH_LIBRARY}") + + # include dl library for statically-linked Lua library + get_filename_component(LUA_LIB_EXT ${LUA_LIBRARY} EXT) + if(LUA_LIB_EXT STREQUAL CMAKE_STATIC_LIBRARY_SUFFIX) + list(APPEND LUA_LIBRARIES ${CMAKE_DL_LIBS}) + endif() + + # For Windows and Mac, don't need to explicitly include the math library + else () + set(LUA_LIBRARIES "${LUA_LIBRARY}") + endif () +endif () + +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) +# handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if +# all listed variables are TRUE +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua + REQUIRED_VARS LUA_LIBRARIES LUA_INCLUDE_DIR + VERSION_VAR LUA_VERSION_STRING) + +mark_as_advanced(LUA_INCLUDE_DIR LUA_LIBRARY) + +cmake_policy(POP) \ No newline at end of file diff --git a/sources/Component/IA/IAComponent.cpp b/sources/Component/IA/IAComponent.cpp index 063467d6..6d6ed180 100644 --- a/sources/Component/IA/IAComponent.cpp +++ b/sources/Component/IA/IAComponent.cpp @@ -6,7 +6,7 @@ */ #include "IAComponent.hpp" -#include +#include "lua.h" namespace BBM { From dbd95c73d577bb632bda4cde01e935ab58cac43d Mon Sep 17 00:00:00 2001 From: Bluub Date: Fri, 4 Jun 2021 00:15:13 +0200 Subject: [PATCH 03/78] removing positino in controllable component --- CMakeLists.txt | 4 +- sources/Component/IA/IAComponent.cpp | 37 ------------------- .../IAControllableComponent.cpp | 23 ++++++++++++ .../IAControllableComponent.hpp} | 22 +++-------- 4 files changed, 30 insertions(+), 56 deletions(-) delete mode 100644 sources/Component/IA/IAComponent.cpp create mode 100644 sources/Component/IAControllable/IAControllableComponent.cpp rename sources/Component/{IA/IAComponent.hpp => IAControllable/IAControllableComponent.hpp} (50%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 04975fa6..e9c7901c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,8 +72,8 @@ set(SOURCES sources/Component/Collision/CollisionComponent.hpp sources/System/Collision/CollisionSystem.hpp sources/System/Collision/CollisionSystem.cpp - sources/Component/IA/IAComponent.hpp - sources/Component/IA/IAComponent.cpp + sources/Component/IAControllable/IAControllableComponent.hpp + sources/Component/IAControllable/IAControllableComponent.cpp ) add_executable(bomberman diff --git a/sources/Component/IA/IAComponent.cpp b/sources/Component/IA/IAComponent.cpp deleted file mode 100644 index 6d6ed180..00000000 --- a/sources/Component/IA/IAComponent.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* -** EPITECH PROJECT, 2021 -** Bomberman -** File description: -** IAComponent -*/ - -#include "IAComponent.hpp" -#include "lua.h" - -namespace BBM -{ - IAComponent::IAComponent(WAL::Entity &entity, std::string scriptPath) - : Component(entity), - _scriptPath(scriptPath) - { } - - IAComponent::IAComponent(WAL::Entity &entity) - : Component(entity), - _scriptPath() - { } - - WAL::Component *IAComponent::clone(WAL::Entity &entity) const - { - return new IAComponent(entity); - } - - Vector3f IAComponent::getPosition(void) const - { - return (this->_pos); - } - - void IAComponent::setPosition(Vector3f &pos) - { - this->_pos = pos; - } -} diff --git a/sources/Component/IAControllable/IAControllableComponent.cpp b/sources/Component/IAControllable/IAControllableComponent.cpp new file mode 100644 index 00000000..18905d25 --- /dev/null +++ b/sources/Component/IAControllable/IAControllableComponent.cpp @@ -0,0 +1,23 @@ +/* +** EPITECH PROJECT, 2021 +** Bomberman +** File description: +** IAControllableComponent +*/ + +#include "IAControllableComponent.hpp" +#include "lua.h" + +namespace BBM +{ + IAControllableComponent::IAControllableComponent(WAL::Entity &entity, std::string scriptPath) + : Component(entity), + _scriptPath(scriptPath) + { } + + WAL::Component *IAControllableComponent::clone(WAL::Entity &entity) const + { + return new IAControllableComponent(entity, _scriptPath); + } + +} diff --git a/sources/Component/IA/IAComponent.hpp b/sources/Component/IAControllable/IAControllableComponent.hpp similarity index 50% rename from sources/Component/IA/IAComponent.hpp rename to sources/Component/IAControllable/IAControllableComponent.hpp index fdc1ed4a..bd4158a9 100644 --- a/sources/Component/IA/IAComponent.hpp +++ b/sources/Component/IAControllable/IAControllableComponent.hpp @@ -14,39 +14,27 @@ namespace BBM { - class IAComponent : public WAL::Component + class IAControllableComponent : public WAL::Component { private: - - Vector3f _pos; const std::string _scriptPath; public: - //! @brief get IA Position - Vector3f getPosition(void) const; - - //! @param pos Position of the player - //! @brief set IA position - void setPosition(Vector3f &); - //! @inherit WAL::Component *clone(WAL::Entity &entity) const override; - - //! @brief A IA component can't be instantiated, it should be derived. - explicit IAComponent(WAL::Entity &entity); //! @brief Constructor - IAComponent(WAL::Entity &entity, std::string scripPath); + IAControllableComponent(WAL::Entity &entity, std::string scripPath); //! @brief A IA component can't be instantiated, it should be derived. - IAComponent(const IAComponent &) = default; + IAControllableComponent(const IAControllableComponent &) = default; //! @brief default destructor - ~IAComponent() override = default; + ~IAControllableComponent() override = default; //! @brief A IA component can't be assigned - IAComponent &operator=(const IAComponent &) = delete; + IAControllableComponent &operator=(const IAControllableComponent &) = delete; protected: }; } From 39f417358d216598960ae030ffe770857a2a29ec Mon Sep 17 00:00:00 2001 From: Bluub Date: Mon, 7 Jun 2021 00:51:29 +0200 Subject: [PATCH 04/78] loading the file and checking if there is an update function --- CMakeLists.txt | 2 +- ai_scripts/john.lua | 3 +++ .../IAControllable/IAControllableComponent.cpp | 11 +++++++---- .../IAControllable/IAControllableComponent.hpp | 5 ++++- sources/Models/GameState.hpp | 2 +- sources/Runner/Runner.cpp | 4 +++- 6 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 ai_scripts/john.lua diff --git a/CMakeLists.txt b/CMakeLists.txt index e9c7901c..9a3da03b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,7 +81,7 @@ add_executable(bomberman ${SOURCES} ) target_include_directories(bomberman PUBLIC sources ${LUA_INCLUDE_DIR}) -target_link_libraries(bomberman PUBLIC wal ray) +target_link_libraries(bomberman PUBLIC wal ray lua) add_executable(unit_tests EXCLUDE_FROM_ALL ${SOURCES} diff --git a/ai_scripts/john.lua b/ai_scripts/john.lua new file mode 100644 index 00000000..a58b3496 --- /dev/null +++ b/ai_scripts/john.lua @@ -0,0 +1,3 @@ +function sum(a,b) + return a + b; +end diff --git a/sources/Component/IAControllable/IAControllableComponent.cpp b/sources/Component/IAControllable/IAControllableComponent.cpp index 18905d25..863135b9 100644 --- a/sources/Component/IAControllable/IAControllableComponent.cpp +++ b/sources/Component/IAControllable/IAControllableComponent.cpp @@ -6,14 +6,17 @@ */ #include "IAControllableComponent.hpp" -#include "lua.h" namespace BBM { IAControllableComponent::IAControllableComponent(WAL::Entity &entity, std::string scriptPath) - : Component(entity), - _scriptPath(scriptPath) - { } + : Component(entity), _scriptPath(scriptPath), state(luaL_newstate()) + { + luaL_dofile(state, scriptPath.c_str()); + lua_getglobal(state, "update"); + if (!lua_isfunction(state, -1)) + std::cout << "No update function in the script" << std::endl; + } WAL::Component *IAControllableComponent::clone(WAL::Entity &entity) const { diff --git a/sources/Component/IAControllable/IAControllableComponent.hpp b/sources/Component/IAControllable/IAControllableComponent.hpp index bd4158a9..ab8b572e 100644 --- a/sources/Component/IAControllable/IAControllableComponent.hpp +++ b/sources/Component/IAControllable/IAControllableComponent.hpp @@ -11,15 +11,18 @@ #include "Component/Component.hpp" #include "Entity/Entity.hpp" #include "Models/Vector3.hpp" +#include "lua.hpp" namespace BBM { class IAControllableComponent : public WAL::Component { private: + //! @brief path to the lua script const std::string _scriptPath; - public: + //! @brief Lua executing state + lua_State *state; //! @inherit WAL::Component *clone(WAL::Entity &entity) const override; diff --git a/sources/Models/GameState.hpp b/sources/Models/GameState.hpp index 883578bf..9bfaacf7 100644 --- a/sources/Models/GameState.hpp +++ b/sources/Models/GameState.hpp @@ -1,6 +1,6 @@ // // Created by Zoe Roux on 5/24/21. -// +//p #pragma once diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index cd5b30e1..73ff735c 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include "Models/Vector2.hpp" @@ -71,7 +72,8 @@ namespace BBM .addComponent() .addComponent(RAY::ModelAnimations("assets/player/player.iqm"), 1) .addComponent(2) - .addComponent(); + .addComponent() + .addComponent("./ai_scripts/john.lua"); scene->addEntity("cube") .addComponent(-5, 0, -5) .addComponent(Vector3f(-5, 0, -5), Vector3f(3, 3, 3), RED) From 2c3fbee797fd71dcb4fdb802d19a3c68bf451cf5 Mon Sep 17 00:00:00 2001 From: Bluub Date: Mon, 7 Jun 2021 10:55:22 +0200 Subject: [PATCH 05/78] moving player up with the lua script --- CMakeLists.txt | 2 ++ ai_scripts/john.lua | 4 +++ sources/Runner/Runner.cpp | 2 ++ .../IAControllable/IAControllableSystem.cpp | 33 +++++++++++++++++++ .../IAControllable/IAControllableSystem.hpp | 27 +++++++++++++++ 5 files changed, 68 insertions(+) create mode 100644 sources/System/IAControllable/IAControllableSystem.cpp create mode 100644 sources/System/IAControllable/IAControllableSystem.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a3da03b..c736ea41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,6 +74,8 @@ set(SOURCES sources/System/Collision/CollisionSystem.cpp sources/Component/IAControllable/IAControllableComponent.hpp sources/Component/IAControllable/IAControllableComponent.cpp + sources/System/IAControllable/IAControllableSystem.hpp + sources/System/IAControllable/IAControllableSystem.cpp ) add_executable(bomberman diff --git a/ai_scripts/john.lua b/ai_scripts/john.lua index a58b3496..3c74b31d 100644 --- a/ai_scripts/john.lua +++ b/ai_scripts/john.lua @@ -1,3 +1,7 @@ function sum(a,b) return a + b; end + +function update() + return 1; +end \ No newline at end of file diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 73ff735c..835d6c2f 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -30,6 +30,7 @@ #include "Component/Animation/AnimationsComponent.hpp" #include "System/Animation/AnimationsSystem.hpp" #include "Map/Map.hpp" +#include "System/IAControllable/IAControllableSystem.hpp" namespace RAY2D = RAY::Drawables::Drawables2D; namespace RAY3D = RAY::Drawables::Drawables3D; @@ -50,6 +51,7 @@ namespace BBM { wal.addSystem() .addSystem() + .addSystem() .addSystem() .addSystem(wal) .addSystem(); diff --git a/sources/System/IAControllable/IAControllableSystem.cpp b/sources/System/IAControllable/IAControllableSystem.cpp new file mode 100644 index 00000000..f020504d --- /dev/null +++ b/sources/System/IAControllable/IAControllableSystem.cpp @@ -0,0 +1,33 @@ +// +// Created by Louis Auzuret on 06/07/21 +// + +#include "Component/Controllable/ControllableComponent.hpp" +#include "Component/IAControllable/IAControllableComponent.hpp" +#include "System/IAControllable/IAControllableSystem.hpp" + +namespace BBM +{ + IAControllableSystem::IAControllableSystem() + : WAL::System({ typeid(IAControllableComponent), + typeid(ControllableComponent)}) + { } + + void IAControllableSystem::onFixedUpdate(WAL::Entity &entity) + { + auto &ia = entity.getComponent(); + auto &controllable = entity.getComponent(); + + lua_getglobal(ia.state, "update"); + //push parameters + int nbParams = 0; + int nbReturn = 1; + lua_pcall(ia.state, nbParams, nbReturn, 0); + if (lua_isnil(ia.state, -1)) + return; + if (!lua_isnumber(ia.state, -1)) + return; + controllable.move.y = lua_tonumber(ia.state, -1); + lua_pop(ia.state, 1); + } +} \ No newline at end of file diff --git a/sources/System/IAControllable/IAControllableSystem.hpp b/sources/System/IAControllable/IAControllableSystem.hpp new file mode 100644 index 00000000..8528c01d --- /dev/null +++ b/sources/System/IAControllable/IAControllableSystem.hpp @@ -0,0 +1,27 @@ +// +// Created by Louis Auzuret on 06/07/21 +// + +#pragma once + +#include "System/System.hpp" + +namespace BBM +{ + //! @brief A system to handle keyboard entities. + class IAControllableSystem : public WAL::System + { + public: + //! @inherit + void onFixedUpdate(WAL::Entity &entity) override; + + //! @brief A default constructor + IAControllableSystem(); + //! @brief A keyboard system is copy constructable + IAControllableSystem(const IAControllableSystem &) = default; + //! @brief A default destructor + ~IAControllableSystem() override = default; + //! @brief A keyboard system is assignable. + IAControllableSystem &operator=(const IAControllableSystem &) = default; + }; +} From 75f6b04e9a2a6e74a398c26da284eee52ea4e543 Mon Sep 17 00:00:00 2001 From: Bluub Date: Mon, 7 Jun 2021 11:19:23 +0200 Subject: [PATCH 06/78] get the 4 returns of the update function --- ai_scripts/john.lua | 6 +-- .../IAControllableComponent.cpp | 2 +- .../IAControllable/IAControllableSystem.cpp | 41 +++++++++++++++---- .../IAControllable/IAControllableSystem.hpp | 5 +++ 4 files changed, 42 insertions(+), 12 deletions(-) diff --git a/ai_scripts/john.lua b/ai_scripts/john.lua index 3c74b31d..22d71275 100644 --- a/ai_scripts/john.lua +++ b/ai_scripts/john.lua @@ -1,7 +1,7 @@ -function sum(a,b) +function Sum(a,b) return a + b; end -function update() - return 1; +function Update() + return 1, 1, false, false; end \ No newline at end of file diff --git a/sources/Component/IAControllable/IAControllableComponent.cpp b/sources/Component/IAControllable/IAControllableComponent.cpp index 863135b9..7df7d830 100644 --- a/sources/Component/IAControllable/IAControllableComponent.cpp +++ b/sources/Component/IAControllable/IAControllableComponent.cpp @@ -13,7 +13,7 @@ namespace BBM : Component(entity), _scriptPath(scriptPath), state(luaL_newstate()) { luaL_dofile(state, scriptPath.c_str()); - lua_getglobal(state, "update"); + lua_getglobal(state, "Update"); if (!lua_isfunction(state, -1)) std::cout << "No update function in the script" << std::endl; } diff --git a/sources/System/IAControllable/IAControllableSystem.cpp b/sources/System/IAControllable/IAControllableSystem.cpp index f020504d..097be3df 100644 --- a/sources/System/IAControllable/IAControllableSystem.cpp +++ b/sources/System/IAControllable/IAControllableSystem.cpp @@ -13,21 +13,46 @@ namespace BBM typeid(ControllableComponent)}) { } + float IAControllableSystem::getReturnNumber(lua_State *state) + { + float res = 0; + + if (lua_isnil(state, -1)) + return res; + if (!lua_isnumber(state, -1)) + return res; + res = lua_tonumber(state, -1); + lua_pop(state, 1); + + return res; + } + + bool IAControllableSystem::getReturnBool(lua_State *state) + { + bool res = false; + + if (lua_isnil(state, -1)) + return res; + if (!lua_isboolean(state, -1)) + return res; + res = lua_toboolean(state, -1); + lua_pop(state, 1); + return res; + } + void IAControllableSystem::onFixedUpdate(WAL::Entity &entity) { auto &ia = entity.getComponent(); auto &controllable = entity.getComponent(); - lua_getglobal(ia.state, "update"); + lua_getglobal(ia.state, "Update"); //push parameters int nbParams = 0; - int nbReturn = 1; + int nbReturn = 4; lua_pcall(ia.state, nbParams, nbReturn, 0); - if (lua_isnil(ia.state, -1)) - return; - if (!lua_isnumber(ia.state, -1)) - return; - controllable.move.y = lua_tonumber(ia.state, -1); - lua_pop(ia.state, 1); + controllable.bomb = getReturnBool(ia.state); + controllable.jump = getReturnBool(ia.state); + controllable.move.y = getReturnNumber(ia.state); + controllable.move.x = getReturnNumber(ia.state); } } \ No newline at end of file diff --git a/sources/System/IAControllable/IAControllableSystem.hpp b/sources/System/IAControllable/IAControllableSystem.hpp index 8528c01d..b0ec6e70 100644 --- a/sources/System/IAControllable/IAControllableSystem.hpp +++ b/sources/System/IAControllable/IAControllableSystem.hpp @@ -11,6 +11,11 @@ namespace BBM //! @brief A system to handle keyboard entities. class IAControllableSystem : public WAL::System { + private: + //! @brief extract a number from the lua stack + float getReturnNumber(lua_State *state); + //! @brief extract a bool from the lua stack + bool getReturnBool(lua_State *state); public: //! @inherit void onFixedUpdate(WAL::Entity &entity) override; From b7bf544b4856e30e30c8d559834466388e463ce3 Mon Sep 17 00:00:00 2001 From: Bluub Date: Mon, 7 Jun 2021 16:42:51 +0200 Subject: [PATCH 07/78] basic tag component --- CMakeLists.txt | 2 ++ sources/Component/Tag/TagComponent.cpp | 17 +++++++++++++++++ sources/Component/Tag/TagComponent.hpp | 16 +++++++++------- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6074174b..167ea788 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,8 @@ set(SOURCES sources/Component/IAControllable/IAControllableComponent.cpp sources/System/IAControllable/IAControllableSystem.hpp sources/System/IAControllable/IAControllableSystem.cpp + sources/Component/Tag/TagComponent.cpp + sources/Component/Tag/TagComponent.hpp ) add_executable(bomberman diff --git a/sources/Component/Tag/TagComponent.cpp b/sources/Component/Tag/TagComponent.cpp index e69de29b..14308654 100644 --- a/sources/Component/Tag/TagComponent.cpp +++ b/sources/Component/Tag/TagComponent.cpp @@ -0,0 +1,17 @@ +// +// Created By Louis Auzuret on 07/06/21 +// + +#include "Component/Tag/TagComponent.hpp" + +namespace BBM +{ + WAL::Component *TagComponent::clone(WAL::Entity &entity) const + { + return new TagComponent(entity, tag); + } + + TagComponent::TagComponent(WAL::Entity &entity, std::string tag) + : Component(entity), tag(tag) + { } +} \ No newline at end of file diff --git a/sources/Component/Tag/TagComponent.hpp b/sources/Component/Tag/TagComponent.hpp index 70a3824e..082a5504 100644 --- a/sources/Component/Tag/TagComponent.hpp +++ b/sources/Component/Tag/TagComponent.hpp @@ -13,20 +13,22 @@ namespace BBM class TagComponent : public WAL::Component { public: + //! @brief tag held by the component + std::string tag; //! @inherit WAL::Component *clone(WAL::Entity &entity) const override; - //! @brief Create a new keyboard component using default keys. - explicit KeyboardComponent(WAL::Entity &entity); + //! @brief Create a new tag Component with a tag + explicit TagComponent(WAL::Entity &entity, std::string tag); - //! @brief A Keyboard component is copy constructable. - KeyboardComponent(const KeyboardComponent &) = default; + //! @brief A Tag component is copy constructable. + TagComponent(const TagComponent &) = default; //! @brief default destructor - ~KeyboardComponent() override = default; + ~TagComponent() override = default; - //! @brief A Keyboard component can't be assigned - KeyboardComponent &operator=(const KeyboardComponent &) = delete; + //! @brief A Tag component can't be assigned + TagComponent &operator=(const TagComponent &) = delete; }; } \ No newline at end of file From cc50f90c6fd4e8d4646fec22a7100cff8e86a17f Mon Sep 17 00:00:00 2001 From: Bluub Date: Mon, 7 Jun 2021 17:00:43 +0200 Subject: [PATCH 08/78] fix cmake lua install --- CMakeLists.txt | 4 ++-- sources/Map/Map.cpp | 26 +++++++++++++++++--------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 167ea788..d0dcb4fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,7 +87,7 @@ add_executable(bomberman ${SOURCES} ) target_include_directories(bomberman PUBLIC sources ${LUA_INCLUDE_DIR}) -target_link_libraries(bomberman PUBLIC wal ray lua) +target_link_libraries(bomberman PUBLIC wal ray ${LUA_LIBRARIES}) add_executable(unit_tests EXCLUDE_FROM_ALL ${SOURCES} @@ -100,7 +100,7 @@ add_executable(unit_tests EXCLUDE_FROM_ALL tests/CollisionTest.cpp ) target_include_directories(unit_tests PUBLIC sources) -target_link_libraries(unit_tests PUBLIC wal ray) +target_link_libraries(unit_tests PUBLIC wal ray lua) find_package(Catch2 QUIET) if (NOT Catch2_FOUND) diff --git a/sources/Map/Map.cpp b/sources/Map/Map.cpp index c4709164..8d14e585 100644 --- a/sources/Map/Map.cpp +++ b/sources/Map/Map.cpp @@ -3,9 +3,10 @@ // Edited by Benjamin Henry on 5/26/21. // +#include "Component/Tag/TagComponent.hpp" #include -#include "Map.hpp" #include +#include "Map.hpp" namespace RAY3D = RAY::Drawables::Drawables3D; @@ -54,7 +55,8 @@ namespace BBM scene->addEntity("Unbreakable Wall") .addComponent(i, 0, j) .addComponent(WAL::Callback(), &MapGenerator::wallCollide, .75) - .addComponent(unbreakableObj, std::make_pair(MAP_DIFFUSE, unbreakablePng)); + .addComponent(unbreakableObj, std::make_pair(MAP_DIFFUSE, unbreakablePng)) + .addComponent("UNBREAKABLE");; } } } @@ -101,8 +103,9 @@ namespace BBM if (map[std::make_tuple(i, 0, j)] != HOLE && map[std::make_tuple(i, -1, j)] != BUMPER) scene->addEntity("Unbreakable Wall") .addComponent(Vector3f(i, -1, j)) - .addComponent(floorObj, - std::make_pair(MAP_DIFFUSE, floorPng)); + .addComponent(floorObj, + std::make_pair(MAP_DIFFUSE, floorPng)) + .addComponent("UNBREAKABLE");; } } } @@ -136,7 +139,8 @@ namespace BBM .addComponent(coords) .addComponent(1) .addComponent(WAL::Callback(), &MapGenerator::wallCollide, .75) - .addComponent(breakableObj, std::make_pair(MAP_DIFFUSE, breakablePng)); + .addComponent(breakableObj, std::make_pair(MAP_DIFFUSE, breakablePng)) + .addComponent("BREAKABLE"); } void MapGenerator::createFloor(Vector3f coords, std::shared_ptr scene) @@ -170,7 +174,8 @@ namespace BBM .addComponent(coords) .addComponent(WAL::Callback(), &MapGenerator::wallCollide, .75) .addComponent(UnbreakableObj, - std::make_pair(MAP_DIFFUSE, UnbreakablePng)); + std::make_pair(MAP_DIFFUSE, UnbreakablePng)) + .addComponent("UNBREAKABLE");; } void MapGenerator::createHole(Vector3f coords, std::shared_ptr scene) @@ -182,7 +187,8 @@ namespace BBM WAL::Entity &holeEntity = scene->addEntity("Hole Block"); - holeEntity.addComponent(Vector3f(coords.x, coords.y - 1, coords.z)); + holeEntity.addComponent(Vector3f(coords.x, coords.y - 1, coords.z)) + .addComponent("HOLE");; if (coords.y == 0) holeEntity.addComponent(holeObj, std::make_pair(MAP_DIFFUSE, holePng)); @@ -203,7 +209,8 @@ namespace BBM scene->addEntity("Bumper Block") .addComponent(Vector3f(coords.x, coords.y, coords.z)) - .addComponent(bumperObj, std::make_pair(MAP_DIFFUSE, bumperPng)); + .addComponent(bumperObj, std::make_pair(MAP_DIFFUSE, bumperPng)) + .addComponent("BUMPER");; /* .addComponent([](const WAL::Entity &entity, WAL::Entity &other) { if (other.hasComponent()) { auto &movable = other.getComponent(); @@ -220,7 +227,8 @@ namespace BBM scene->addEntity("Stairs Block") .addComponent(coords) //.addComponent(1) - .addComponent(stairsObj, std::make_pair(MAP_DIFFUSE, stairsPng)); + .addComponent(stairsObj, std::make_pair(MAP_DIFFUSE, stairsPng)) + .addComponent("STAIRS");; } bool MapGenerator::isCloseToBlockType(std::map, BlockType> map, int x, int y, int z, From 92a486204156c63d42f3078c7bab51e1a8477fa5 Mon Sep 17 00:00:00 2001 From: Bluub Date: Tue, 8 Jun 2021 10:44:28 +0200 Subject: [PATCH 09/78] function check --- ai_scripts/john.lua | 2 +- sources/Component/IAControllable/IAControllableComponent.cpp | 2 +- sources/System/IAControllable/IAControllableSystem.cpp | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ai_scripts/john.lua b/ai_scripts/john.lua index 22d71275..e6c274cf 100644 --- a/ai_scripts/john.lua +++ b/ai_scripts/john.lua @@ -4,4 +4,4 @@ end function Update() return 1, 1, false, false; -end \ No newline at end of file +end diff --git a/sources/Component/IAControllable/IAControllableComponent.cpp b/sources/Component/IAControllable/IAControllableComponent.cpp index 7df7d830..11d40b2c 100644 --- a/sources/Component/IAControllable/IAControllableComponent.cpp +++ b/sources/Component/IAControllable/IAControllableComponent.cpp @@ -5,7 +5,7 @@ ** IAControllableComponent */ -#include "IAControllableComponent.hpp" +#include "Component/IAControllable/IAControllableComponent.hpp" namespace BBM { diff --git a/sources/System/IAControllable/IAControllableSystem.cpp b/sources/System/IAControllable/IAControllableSystem.cpp index 31753a9a..55b32e07 100644 --- a/sources/System/IAControllable/IAControllableSystem.cpp +++ b/sources/System/IAControllable/IAControllableSystem.cpp @@ -45,6 +45,10 @@ namespace BBM auto &controllable = entity.get(); lua_getglobal(ia.state, "Update"); + if (!lua_isfunction(ia.state, -1)) + return; + //std::vector<> players; + //std::vector<> map; //push parameters int nbParams = 0; int nbReturn = 4; From 41ff375d6a210a94ad86dce145044466a129794a Mon Sep 17 00:00:00 2001 From: Bluub Date: Wed, 9 Jun 2021 12:08:40 +0200 Subject: [PATCH 10/78] using luabridge, binding MapInfo type and calling update --- CMakeLists.txt | 7 +- ai_scripts/john.lua | 5 +- lib/LuaBridge/LuaBridge.hpp | 7789 +++++++++++++++++ .../IAControllableComponent.cpp | 14 +- .../IAControllableComponent.hpp | 1 + sources/Map/Map.hpp | 36 +- sources/Map/MapInfo.cpp | 21 + sources/Map/MapInfo.hpp | 37 + .../IAControllable/IAControllableSystem.cpp | 24 +- 9 files changed, 7897 insertions(+), 37 deletions(-) create mode 100644 lib/LuaBridge/LuaBridge.hpp create mode 100644 sources/Map/MapInfo.cpp create mode 100644 sources/Map/MapInfo.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d0dcb4fb..fc6cda92 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,9 +7,10 @@ set(CMAKE_CXX_STANDARD 20) # Find Lua find_package(Lua REQUIRED) #-> CHANGE -include_directories(bomberman ${LUA_INCLUDE_DIR}) #-> ADDED '{LUA_INCLUDE_DIR}' +include_directories(bomberman ${LUA_INCLUDE_DIR}) include_directories(bomberman lib/Ray/sources) include_directories(bomberman lib/wal/sources) +include_directories(bomberman lib/LuaBridge) include_directories(bomberman sources) add_subdirectory(${PROJECT_SOURCE_DIR}/lib/wal) @@ -80,13 +81,15 @@ set(SOURCES sources/System/IAControllable/IAControllableSystem.cpp sources/Component/Tag/TagComponent.cpp sources/Component/Tag/TagComponent.hpp + sources/Map/MapInfo.hpp + sources/Map/MapInfo.cpp ) add_executable(bomberman sources/main.cpp ${SOURCES} ) -target_include_directories(bomberman PUBLIC sources ${LUA_INCLUDE_DIR}) +target_include_directories(bomberman PUBLIC sources ${LUA_INCLUDE_DIR} lib/LuaBridge) target_link_libraries(bomberman PUBLIC wal ray ${LUA_LIBRARIES}) add_executable(unit_tests EXCLUDE_FROM_ALL diff --git a/ai_scripts/john.lua b/ai_scripts/john.lua index e6c274cf..5bec036a 100644 --- a/ai_scripts/john.lua +++ b/ai_scripts/john.lua @@ -2,6 +2,7 @@ function Sum(a,b) return a + b; end -function Update() +function Update(info) return 1, 1, false, false; -end + --return info.x, info.y, (info.z ~= 1), (info.type ~= 0); +end \ No newline at end of file diff --git a/lib/LuaBridge/LuaBridge.hpp b/lib/LuaBridge/LuaBridge.hpp new file mode 100644 index 00000000..d8e84159 --- /dev/null +++ b/lib/LuaBridge/LuaBridge.hpp @@ -0,0 +1,7789 @@ +// https://github.com/kunitoki/LuaBridge3 +// Copyright 2021, Lucio Asnaghi +// SPDX-License-Identifier: MIT + +// clang-format off + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Begin File: Source/LuaBridge/detail/Config.h + +// https://github.com/kunitoki/LuaBridge3 +// Copyright 2020, Lucio Asnaghi +// Copyright 2020, Dmitry Tarakanov +// Copyright 2019, George Tokmaji +// SPDX-License-Identifier: MIT + +#if !(__cplusplus >= 201703L || (defined(_MSC_VER) && _HAS_CXX17)) +#error LuaBridge 3 requires a compliant C++17 compiler, or C++17 has not been enabled ! +#endif + +#if defined(_MSC_VER) +#if _CPPUNWIND || _HAS_EXCEPTIONS +#define LUABRIDGE_HAS_EXCEPTIONS 1 +#else +#define LUABRIDGE_HAS_EXCEPTIONS 0 +#endif +#elif defined(__clang__) +#if __EXCEPTIONS && __has_feature(cxx_exceptions) +#define LUABRIDGE_HAS_EXCEPTIONS 1 +#else +#define LUABRIDGE_HAS_EXCEPTIONS 0 +#endif +#elif defined(__GNUC__) +#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) +#define LUABRIDGE_HAS_EXCEPTIONS 1 +#else +#define LUABRIDGE_HAS_EXCEPTIONS 0 +#endif +#endif + +// End File: Source/LuaBridge/detail/Config.h + +// Begin File: Source/LuaBridge/detail/LuaHelpers.h + +// https://github.com/kunitoki/LuaBridge3 +// Copyright 2020, Lucio Asnaghi +// Copyright 2012, Vinnie Falco +// Copyright 2007, Nathan Reed +// SPDX-License-Identifier: MIT + +namespace luabridge { + +// These are for Lua versions prior to 5.2.0. +#if LUA_VERSION_NUM < 502 + +using lua_Unsigned = lua_Integer; + +inline int lua_absindex(lua_State* L, int idx) +{ + if (idx > LUA_REGISTRYINDEX && idx < 0) + return lua_gettop(L) + idx + 1; + else + return idx; +} + +inline void lua_rawgetp(lua_State* L, int idx, void const* p) +{ + idx = lua_absindex(L, idx); + lua_pushlightuserdata(L, const_cast(p)); + lua_rawget(L, idx); +} + +inline void lua_rawsetp(lua_State* L, int idx, void const* p) +{ + idx = lua_absindex(L, idx); + luaL_checkstack(L, 1, "not enough stack slots"); + lua_pushlightuserdata(L, const_cast(p)); + lua_insert(L, -2); + lua_rawset(L, idx); +} + +#define LUA_OPEQ 1 +#define LUA_OPLT 2 +#define LUA_OPLE 3 + +inline int lua_compare(lua_State* L, int idx1, int idx2, int op) +{ + switch (op) + { + case LUA_OPEQ: + return lua_equal(L, idx1, idx2); + break; + + case LUA_OPLT: + return lua_lessthan(L, idx1, idx2); + break; + + case LUA_OPLE: + return lua_equal(L, idx1, idx2) || lua_lessthan(L, idx1, idx2); + break; + + default: + return 0; + }; +} + +inline int get_length(lua_State* L, int idx) +{ + return int(lua_objlen(L, idx)); +} + +#else +inline int get_length(lua_State* L, int idx) +{ + lua_len(L, idx); + int len = int(luaL_checknumber(L, -1)); + lua_pop(L, 1); + return len; +} + +#endif + +#ifndef LUA_OK +#define LUABRIDGE_LUA_OK 0 +#else +#define LUABRIDGE_LUA_OK LUA_OK +#endif + +/** + * @brief Helper for unused vars. + */ +template +constexpr void unused(Args&&...) +{ +} + +/** + * @brief Helper to throw or return an error code. + */ +template +std::error_code throw_or_error_code(ErrorType error) +{ +#if LUABRIDGE_HAS_EXCEPTIONS + throw T(makeErrorCode(error).message().c_str()); +#else + return makeErrorCode(error); +#endif +} + +template +std::error_code throw_or_error_code(lua_State* L, ErrorType error) +{ +#if LUABRIDGE_HAS_EXCEPTIONS + throw T(L, makeErrorCode(error)); +#else + return (void)L, makeErrorCode(error); +#endif +} + +/** + * @brief Helper to throw or assert. + */ +template +void throw_or_assert(Args&&... args) +{ +#if LUABRIDGE_HAS_EXCEPTIONS + throw T(std::forward(args)...); +#else + unused(std::forward(args)...); + assert(false); +#endif +} + +/** + * @brief Helper to set unsigned. + */ +template +void pushunsigned(lua_State* L, T value) +{ +#if LUA_VERSION_NUM != 502 + lua_pushinteger(L, static_cast(value)); +#else + lua_pushunsigned(L, static_cast(value)); +#endif +} + +/** + * @brief Get a table value, bypassing metamethods. + */ +inline void rawgetfield(lua_State* L, int index, char const* key) +{ + assert(lua_istable(L, index)); + index = lua_absindex(L, index); + lua_pushstring(L, key); + lua_rawget(L, index); +} + +/** + * @brief Set a table value, bypassing metamethods. + */ +inline void rawsetfield(lua_State* L, int index, char const* key) +{ + assert(lua_istable(L, index)); + index = lua_absindex(L, index); + lua_pushstring(L, key); + lua_insert(L, -2); + lua_rawset(L, index); +} + +/** + * @brief Returns true if the value is a full userdata (not light). + */ +[[nodiscard]] inline bool isfulluserdata(lua_State* L, int index) +{ + return lua_isuserdata(L, index) && !lua_islightuserdata(L, index); +} + +/** + * @brief Test lua_State objects for global equality. + * + * This can determine if two different lua_State objects really point + * to the same global state, such as when using coroutines. + * + * @note This is used for assertions. + */ +[[nodiscard]] inline bool equalstates(lua_State* L1, lua_State* L2) +{ + return lua_topointer(L1, LUA_REGISTRYINDEX) == lua_topointer(L2, LUA_REGISTRYINDEX); +} + +/** + * @brief Return an aligned pointer of type T. + */ +template +[[nodiscard]] T* align(void* ptr) noexcept +{ + auto address = reinterpret_cast(ptr); + + auto offset = address % alignof(T); + auto aligned_address = (offset == 0) ? address : (address + alignof(T) - offset); + + return reinterpret_cast(aligned_address); +} + +/** + * @brief Return the space needed to align the type T on an unaligned address. + */ +template +[[nodiscard]] size_t maximum_space_needed_to_align() noexcept +{ + return sizeof(T) + alignof(T) - 1; +} + +/** + * @brief Allocate lua userdata taking into account alignment. + * + * Using this instead of lua_newuserdata directly prevents alignment warnings on 64bits platforms. + */ +template +void* lua_newuserdata_aligned(lua_State* L, Args&&... args) +{ + void* pointer = lua_newuserdata(L, maximum_space_needed_to_align()); + + T* aligned = align(pointer); + + new (aligned) T(std::forward(args)...); + + return pointer; +} + +/** + * @brief Deallocate lua userdata taking into account alignment. + */ +template +int lua_deleteuserdata_aligned(lua_State* L) +{ + assert(isfulluserdata(L, 1)); + + T* aligned = align(lua_touserdata(L, 1)); + aligned->~T(); + + return 0; +} + +/** + * @brief Helper to write a lua string error. + */ +inline void writestringerror(const char* fmt, const char* text) +{ + fprintf(stderr, fmt, text); + fflush(stderr); +} + +} // namespace luabridge + +// End File: Source/LuaBridge/detail/LuaHelpers.h + +// Begin File: Source/LuaBridge/detail/Errors.h + +// https://github.com/vinniefalco/LuaBridge +// Copyright 2021, Lucio Asnaghi +// SPDX-License-Identifier: MIT + +namespace luabridge { + +//================================================================================================= +/** + * @brief LuaBridge error codes. + */ +enum class ErrorCode +{ + ClassNotRegistered = 1, + + LuaFunctionCallFailed, +}; + +//================================================================================================= +namespace detail { +struct ErrorCategory : std::error_category +{ + const char* name() const noexcept override + { + return "luabridge"; + } + + std::string message(int ev) const override + { + switch (static_cast(ev)) + { + case ErrorCode::ClassNotRegistered: + return "The class is not registered in LuaBridge"; + + case ErrorCode::LuaFunctionCallFailed: + return "The lua function invocation raised an error"; + + default: + return "Unknown error"; + } + } + + static const ErrorCategory& getInstance() noexcept + { + static ErrorCategory category; + return category; + } +}; +} // namespace detail + +//================================================================================================= +/** + * @brief Construct an error code from the error enum. + */ +inline std::error_code makeErrorCode(ErrorCode e) +{ + return { static_cast(e), detail::ErrorCategory::getInstance() }; +} + +} // namespace luabridge + +namespace std { +template <> struct is_error_code_enum : true_type {}; +} // namespace std + +// End File: Source/LuaBridge/detail/Errors.h + +// Begin File: Source/LuaBridge/detail/LuaException.h + +// https://github.com/kunitoki/LuaBridge3 +// Copyright 2021, Lucio Asnaghi +// Copyright 2012, Vinnie Falco +// Copyright 2008, Nigel Atkinson +// SPDX-License-Identifier: MIT + +namespace luabridge { + +//================================================================================================ +class LuaException : public std::exception +{ +public: + //============================================================================================= + /** + * @brief Construct a LuaException after a lua_pcall(). + * + * Assumes the error string is on top of the stack, but provides a generic error message otherwise. + */ + LuaException(lua_State* L, std::error_code code) + : m_L(L) + , m_code(code) + { + } + + ~LuaException() noexcept override + { + } + + //============================================================================================= + /** + * @brief Return the error message. + */ + const char* what() const noexcept override + { + return m_what.c_str(); + } + + //============================================================================================= + /** + * @brief Throw an exception or raises a luaerror when exceptions are disabled. + * + * This centralizes all the exceptions thrown, so that we can set breakpoints before the stack is + * unwound, or otherwise customize the behavior. + */ + template + static void raise(const Exception& e) + { + assert(areExceptionsEnabled()); + +#if LUABRIDGE_HAS_EXCEPTIONS + throw e; +#else + unused(e); + + std::abort(); +#endif + } + + //============================================================================================= + /** + * @brief Check if exceptions are enabled. + */ + static bool areExceptionsEnabled() noexcept + { + return exceptionsEnabled(); + } + + /** + * @brief Initializes error handling. + * + * Subsequent Lua errors are translated to C++ exceptions, or logging and abort if exceptions are disabled. + */ + static void enableExceptions(lua_State* L) noexcept + { + exceptionsEnabled() = true; + + lua_atpanic(L, panicHandlerCallback); + } + +private: + struct FromLua {}; + + LuaException(lua_State* L, std::error_code code, FromLua) + : m_L(L) + , m_code(code) + { + whatFromStack(); + } + + void whatFromStack() + { + std::stringstream ss; + + const char* errorText = nullptr; + + if (lua_gettop(m_L) > 0) + { + errorText = lua_tostring(m_L, -1); + lua_pop(m_L, 1); + } + + ss << (errorText ? errorText : "Unknown error") << " (code=" << m_code.message() << ")"; + + m_what = std::move(ss).str(); + } + + static int panicHandlerCallback(lua_State* L) + { +#if LUABRIDGE_HAS_EXCEPTIONS + throw LuaException(L, makeErrorCode(ErrorCode::LuaFunctionCallFailed), FromLua{}); +#else + unused(L); + + std::abort(); +#endif + } + + static bool& exceptionsEnabled() + { + static bool areExceptionsEnabled = false; + return areExceptionsEnabled; + } + + lua_State* m_L = nullptr; + std::error_code m_code; + std::string m_what; +}; + +//================================================================================================= +/** + * @brief Initializes error handling using C++ exceptions. + * + * Subsequent Lua errors are translated to C++ exceptions. It aborts the application if called when no exceptions. + */ +inline void enableExceptions(lua_State* L) noexcept +{ +#if LUABRIDGE_HAS_EXCEPTIONS + LuaException::enableExceptions(L); +#else + unused(L); + + assert(false); // Never call this function when exceptions are not enabled. +#endif +} + +} // namespace luabridge + +// End File: Source/LuaBridge/detail/LuaException.h + +// Begin File: Source/LuaBridge/detail/ClassInfo.h + +// https://github.com/kunitoki/LuaBridge3 +// Copyright 2020, Lucio Asnaghi +// Copyright 2020, Dmitry Tarakanov +// Copyright 2012, Vinnie Falco +// SPDX-License-Identifier: MIT + +namespace luabridge { +namespace detail { + +//================================================================================================= +/** + * @brief A unique key for a type name in a metatable. + */ +inline const void* getTypeKey() noexcept +{ + return reinterpret_cast(0x71); +} + +//================================================================================================= +/** + * @brief The key of a const table in another metatable. + */ +inline const void* getConstKey() noexcept +{ + return reinterpret_cast(0xc07); +} + +//================================================================================================= +/** + * @brief The key of a class table in another metatable. + */ +inline const void* getClassKey() noexcept +{ + return reinterpret_cast(0xc1a); +} + +//================================================================================================= +/** + * @brief The key of a propget table in another metatable. + */ +inline const void* getPropgetKey() noexcept +{ + return reinterpret_cast(0x6e7); +} + +//================================================================================================= +/** + * @brief The key of a propset table in another metatable. + */ +inline const void* getPropsetKey() noexcept +{ + return reinterpret_cast(0x5e7); +} + +//================================================================================================= +/** + * @brief The key of a static table in another metatable. + */ +inline const void* getStaticKey() noexcept +{ + return reinterpret_cast(0x57a); +} + +//================================================================================================= +/** + * @brief The key of a parent table in another metatable. + */ +inline const void* getParentKey() noexcept +{ + return reinterpret_cast(0xdad); +} + +//================================================================================================= +/** + * @brief Get the key for the static table in the Lua registry. + * + * The static table holds the static data members, static properties, and static member functions for a class. + */ +template +const void* getStaticRegistryKey() noexcept +{ + static char value; + return std::addressof(value); +} + +//================================================================================================= +/** + * @brief Get the key for the class table in the Lua registry. + * + * The class table holds the data members, properties, and member functions of a class. Read-only data and properties, and const + * member functions are also placed here (to save a lookup in the const table). + */ +template +const void* getClassRegistryKey() noexcept +{ + static char value; + return std::addressof(value); +} + +//================================================================================================= +/** + * @brief Get the key for the const table in the Lua registry. + * + * The const table holds read-only data members and properties, and const member functions of a class. + */ +template +const void* getConstRegistryKey() noexcept +{ + static char value; + return std::addressof(value); +} + +} // namespace detail +} // namespace luabridge + +// End File: Source/LuaBridge/detail/ClassInfo.h + +// Begin File: Source/LuaBridge/detail/TypeTraits.h + +// https://github.com/kunitoki/LuaBridge3 +// Copyright 2020, Lucio Asnaghi +// Copyright 2019, Dmitry Tarakanov +// Copyright 2012, Vinnie Falco +// SPDX-License-Identifier: MIT + +namespace luabridge { + +//================================================================================================= +/** + * @brief Container traits. + * + * Unspecialized ContainerTraits has the isNotContainer typedef for SFINAE. All user defined containers must supply an appropriate + * specialization for ContinerTraits (without the alias isNotContainer). The containers that come with LuaBridge also come with the + * appropriate ContainerTraits specialization. + * + * @note See the corresponding declaration for details. + * + * A specialization of ContainerTraits for some generic type ContainerType looks like this: + * + * @code + * + * template + * struct ContainerTraits> + * { + * using Type = T; + * + * static ContainerType construct(T* c) + * { + * return c; // Implementation-dependent on ContainerType + * } + * + * static T* get(const ContainerType& c) + * { + * return c.get(); // Implementation-dependent on ContainerType + * } + * }; + * + * @endcode + */ +template +struct ContainerTraits +{ + using IsNotContainer = bool; + + using Type = T; +}; + +/** + * @brief Register shared_ptr support as container. + * + * @tparam T Class that is hold by the shared_ptr, must inherit from std::enable_shared_from_this. + */ +template +struct ContainerTraits> +{ + static_assert(std::is_base_of_v, T>); + + using Type = T; + + static std::shared_ptr construct(T* t) + { + return t->shared_from_this(); + } + + static T* get(const std::shared_ptr& c) + { + return c.get(); + } +}; + +namespace detail { + +//================================================================================================= +/** + * @brief Determine if type T is a container. + * + * To be considered a container, there must be a specialization of ContainerTraits with the required fields. + */ +template +class IsContainer +{ +private: + typedef char yes[1]; // sizeof (yes) == 1 + typedef char no[2]; // sizeof (no) == 2 + + template + static constexpr no& test(typename C::IsNotContainer*); + + template + static constexpr yes& test(...); + +public: + static constexpr bool value = sizeof(test>(0)) == sizeof(yes); +}; + +} // namespace detail +} // namespace luabridge + +// End File: Source/LuaBridge/detail/TypeTraits.h + +// Begin File: Source/LuaBridge/detail/Userdata.h + +// https://github.com/kunitoki/LuaBridge3 +// Copyright 2020, Lucio Asnaghi +// Copyright 2019, Dmitry Tarakanov +// Copyright 2012, Vinnie Falco +// SPDX-License-Identifier: MIT + +namespace luabridge { +namespace detail { + +//================================================================================================= +/** + * @brief Return the identity pointer for our lightuserdata tokens. + * + * Because of Lua's dynamic typing and our improvised system of imposing C++ class structure, there is the possibility that executing + * scripts may knowingly or unknowingly cause invalid data to get passed to the C functions created by LuaBridge. + * + * In particular, our security model addresses the following: + * + * 1. Scripts cannot create a userdata (ignoring the debug lib). + * + * 2. Scripts cannot create a lightuserdata (ignoring the debug lib). + * + * 3. Scripts cannot set the metatable on a userdata. + */ + +/** + * @brief Interface to a class pointer retrievable from a userdata. + */ +class Userdata +{ +private: + //============================================================================================= + /** + * @brief Validate and retrieve a Userdata on the stack. + * + * The Userdata must exactly match the corresponding class table or const table, or else a Lua error is raised. This is used for the + * __gc metamethod. + */ + static Userdata* getExactClass(lua_State* L, int index, const void* classKey) + { + return (void)classKey, static_cast(lua_touserdata(L, lua_absindex(L, index))); + } + + //============================================================================================= + /** + * @brief Validate and retrieve a Userdata on the stack. + * + * The Userdata must be derived from or the same as the given base class, identified by the key. If canBeConst is false, generates + * an error if the resulting Userdata represents to a const object. We do the type check first so that the error message is informative. + */ + static Userdata* getClass(lua_State* L, + int index, + const void* registryConstKey, + const void* registryClassKey, + bool canBeConst) + { + index = lua_absindex(L, index); + + lua_getmetatable(L, index); // Stack: object metatable (ot) | nil + if (!lua_istable(L, -1)) + { + lua_rawgetp(L, LUA_REGISTRYINDEX, registryClassKey); // Stack: registry metatable (rt) | nil + return throwBadArg(L, index); + } + + lua_rawgetp(L, -1, getConstKey()); // Stack: ot | nil, const table (co) | nil + assert(lua_istable(L, -1) || lua_isnil(L, -1)); + + // If const table is NOT present, object is const. Use non-const registry table + // if object cannot be const, so constness validation is done automatically. + // E.g. nonConstFn (constObj) + // -> canBeConst = false, isConst = true + // -> 'Class' registry table, 'const Class' object table + // -> 'expected Class, got const Class' + bool isConst = lua_isnil(L, -1); // Stack: ot | nil, nil, rt + if (isConst && canBeConst) + { + lua_rawgetp(L, LUA_REGISTRYINDEX, registryConstKey); // Stack: ot, nil, rt + } + else + { + lua_rawgetp(L, LUA_REGISTRYINDEX, registryClassKey); // Stack: ot, co, rt + } + + lua_insert(L, -3); // Stack: rt, ot, co | nil + lua_pop(L, 1); // Stack: rt, ot + + for (;;) + { + if (lua_rawequal(L, -1, -2)) // Stack: rt, ot + { + lua_pop(L, 2); // Stack: - + return static_cast(lua_touserdata(L, index)); + } + + // Replace current metatable with it's base class. + lua_rawgetp(L, -1, getParentKey()); // Stack: rt, ot, parent ot (pot) | nil + + if (lua_isnil(L, -1)) // Stack: rt, ot, nil + { + // Drop the object metatable because it may be some parent metatable + lua_pop(L, 2); // Stack: rt + return throwBadArg(L, index); + } + + lua_remove(L, -2); // Stack: rt, pot + } + + // no return + } + + static bool isInstance(lua_State* L, int index, const void* registryClassKey) + { + index = lua_absindex(L, index); + + int result = lua_getmetatable(L, index); // Stack: object metatable (ot) | nothing + if (result == 0) + return false; // Nothing was pushed on the stack + + if (!lua_istable(L, -1)) + { + lua_pop(L, 1); // Stack: - + return false; + } + + lua_rawgetp(L, LUA_REGISTRYINDEX, registryClassKey); // Stack: ot, rt + lua_insert(L, -2); // Stack: rt, ot + + for (;;) + { + if (lua_rawequal(L, -1, -2)) // Stack: rt, ot + { + lua_pop(L, 2); // Stack: - + return true; + } + + // Replace current metatable with it's base class. + lua_rawgetp(L, -1, getParentKey()); // Stack: rt, ot, parent ot (pot) | nil + + if (lua_isnil(L, -1)) // Stack: rt, ot, nil + { + lua_pop(L, 3); // Stack: - + return false; + } + + lua_remove(L, -2); // Stack: rt, pot + } + } + + static Userdata* throwBadArg(lua_State* L, int index) + { + assert(lua_istable(L, -1) || lua_isnil(L, -1)); // Stack: rt | nil + + const char* expected = 0; + if (lua_isnil(L, -1)) // Stack: nil + { + expected = "unregistered class"; + } + else + { + lua_rawgetp(L, -1, getTypeKey()); // Stack: rt, registry type + expected = lua_tostring(L, -1); + } + + const char* got = 0; + if (lua_isuserdata(L, index)) + { + lua_getmetatable(L, index); // Stack: ..., ot | nil + if (lua_istable(L, -1)) // Stack: ..., ot + { + lua_rawgetp(L, -1, getTypeKey()); // Stack: ..., ot, object type | nil + if (lua_isstring(L, -1)) + { + got = lua_tostring(L, -1); + } + } + } + + if (!got) + { + got = lua_typename(L, lua_type(L, index)); + } + + luaL_argerror(L, index, lua_pushfstring(L, "%s expected, got %s", expected, got)); + return 0; + } + +public: + virtual ~Userdata() {} + + //============================================================================================= + /** + * @brief Returns the Userdata* if the class on the Lua stack matches. + * + * If the class does not match, a Lua error is raised. + * + * @tparam T A registered user class. + * + * @param L A Lua state. + * @param index The index of an item on the Lua stack. + * + * @return A userdata pointer if the class matches. + */ + template + static Userdata* getExact(lua_State* L, int index) + { + return getExactClass(L, index, detail::getClassRegistryKey()); + } + + //============================================================================================= + /** + * @brief Get a pointer to the class from the Lua stack. + * + * If the object is not the class or a subclass, or it violates the const-ness, a Lua error is raised. + * + * @tparam T A registered user class. + * + * @param L A Lua state. + * @param index The index of an item on the Lua stack. + * @param canBeConst TBD + * + * @return A pointer if the class and constness match. + */ + template + static T* get(lua_State* L, int index, bool canBeConst) + { + if (lua_isnil(L, index)) + return nullptr; + + return static_cast(getClass(L, + index, + detail::getConstRegistryKey(), + detail::getClassRegistryKey(), + canBeConst) + ->getPointer()); + } + + template + static bool isInstance(lua_State* L, int index) + { + return isInstance(L, index, detail::getClassRegistryKey()); + } + +protected: + Userdata() = default; + + /** + * @brief Get an untyped pointer to the contained class. + */ + void* getPointer() const noexcept + { + return m_p; + } + + void* m_p = nullptr; // subclasses must set this +}; + +//================================================================================================= +/** + * @brief Wraps a class object stored in a Lua userdata. + * + * The lifetime of the object is managed by Lua. The object is constructed inside the userdata using placement new. + */ +template +class UserdataValue : public Userdata +{ +public: + /** + * @brief Push a T via placement new. + * + * The caller is responsible for calling placement new using the returned uninitialized storage. + * + * @param L A Lua state. + * + * @return An object referring to the newly created userdata value. + */ + static UserdataValue* place(lua_State* L, std::error_code& ec) + { + auto* ud = new (lua_newuserdata(L, sizeof(UserdataValue))) UserdataValue(); + + lua_rawgetp(L, LUA_REGISTRYINDEX, detail::getClassRegistryKey()); + + if (!lua_istable(L, -1)) + { + lua_pop(L, 1); // possibly: a nil + + ud->~UserdataValue(); + + ec = throw_or_error_code(L, ErrorCode::ClassNotRegistered); + + return nullptr; + } + + lua_setmetatable(L, -2); + + return ud; + } + + /** + * @brief Push T via copy construction from U. + * + * @tparam U A container type. + * + * @param L A Lua state. + * @param u A container object l-value reference. + * @param ec Error code that will be set in case of failure to push on the lua stack. + */ + template + static bool push(lua_State* L, const U& u, std::error_code& ec) + { + auto* ud = place(L, ec); + + if (!ud) + return false; + + new (ud->getObject()) U(u); + + ud->commit(); + + return true; + } + + /** + * @brief Push T via move construction from U. + * + * @tparam U A container type. + * + * @param L A Lua state. + * @param u A container object r-value reference. + * @param ec Error code that will be set in case of failure to push on the lua stack. + */ + template + static bool push(lua_State* L, U&& u, std::error_code& ec) + { + auto* ud = place(L, ec); + + if (!ud) + return false; + + new (ud->getObject()) U(std::move(u)); + + ud->commit(); + + return true; + } + + /** + * @brief Confirm object construction. + */ + void commit() noexcept + { + m_p = getObject(); + } + + T* getObject() noexcept + { + // If this fails to compile it means you forgot to provide + // a Container specialization for your container! + return reinterpret_cast(&m_storage); + } + +private: + /** + * @brief Used for placement construction. + */ + UserdataValue() noexcept + { + m_p = nullptr; + } + + ~UserdataValue() + { + if (getPointer() != nullptr) + { + getObject()->~T(); + } + } + + UserdataValue(const UserdataValue&); + UserdataValue operator=(const UserdataValue&); + + std::aligned_storage_t m_storage; +}; + +//================================================================================================= +/** + * @brief Wraps a pointer to a class object inside a Lua userdata. + * + * The lifetime of the object is managed by C++. + */ +class UserdataPtr : public Userdata +{ +public: + /** + * @brief Push non-const pointer to object. + * + * @tparam T A user registered class. + * + * @param L A Lua state. + * @param p A pointer to the user class instance. + * @param ec Error code that will be set in case of failure to push on the lua stack. + */ + template + static bool push(lua_State* L, T* p, std::error_code& ec) + { + if (p) + return push(L, p, getClassRegistryKey(), ec); + + lua_pushnil(L); + return true; + } + + /** + * @brief Push const pointer to object. + * + * @tparam T A user registered class. + * + * @param L A Lua state. + * @param p A pointer to the user class instance. + * @param ec Error code that will be set in case of failure to push on the lua stack. + */ + template + static bool push(lua_State* L, const T* p, std::error_code& ec) + { + if (p) + return push(L, p, getConstRegistryKey(), ec); + + lua_pushnil(L); + return true; + } + +private: + /** + * @brief Push a pointer to object using metatable key. + */ + static bool push(lua_State* L, const void* p, const void* key, std::error_code& ec) + { + auto* ptr = new (lua_newuserdata(L, sizeof(UserdataPtr))) UserdataPtr(const_cast(p)); + + lua_rawgetp(L, LUA_REGISTRYINDEX, key); + + if (!lua_istable(L, -1)) + { + lua_pop(L, 1); // possibly: a nil + + ptr->~UserdataPtr(); + + ec = throw_or_error_code(L, ErrorCode::ClassNotRegistered); + + return false; + } + + lua_setmetatable(L, -2); + + return true; + } + + explicit UserdataPtr(void* p) + { + // Can't construct with a null pointer! + assert(p != nullptr); + + m_p = p; + } + + UserdataPtr(const UserdataPtr&); + UserdataPtr operator=(const UserdataPtr&); +}; + +//============================================================================ +/** + * @brief Wraps a container that references a class object. + * + * The template argument C is the container type, ContainerTraits must be specialized on C or else a compile error will result. + */ +template +class UserdataShared : public Userdata +{ +public: + ~UserdataShared() = default; + + /** + * @brief Construct from a container to the class or a derived class. + * + * @tparam U A container type. + * + * @param u A container object reference. + */ + template + explicit UserdataShared(const U& u) : m_c(u) + { + m_p = const_cast(reinterpret_cast((ContainerTraits::get(m_c)))); + } + + /** + * @brief Construct from a pointer to the class or a derived class. + * + * @tparam U A container type. + * + * @param u A container object pointer. + */ + template + explicit UserdataShared(U* u) : m_c(u) + { + m_p = const_cast(reinterpret_cast((ContainerTraits::get(m_c)))); + } + +private: + UserdataShared(const UserdataShared&); + UserdataShared& operator=(const UserdataShared&); + + C m_c; +}; + +//================================================================================================= +/** + * @brief SFINAE helper for non-const objects. + */ +template +struct UserdataSharedHelper +{ + using T = std::remove_const_t::Type>; + + static bool push(lua_State* L, const C& c, std::error_code& ec) + { + if (ContainerTraits::get(c) != nullptr) + { + auto* us = new (lua_newuserdata(L, sizeof(UserdataShared))) UserdataShared(c); + + lua_rawgetp(L, LUA_REGISTRYINDEX, getClassRegistryKey()); + + if (!lua_istable(L, -1)) + { + lua_pop(L, 1); // possibly: a nil + + us->~UserdataShared(); + + ec = throw_or_error_code(L, ErrorCode::ClassNotRegistered); + + return false; + } + + lua_setmetatable(L, -2); + } + else + { + lua_pushnil(L); + } + + return true; + } + + static bool push(lua_State* L, T* t, std::error_code& ec) + { + if (t) + { + auto* us = new (lua_newuserdata(L, sizeof(UserdataShared))) UserdataShared(t); + + lua_rawgetp(L, LUA_REGISTRYINDEX, getClassRegistryKey()); + + if (!lua_istable(L, -1)) + { + lua_pop(L, 1); // possibly: a nil + + us->~UserdataShared(); + + ec = throw_or_error_code(L, ErrorCode::ClassNotRegistered); + + return false; + } + + lua_setmetatable(L, -2); + } + else + { + lua_pushnil(L); + } + + return true; + } +}; + +/** + * @brief SFINAE helper for const objects. + */ +template +struct UserdataSharedHelper +{ + using T = std::remove_const_t::Type>; + + static bool push(lua_State* L, const C& c, std::error_code& ec) + { + if (ContainerTraits::get(c) != nullptr) + { + auto* us = new (lua_newuserdata(L, sizeof(UserdataShared))) UserdataShared(c); + + lua_rawgetp(L, LUA_REGISTRYINDEX, getConstRegistryKey()); + + if (!lua_istable(L, -1)) + { + lua_pop(L, 1); // possibly: a nil + + us->~UserdataShared(); + + ec = throw_or_error_code(L, ErrorCode::ClassNotRegistered); + + return false; + } + + lua_setmetatable(L, -2); + } + else + { + lua_pushnil(L); + } + + return true; + } + + static bool push(lua_State* L, T* t, std::error_code& ec) + { + if (t) + { + auto* us = new (lua_newuserdata(L, sizeof(UserdataShared))) UserdataShared(t); + + lua_rawgetp(L, LUA_REGISTRYINDEX, getConstRegistryKey()); + + if (!lua_istable(L, -1)) + { + lua_pop(L, 1); // possibly: a nil + + us->~UserdataShared(); + + ec = throw_or_error_code(L, ErrorCode::ClassNotRegistered); + + return false; + } + + lua_setmetatable(L, -2); + } + else + { + lua_pushnil(L); + } + + return true; + } +}; + +//================================================================================================= +/** + * @brief Pass by container. + * + * The container controls the object lifetime. Typically this will be a lifetime shared by C++ and Lua using a reference count. Because of type + * erasure, containers like std::shared_ptr will not work, unless the type hold by them is derived from std::enable_shared_from_this. + */ +template +struct StackHelper +{ + using ReturnType = std::remove_const_t::Type>; + + static bool push(lua_State* L, const T& t, std::error_code& ec) + { + return UserdataSharedHelper::Type>>::push(L, t, ec); + } + + static T get(lua_State* L, int index) + { + return ContainerTraits::construct(Userdata::get(L, index, true)); + } +}; + +/** + * @brief Pass by value. + * + * Lifetime is managed by Lua. A C++ function which accesses a pointer or reference to an object outside the activation record in which it was + * retrieved may result in undefined behavior if Lua garbage collected it. + */ +template +struct StackHelper +{ + static bool push(lua_State* L, const T& t, std::error_code& ec) + { + return UserdataValue::push(L, t, ec); + } + + static bool push(lua_State* L, T&& t, std::error_code& ec) + { + return UserdataValue::push(L, std::move(t), ec); + } + + static T const& get(lua_State* L, int index) + { + return *Userdata::get(L, index, true); + } +}; + +//================================================================================================= +/** + * @brief Lua stack conversions for pointers and references to class objects. + * + * Lifetime is managed by C++. Lua code which remembers a reference to the value may result in undefined behavior if C++ destroys the object. + * The handling of the const and volatile qualifiers happens in UserdataPtr. + */ +template +struct RefStackHelper +{ + using ReturnType = C; + using T = std::remove_const_t::Type>; + + static inline bool push(lua_State* L, const C& t, std::error_code& ec) + { + return UserdataSharedHelper::Type>>::push(L, t, ec); + } + + static ReturnType get(lua_State* L, int index) + { + return ContainerTraits::construct(Userdata::get(L, index, true)); + } +}; + +template +struct RefStackHelper +{ + using ReturnType = T&; + + static bool push(lua_State* L, const T& t, std::error_code& ec) + { + return UserdataPtr::push(L, &t, ec); + } + + static ReturnType get(lua_State* L, int index) + { + T* t = Userdata::get(L, index, true); + + if (!t) + luaL_error(L, "nil passed to reference"); + + return *t; + } +}; + +//================================================================================================= +/** + * @brief Trait class that selects whether to return a user registered class object by value or by reference. + */ +template +struct UserdataGetter +{ + using ReturnType = T*; + + static ReturnType get(lua_State* L, int index) + { + return Userdata::get(L, index, false); + } +}; + +template +struct UserdataGetter> +{ + using ReturnType = T; + + static ReturnType get(lua_State* L, int index) + { + return StackHelper::value>::get(L, index); + } +}; + +} // namespace detail + +//================================================================================================= +/** + * @brief Lua stack conversions for class objects passed by value. + */ +template +struct Stack +{ + using IsUserdata = void; + + using Getter = detail::UserdataGetter; + using ReturnType = typename Getter::ReturnType; + + static bool push(lua_State* L, const T& value, std::error_code& ec) + { + return detail::StackHelper::value>::push(L, value, ec); + } + + static bool push(lua_State* L, T&& value, std::error_code& ec) + { + return detail::StackHelper::value>::push(L, std::move(value), ec); + } + + static ReturnType get(lua_State* L, int index) + { + return Getter::get(L, index); + } + + static bool isInstance(lua_State* L, int index) + { + return detail::Userdata::isInstance(L, index); + } +}; + +namespace detail { + +//================================================================================================= +/** + * @brief Trait class indicating whether the parameter type must be a user registered class. + * + * The trait checks the existence of member type Stack::IsUserdata specialization for detection. + */ +template +struct IsUserdata : std::false_type +{ +}; + +template +struct IsUserdata::IsUserdata>> : std::true_type +{ +}; + +//================================================================================================= +/** + * @brief Trait class that selects a specific push/get implemenation. + */ +template +struct StackOpSelector; + +// pointer +template +struct StackOpSelector +{ + using ReturnType = T*; + + static bool push(lua_State* L, T* value, std::error_code& ec) { return UserdataPtr::push(L, value, ec); } + + static T* get(lua_State* L, int index) { return Userdata::get(L, index, false); } + + static bool isInstance(lua_State* L, int index) { return Userdata::isInstance(L, index); } +}; + +// pointer to const +template +struct StackOpSelector +{ + using ReturnType = const T*; + + static bool push(lua_State* L, const T* value, std::error_code& ec) { return UserdataPtr::push(L, value, ec); } + + static const T* get(lua_State* L, int index) { return Userdata::get(L, index, true); } + + static bool isInstance(lua_State* L, int index) { return Userdata::isInstance(L, index); } +}; + +// l-value reference +template +struct StackOpSelector +{ + using Helper = RefStackHelper::value>; + using ReturnType = typename Helper::ReturnType; + + static bool push(lua_State* L, T& value, std::error_code& ec) { return UserdataPtr::push(L, &value, ec); } + + static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); } + + static bool isInstance(lua_State* L, int index) { return Userdata::isInstance(L, index); } +}; + +// l-value reference to const +template +struct StackOpSelector +{ + using Helper = RefStackHelper::value>; + using ReturnType = typename Helper::ReturnType; + + static bool push(lua_State* L, const T& value, std::error_code& ec) { return Helper::push(L, value, ec); } + + static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); } + + static bool isInstance(lua_State* L, int index) { return Userdata::isInstance(L, index); } +}; + +} // namespace detail +} // namespace luabridge + +// End File: Source/LuaBridge/detail/Userdata.h + +// Begin File: Source/LuaBridge/detail/Stack.h + +// https://github.com/kunitoki/LuaBridge3 +// Copyright 2020, Lucio Asnaghi +// Copyright 2019, Dmitry Tarakanov +// Copyright 2012, Vinnie Falco +// Copyright 2007, Nathan Reed +// SPDX-License-Identifier: MIT + +namespace luabridge { + +//================================================================================================= +/** + * @brief Lua stack traits for C++ types. + * + * @tparam T A C++ type. + */ +template +struct Stack; + +//================================================================================================= +/** + * @brief Specialization for void type. + */ +template <> +struct Stack +{ + static bool push(lua_State*, std::error_code&) + { + return true; + } +}; + +//================================================================================================= +/** + * @brief Specialization for nullptr_t. + */ +template <> +struct Stack +{ + static bool push(lua_State* L, std::nullptr_t, std::error_code&) + { + lua_pushnil(L); + return true; + } + + static std::nullptr_t get(lua_State*, int) + { + return nullptr; + } + + static bool isInstance(lua_State* L, int index) + { + return lua_isnil(L, index); + } +}; + +//================================================================================================= +/** + * @brief Receive the lua_State* as an argument. + */ +template <> +struct Stack +{ + static lua_State* get(lua_State* L, int) + { + return L; + } +}; + +//================================================================================================= +/** + * @brief Stack specialization for a lua_CFunction. + */ +template <> +struct Stack +{ + static bool push(lua_State* L, lua_CFunction f, std::error_code&) + { + lua_pushcfunction(L, f); + return true; + } + + static lua_CFunction get(lua_State* L, int index) + { + return lua_tocfunction(L, index); + } + + static bool isInstance(lua_State* L, int index) + { + return lua_iscfunction(L, index); + } +}; + +//================================================================================================= +/** + * @brief Stack specialization for `bool`. + */ +template <> +struct Stack +{ + static bool push(lua_State* L, bool value, std::error_code&) + { + lua_pushboolean(L, value ? 1 : 0); + return true; + } + + static bool get(lua_State* L, int index) + { + return lua_toboolean(L, index) ? true : false; + } + + static bool isInstance(lua_State* L, int index) + { + return lua_isboolean(L, index); + } +}; + +//================================================================================================= +/** + * @brief Stack specialization for `std::byte`. + */ +template <> +struct Stack +{ + static bool push(lua_State* L, std::byte value, std::error_code&) + { + pushunsigned(L, std::to_integer(value)); + return true; + } + + static std::byte get(lua_State* L, int index) + { + return static_cast(luaL_checkinteger(L, index)); + } + + static bool isInstance(lua_State* L, int index) + { + return lua_type(L, index) == LUA_TNUMBER; + } +}; + +//================================================================================================= +/** + * @brief Stack specialization for `char`. + */ +template <> +struct Stack +{ + static bool push(lua_State* L, char value, std::error_code&) + { + lua_pushlstring(L, &value, 1); + return true; + } + + static char get(lua_State* L, int index) + { + return luaL_checkstring(L, index)[0]; + } + + static bool isInstance(lua_State* L, int index) + { + return lua_type(L, index) == LUA_TSTRING; + } +}; + +//================================================================================================= +/** + * @brief Stack specialization for `unsigned char`. + */ +template <> +struct Stack +{ + static bool push(lua_State* L, unsigned char value, std::error_code&) + { + pushunsigned(L, value); + return true; + } + + static unsigned char get(lua_State* L, int index) + { + return static_cast(luaL_checkinteger(L, index)); + } + + static bool isInstance(lua_State* L, int index) + { + return lua_type(L, index) == LUA_TNUMBER; + } +}; + +//================================================================================================= +/** + Stack specialization for `short`. +*/ +template <> +struct Stack +{ + static bool push(lua_State* L, short value, std::error_code&) + { + lua_pushinteger(L, static_cast(value)); + return true; + } + + static short get(lua_State* L, int index) + { + return static_cast(luaL_checkinteger(L, index)); + } + + static bool isInstance(lua_State* L, int index) + { + return lua_type(L, index) == LUA_TNUMBER; + } +}; + +//================================================================================================= +/** + * @brief Stack specialization for `unsigned short`. + */ +template <> +struct Stack +{ + static bool push(lua_State* L, unsigned short value, std::error_code&) + { + pushunsigned(L, value); + return true; + } + + static unsigned short get(lua_State* L, int index) + { + return static_cast(luaL_checkinteger(L, index)); + } + + static bool isInstance(lua_State* L, int index) + { + return lua_type(L, index) == LUA_TNUMBER; + } +}; + +//================================================================================================= +/** + * @brief Stack specialization for `int`. + */ +template <> +struct Stack +{ + static bool push(lua_State* L, int value, std::error_code&) + { + lua_pushinteger(L, static_cast(value)); + return true; + } + + static int get(lua_State* L, int index) + { + return static_cast(luaL_checkinteger(L, index)); + } + + static bool isInstance(lua_State* L, int index) + { + return lua_type(L, index) == LUA_TNUMBER; + } +}; + +//================================================================================================= +/** + * @brief Stack specialization for `unsigned int`. + */ +template <> +struct Stack +{ + static bool push(lua_State* L, unsigned int value, std::error_code&) + { + pushunsigned(L, value); + return true; + } + + static unsigned int get(lua_State* L, int index) + { + return static_cast(luaL_checkinteger(L, index)); + } + + static bool isInstance(lua_State* L, int index) + { + return lua_type(L, index) == LUA_TNUMBER; + } +}; + +//================================================================================================= +/** + * @brief Stack specialization for `long`. + */ +template <> +struct Stack +{ + static bool push(lua_State* L, long value, std::error_code&) + { + lua_pushinteger(L, static_cast(value)); + return true; + } + + static long get(lua_State* L, int index) + { + return static_cast(luaL_checkinteger(L, index)); + } + + static bool isInstance(lua_State* L, int index) + { + return lua_type(L, index) == LUA_TNUMBER; + } +}; + +//================================================================================================= +/** + * @brief Stack specialization for `unsigned long`. + */ +template <> +struct Stack +{ + static bool push(lua_State* L, unsigned long value, std::error_code&) + { + pushunsigned(L, value); + return true; + } + + static unsigned long get(lua_State* L, int index) + { + return static_cast(luaL_checkinteger(L, index)); + } + + static bool isInstance(lua_State* L, int index) + { + return lua_type(L, index) == LUA_TNUMBER; + } +}; + +//================================================================================================= +/** + * @brief Stack specialization for `long long`. + */ +template <> +struct Stack +{ + static bool push(lua_State* L, long long value, std::error_code&) + { + lua_pushinteger(L, static_cast(value)); + return true; + } + + static long long get(lua_State* L, int index) + { + return static_cast(luaL_checkinteger(L, index)); + } + + static bool isInstance(lua_State* L, int index) + { + return lua_type(L, index) == LUA_TNUMBER; + } +}; + +//================================================================================================= +/** + * @brief Stack specialization for `unsigned long long`. + */ +template <> +struct Stack +{ + static bool push(lua_State* L, unsigned long long value, std::error_code&) + { + pushunsigned(L, value); + return true; + } + + static unsigned long long get(lua_State* L, int index) + { + return static_cast(luaL_checkinteger(L, index)); + } + + static bool isInstance(lua_State* L, int index) + { + return lua_type(L, index) == LUA_TNUMBER; + } +}; + +//================================================================================================= +/** + * @brief Stack specialization for `float`. + */ +template <> +struct Stack +{ + static bool push(lua_State* L, float value, std::error_code&) + { + lua_pushnumber(L, static_cast(value)); + return true; + } + + static float get(lua_State* L, int index) + { + return static_cast(luaL_checknumber(L, index)); + } + + static bool isInstance(lua_State* L, int index) + { + return lua_type(L, index) == LUA_TNUMBER; + } +}; + +//================================================================================================= +/** + * @brief Stack specialization for `double`. + */ +template <> +struct Stack +{ + static bool push(lua_State* L, double value, std::error_code&) + { + lua_pushnumber(L, static_cast(value)); + return true; + } + + static double get(lua_State* L, int index) + { + return static_cast(luaL_checknumber(L, index)); + } + + static bool isInstance(lua_State* L, int index) + { + return lua_type(L, index) == LUA_TNUMBER; + } +}; + +//================================================================================================= +/** + * @brief Stack specialization for `long double`. + */ +template <> +struct Stack +{ + static bool push(lua_State* L, long double value, std::error_code&) + { + lua_pushnumber(L, static_cast(value)); + return true; + } + + static long double get(lua_State* L, int index) + { + return static_cast(luaL_checknumber(L, index)); + } + + static bool isInstance(lua_State* L, int index) + { + return lua_type(L, index) == LUA_TNUMBER; + } +}; + +//================================================================================================= +/** + * @brief Stack specialization for `const char*`. + */ +template <> +struct Stack +{ + static bool push(lua_State* L, const char* str, std::error_code&) + { + if (str != nullptr) + lua_pushstring(L, str); + else + lua_pushnil(L); + + return true; + } + + static const char* get(lua_State* L, int index) + { + return lua_isnil(L, index) ? nullptr : luaL_checkstring(L, index); + } + + static bool isInstance(lua_State* L, int index) + { + return lua_isnil(L, index) || lua_type(L, index) == LUA_TSTRING; + } +}; + +//================================================================================================= +/** + * @brief Stack specialization for `const char[N]` literals. + */ +namespace detail { +template +struct IsStringLiteral : std::is_same>]>> +{ +}; +} // namespace detail + +template +struct Stack::value>> +{ + static bool push(lua_State* L, const char (&str)[std::extent_v>], std::error_code&) + { + lua_pushlstring(L, str, std::extent_v>); + return true; + } +}; + +//================================================================================================= +/** + * @brief Stack specialization for `std::string_view`. + */ +template <> +struct Stack +{ + static bool push(lua_State* L, std::string_view str, std::error_code&) + { + lua_pushlstring(L, str.data(), str.size()); + return true; + } + + static std::string_view get(lua_State* L, int index) + { + return lua_isnil(L, index) ? std::string_view() : luaL_checkstring(L, index); + } + + static bool isInstance(lua_State* L, int index) + { + return lua_isnil(L, index) || lua_type(L, index) == LUA_TSTRING; + } +}; + +//================================================================================================= +/** + * @brief Stack specialization for `std::string`. + */ +template <> +struct Stack +{ + static bool push(lua_State* L, const std::string& str, std::error_code&) + { + lua_pushlstring(L, str.data(), str.size()); + return true; + } + + static std::string get(lua_State* L, int index) + { + std::size_t len; + if (lua_type(L, index) == LUA_TSTRING) + { + const char* str = lua_tolstring(L, index, &len); + return std::string(str, len); + } + + // Lua reference manual: + // If the value is a number, then lua_tolstring also changes the actual value in the stack + // to a string. (This change confuses lua_next when lua_tolstring is applied to keys during + // a table traversal.) + lua_pushvalue(L, index); + const char* str = lua_tolstring(L, -1, &len); + std::string string(str, len); + lua_pop(L, 1); // Pop the temporary string + return string; + } + + static bool isInstance(lua_State* L, int index) + { + return lua_type(L, index) == LUA_TSTRING; + } +}; + +//================================================================================================= +/** + * @brief Stack specialization for `std::tuple`. + */ +template +struct Stack> +{ + static bool push(lua_State* L, const std::tuple& t, std::error_code& ec) + { + lua_createtable(L, static_cast(Size), 0); + + return push_element(L, t, ec); + } + + static std::tuple get(lua_State* L, int index) + { + if (!lua_istable(L, index)) + luaL_error(L, "#%d argment must be a table", index); + + if (get_length(L, index) != Size) + luaL_error(L, "table size should be %d but is %d", Size, get_length(L, index)); + + std::tuple value; + + int absIndex = lua_absindex(L, index); + lua_pushnil(L); + + pop_element(L, absIndex, value); + + return value; + } + + static bool isInstance(lua_State* L, int index) + { + return lua_type(L, index) == LUA_TTABLE; + } + +private: + static constexpr std::size_t Size = std::tuple_size_v>; + + template + static auto push_element(lua_State*, const std::tuple&, std::error_code&) + -> std::enable_if_t + { + return true; + } + + template + static auto push_element(lua_State* L, const std::tuple& t, std::error_code& ec) + -> std::enable_if_t + { + using T = std::tuple_element_t>; + + lua_pushinteger(L, static_cast(Index + 1)); + + std::error_code push_ec; + bool result = Stack::push(L, std::get(t), push_ec); + if (! result) + { + lua_pushnil(L); + lua_settable(L, -3); + ec = push_ec; + return false; + } + + lua_settable(L, -3); + + return push_element(L, t, ec); + } + + template + static auto pop_element(lua_State*, int, std::tuple&) + -> std::enable_if_t + { + } + + template + static auto pop_element(lua_State* L, int absIndex, std::tuple& t) + -> std::enable_if_t + { + using T = std::tuple_element_t>; + + if (lua_next(L, absIndex) == 0) + return; + + std::get(t) = Stack::get(L, -1); + lua_pop(L, 1); + + pop_element(L, absIndex, t); + } +}; + +namespace detail { + +template +struct StackOpSelector +{ + using ReturnType = T; + + static bool push(lua_State* L, T& value, std::error_code& ec) { return Stack::push(L, value, ec); } + + static ReturnType get(lua_State* L, int index) { return Stack::get(L, index); } + + static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } +}; + +template +struct StackOpSelector +{ + using ReturnType = T; + + static bool push(lua_State* L, const T& value, std::error_code& ec) { return Stack::push(L, value, ec); } + + static ReturnType get(lua_State* L, int index) { return Stack::get(L, index); } + + static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } +}; + +template +struct StackOpSelector +{ + using ReturnType = T; + + static bool push(lua_State* L, T* value, std::error_code& ec) { return Stack::push(L, *value, ec); } + + static ReturnType get(lua_State* L, int index) { return Stack::get(L, index); } + + static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } +}; + +template +struct StackOpSelector +{ + using ReturnType = T; + + static bool push(lua_State* L, const T* value, std::error_code& ec) { return Stack::push(L, *value, ec); } + + static ReturnType get(lua_State* L, int index) { return Stack::get(L, index); } + + static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } +}; + +} // namespace detail + +template +struct Stack::value>> +{ + using Helper = detail::StackOpSelector::value>; + using ReturnType = typename Helper::ReturnType; + + static bool push(lua_State* L, T& value, std::error_code& ec) { return Helper::push(L, value, ec); } + + static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); } + + static bool isInstance(lua_State* L, int index) { return Helper::template isInstance(L, index); } +}; + +template +struct Stack::value>> +{ + using Helper = detail::StackOpSelector::value>; + using ReturnType = typename Helper::ReturnType; + + static bool push(lua_State* L, const T& value, std::error_code& ec) { return Helper::push(L, value, ec); } + + static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); } + + static bool isInstance(lua_State* L, int index) { return Helper::template isInstance(L, index); } +}; + +template +struct Stack +{ + using Helper = detail::StackOpSelector::value>; + using ReturnType = typename Helper::ReturnType; + + static bool push(lua_State* L, T* value, std::error_code& ec) { return Helper::push(L, value, ec); } + + static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); } + + static bool isInstance(lua_State* L, int index) { return Helper::template isInstance(L, index); } +}; + +template +struct Stack +{ + using Helper = detail::StackOpSelector::value>; + using ReturnType = typename Helper::ReturnType; + + static bool push(lua_State* L, const T* value, std::error_code& ec) { return Helper::push(L, value, ec); } + + static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); } + + static bool isInstance(lua_State* L, int index) { return Helper::template isInstance(L, index); } +}; + +//------------------------------------------------------------------------------ +/** + * @brief Push an object onto the Lua stack. + */ +template +bool push(lua_State* L, T t, std::error_code& ec) +{ + return Stack::push(L, t, ec); +} + +//------------------------------------------------------------------------------ +/** + * @brief Check whether an object on the Lua stack is of type T. + */ +template +bool isInstance(lua_State* L, int index) +{ + return Stack::isInstance(L, index); +} + +} // namespace luabridge + +// End File: Source/LuaBridge/detail/Stack.h + +// Begin File: Source/LuaBridge/Map.h + +// https://github.com/kunitoki/LuaBridge3 +// Copyright 2020, Lucio Asnaghi +// Copyright 2018, Dmitry Tarakanov +// SPDX-License-Identifier: MIT + +namespace luabridge { + +//================================================================================================= +/** + * @brief Stack specialization for `std::map`. + */ +template +struct Stack> +{ + using Type = std::map; + + static bool push(lua_State* L, const Type& map, std::error_code& ec) + { + const int initialStackSize = lua_gettop(L); + + lua_createtable(L, 0, static_cast(map.size())); + + for (auto it = map.begin(); it != map.end(); ++it) + { + std::error_code errorCodeKey; + if (! Stack::push(L, it->first, errorCodeKey)) + { + ec = errorCodeKey; + lua_pop(L, lua_gettop(L) - initialStackSize); + return false; + } + + std::error_code errorCodeValue; + if (! Stack::push(L, it->second, errorCodeValue)) + { + ec = errorCodeValue; + lua_pop(L, lua_gettop(L) - initialStackSize); + return false; + } + + lua_settable(L, -3); + } + + return true; + } + + static Type get(lua_State* L, int index) + { + if (!lua_istable(L, index)) + luaL_error(L, "#%d argument must be a table", index); + + Type map; + + int absIndex = lua_absindex(L, index); + lua_pushnil(L); + + while (lua_next(L, absIndex) != 0) + { + map.emplace(Stack::get(L, -2), Stack::get(L, -1)); + lua_pop(L, 1); + } + + return map; + } + + static bool isInstance(lua_State* L, int index) + { + return lua_istable(L, index); + } +}; + +} // namespace luabridge + +// End File: Source/LuaBridge/Map.h + +// Begin File: Source/LuaBridge/UnorderedMap.h + +// https://github.com/kunitoki/LuaBridge3 +// Copyright 2020, Lucio Asnaghi +// Copyright 2019, Dmitry Tarakanov +// SPDX-License-Identifier: MIT + +namespace luabridge { + +//================================================================================================= +/** + * @brief Stack specialization for `std::unordered_map`. + */ +template +struct Stack> +{ + using Type = std::unordered_map; + + static bool push(lua_State* L, const Type& map, std::error_code& ec) + { + const int initialStackSize = lua_gettop(L); + + lua_createtable(L, 0, static_cast(map.size())); + + for (auto it = map.begin(); it != map.end(); ++it) + { + std::error_code errorCodeKey; + if (! Stack::push(L, it->first, errorCodeKey)) + { + ec = errorCodeKey; + lua_pop(L, lua_gettop(L) - initialStackSize); + return false; + } + + std::error_code errorCodeValue; + if (! Stack::push(L, it->second, errorCodeValue)) + { + ec = errorCodeValue; + lua_pop(L, lua_gettop(L) - initialStackSize); + return false; + } + + lua_settable(L, -3); + } + + return true; + } + + static Type get(lua_State* L, int index) + { + if (!lua_istable(L, index)) + luaL_error(L, "#%d argument must be a table", index); + + Type map; + + int absIndex = lua_absindex(L, index); + lua_pushnil(L); + + while (lua_next(L, absIndex) != 0) + { + map.emplace(Stack::get(L, -2), Stack::get(L, -1)); + lua_pop(L, 1); + } + + return map; + } + + static bool isInstance(lua_State* L, int index) + { + return lua_istable(L, index); + } +}; + +} // namespace luabridge + +// End File: Source/LuaBridge/UnorderedMap.h + +// Begin File: Source/LuaBridge/Optional.h + +// https://github.com/kunitoki/LuaBridge3 +// Copyright 2020, Lucio Asnaghi +// SPDX-License-Identifier: MIT + +namespace luabridge { + +//================================================================================================= +/** + * @brief Stack specialization for `std::optional`. + */ +template +struct Stack> +{ + using Type = std::optional; + + static bool push(lua_State* L, const Type& value, std::error_code& ec) + { + if (value) + return Stack::push(L, *value, ec); + + lua_pushnil(L); + return true; + } + + static Type get(lua_State* L, int index) + { + if (lua_type(L, index) == LUA_TNIL) + return std::nullopt; + + return Stack::get(L, index); + } + + static bool isInstance(lua_State* L, int index) + { + return lua_isnil(L, index) || Stack::isInstance(L, index); + } +}; + +} // namespace luabridge + +// End File: Source/LuaBridge/Optional.h + +// Begin File: Source/LuaBridge/detail/FuncTraits.h + +// https://github.com/kunitoki/LuaBridge3 +// Copyright 2020, Lucio Asnaghi +// Copyright 2020, Dmitry Tarakanov +// Copyright 2019, George Tokmaji +// Copyright 2012, Vinnie Falco +// SPDX-License-Identifier: MIT + +namespace luabridge { +namespace detail { + +//================================================================================================= +/** + * @brief Generic function traits. + * + * @tparam IsMember True if the function is a member function pointer. + * @tparam IsConst True if the function is const. + * @tparam R Return type of the function. + * @tparam Args Arguments types as variadic parameter pack. + */ +template +struct function_traits_base +{ + using result_type = R; + + using argument_types = std::tuple; + + static constexpr auto arity = sizeof...(Args); + + static constexpr auto is_member = IsMember; + + static constexpr auto is_const = IsConst; +}; + +template +struct function_traits_impl; + +template +struct function_traits_impl : function_traits_base +{ +}; + +template +struct function_traits_impl : function_traits_base +{ +}; + +template +struct function_traits_impl : function_traits_base +{ +}; + +template +struct function_traits_impl : function_traits_base +{ +}; + +template +struct function_traits_impl : function_traits_base +{ +}; + +template +struct function_traits_impl : function_traits_base +{ +}; + +template +struct function_traits_impl : function_traits_base +{ +}; + +template +struct function_traits_impl : function_traits_base +{ +}; + +#if _MSC_VER && _M_IX86 // Windows: WINAPI (a.k.a. __stdcall) function pointers (32bit only). +template +struct function_traits_impl : function_traits_base +{ +}; + +template +struct function_traits_impl : function_traits_base +{ +}; + +template +struct function_traits_impl : function_traits_base +{ +}; + +template +struct function_traits_impl : function_traits_base +{ +}; + +template +struct function_traits_impl : function_traits_base +{ +}; + +template +struct function_traits_impl : function_traits_base +{ +}; + +template +struct function_traits_impl : function_traits_base +{ +}; + +template +struct function_traits_impl : function_traits_base +{ +}; +#endif + +template +struct functor_traits_impl : function_traits_impl +{ +}; + +//================================================================================================= +/** + * @brief Traits class for callable objects (e.g. function pointers, lambdas) + * + * @tparam F Callable object. + */ +template +struct function_traits : std::conditional_t, + detail::functor_traits_impl, + detail::function_traits_impl> +{ +}; + +//================================================================================================= +/** + * @brief Deduces the return type of a callble object. + * + * @tparam F Callable object. + */ +template +using function_result_t = typename function_traits::result_type; + +/** + * @brief Deduces the argument type of a callble object. + * + * @tparam I Argument index. + * @tparam F Callable object. + */ +template +using function_argument_t = std::tuple_element_t::argument_types>; + +/** + * @brief Deduces the arguments type of a callble object. + * + * @tparam F Callable object. + */ +template +using function_arguments_t = typename function_traits::argument_types; + +/** + * @brief An integral constant expression that gives the number of arguments accepted by the callable object. + * + * @tparam F Callable object. + */ +template +static constexpr std::size_t function_arity_v = function_traits::arity; + +/** + * @brief An boolean constant expression that checks if the callable object is a member function. + * + * @tparam F Callable object. + */ +template +static constexpr bool function_is_member_v = function_traits::is_member; + +/** + * @brief An boolean constant expression that checks if the callable object is const. + * + * @tparam F Callable object. + */ +template +static constexpr bool function_is_const_v = function_traits::is_const; + +//================================================================================================= +/** + * @brief Detect if we are a `std::function`. + * + * @tparam F Callable object. + */ +template +struct is_std_function : std::false_type +{ +}; + +template +struct is_std_function> : std::true_type +{ +}; + +template +struct is_std_function> : std::true_type +{ +}; + +template +static constexpr bool is_std_function_v = is_std_function::value; + +//================================================================================================= +/** + * @brief Reconstruct a function signature from return type and args. + */ +template +struct to_std_function_type +{ +}; + +template +struct to_std_function_type> +{ + using type = std::function; +}; + +template +using to_std_function_type_t = typename to_std_function_type::type; + +//================================================================================================= +/** + * @brief Simple make_tuple alternative that doesn't decay the types. + * + * @tparam Types Argument types that will compose the tuple. + */ +template +constexpr auto tupleize(Types&&... types) +{ + return std::tuple(std::forward(types)...); +} + +//================================================================================================= +/** + * @brief Make argument lists extracting them from the lua state, starting at a stack index. + * + * @tparam ArgsPack Arguments pack to extract from the lua stack. + * @tparam Start Start index where stack variables are located in the lua stack. + */ +template +auto make_arguments_list_impl(lua_State* L, std::index_sequence) +{ + return tupleize(Stack>::get(L, Start + Indices)...); +} + +template +auto make_arguments_list(lua_State* L) +{ + return make_arguments_list_impl(L, std::make_index_sequence>()); +} + +//================================================================================================= +/** + * @brief Helpers for iterating through tuple arguments, pushing each argument to the lua stack. + */ +template +auto push_arguments(lua_State*, std::tuple, std::error_code&) + -> std::enable_if_t +{ + return Index + 1; +} + +template +auto push_arguments(lua_State* L, std::tuple t, std::error_code& ec) + -> std::enable_if_t +{ + using T = std::tuple_element_t>; + + std::error_code pec; + bool result = Stack::push(L, std::get(t), pec); + if (! result) + { + ec = pec; + return Index + 1; + } + + return push_arguments(L, std::move(t), ec); +} + +//================================================================================================= +/** + * @brief Helpers for iterating through tuple arguments, popping each argument from the lua stack. + */ +template +auto pop_arguments(lua_State*, std::tuple&) + -> std::enable_if_t +{ + return sizeof...(Types); +} + +template +auto pop_arguments(lua_State* L, std::tuple& t) + -> std::enable_if_t +{ + using T = std::tuple_element_t>; + + std::get(t) = Stack::get(L, Start - Index); + + return pop_arguments(L, t); +} + +//================================================================================================= +/** + * @brief Remove first type from tuple. + */ +template +struct remove_first_type +{ +}; + +template +struct remove_first_type> +{ + using type = std::tuple; +}; + +template +using remove_first_type_t = typename remove_first_type::type; + +//================================================================================================= +/** + * @brief Function generator. + */ +template +struct function +{ + template + static int call(lua_State* L, F func) + { +#if LUABRIDGE_HAS_EXCEPTIONS + try + { +#endif + std::error_code ec; + bool result = Stack::push(L, std::apply(func, make_arguments_list(L)), ec); + if (! result) + return luaL_error(L, ec.message().c_str()); + + return 1; + +#if LUABRIDGE_HAS_EXCEPTIONS + } + catch (const std::exception& e) + { + return luaL_error(L, e.what()); + } + catch (...) + { + return luaL_error(L, "Error while calling function"); + } +#endif + } + + template + static int call(lua_State* L, T* ptr, F func) + { +#if LUABRIDGE_HAS_EXCEPTIONS + try + { +#endif + auto f = [ptr, func](auto&&... args) -> ReturnType { return (ptr->*func)(std::forward(args)...); }; + + std::error_code ec; + bool result = Stack::push(L, std::apply(f, make_arguments_list(L)), ec); + if (! result) + return luaL_error(L, ec.message().c_str()); + + return 1; + +#if LUABRIDGE_HAS_EXCEPTIONS + } + catch (const std::exception& e) + { + return luaL_error(L, e.what()); + } + catch (...) + { + return luaL_error(L, "Error while calling method"); + } +#endif + } +}; + +template +struct function +{ + template + static int call(lua_State* L, F func) + { +#if LUABRIDGE_HAS_EXCEPTIONS + try + { +#endif + std::apply(func, make_arguments_list(L)); + + return 0; + +#if LUABRIDGE_HAS_EXCEPTIONS + } + catch (const std::exception& e) + { + return luaL_error(L, e.what()); + } + catch (...) + { + return luaL_error(L, "Error while calling function"); + } +#endif + } + + template + static int call(lua_State* L, T* ptr, F func) + { +#if LUABRIDGE_HAS_EXCEPTIONS + try + { +#endif + auto f = [ptr, func](auto&&... args) { (ptr->*func)(std::forward(args)...); }; + + std::apply(f, make_arguments_list(L)); + + return 0; + +#if LUABRIDGE_HAS_EXCEPTIONS + } + catch (const std::exception& e) + { + return luaL_error(L, e.what()); + } + catch (...) + { + return luaL_error(L, "Error while calling method"); + } +#endif + } +}; + +//================================================================================================= +/** + * @brief Constructor generators. + * + * These templates call operator new with the contents of a type/value list passed to the constructor. Two versions of call() are provided. + * One performs a regular new, the other performs a placement new. + */ +template +struct constructor; + +template +struct constructor +{ + using empty = std::tuple<>; + + static T* call(const empty&) + { + return new T; + } + + static T* call(void* ptr, const empty&) + { + return new (ptr) T; + } +}; + +template +struct constructor +{ + static T* call(const Args& args) + { + auto alloc = [](auto&&... args) { return new T{ std::forward(args)... }; }; + + return std::apply(alloc, args); + } + + static T* call(void* ptr, const Args& args) + { + auto alloc = [ptr](auto&&... args) { return new (ptr) T{ std::forward(args)... }; }; + + return std::apply(alloc, args); + } +}; + +//================================================================================================= +/** + * @brief Factory generators. + */ +template +struct factory +{ + template + static T* call(void* ptr, const F& func, const Args& args) + { + auto alloc = [ptr, &func](auto&&... args) { return func(ptr, std::forward(args)...); }; + + return std::apply(alloc, args); + } + + template + static T* call(void* ptr, const F& func) + { + return func(ptr); + } +}; + +} // namespace detail +} // namespace luabridge + +// End File: Source/LuaBridge/detail/FuncTraits.h + +// Begin File: Source/LuaBridge/detail/CFunctions.h + +// https://github.com/kunitoki/LuaBridge3 +// Copyright 2020, Lucio Asnaghi +// Copyright 2019, Dmitry Tarakanov +// Copyright 2012, Vinnie Falco +// SPDX-License-Identifier: MIT + +namespace luabridge { +namespace detail { + +//================================================================================================= +/** + * @brief __index metamethod for a namespace or class static and non-static members. + * + * Retrieves functions from metatables and properties from propget tables. Looks through the class hierarchy if inheritance is present. + */ +inline int index_metamethod(lua_State* L) +{ + assert(lua_istable(L, 1) || lua_isuserdata(L, 1)); // Stack (further not shown): table | userdata, name + + lua_getmetatable(L, 1); // Stack: class/const table (mt) + assert(lua_istable(L, -1)); + + for (;;) + { + lua_pushvalue(L, 2); // Stack: mt, field name + lua_rawget(L, -2); // Stack: mt, field | nil + + if (lua_iscfunction(L, -1)) // Stack: mt, field + { + lua_remove(L, -2); // Stack: field + return 1; + } + + assert(lua_isnil(L, -1)); // Stack: mt, nil + lua_pop(L, 1); // Stack: mt + + lua_rawgetp(L, -1, getPropgetKey()); // Stack: mt, propget table (pg) + assert(lua_istable(L, -1)); + + lua_pushvalue(L, 2); // Stack: mt, pg, field name + lua_rawget(L, -2); // Stack: mt, pg, getter | nil + lua_remove(L, -2); // Stack: mt, getter | nil + + if (lua_iscfunction(L, -1)) // Stack: mt, getter + { + lua_remove(L, -2); // Stack: getter + lua_pushvalue(L, 1); // Stack: getter, table | userdata + lua_call(L, 1, 1); // Stack: value + return 1; + } + + assert(lua_isnil(L, -1)); // Stack: mt, nil + lua_pop(L, 1); // Stack: mt + + // It may mean that the field may be in const table and it's constness violation. + // Don't check that, just return nil + + // Repeat the lookup in the parent metafield, + // or return nil if the field doesn't exist. + lua_rawgetp(L, -1, getParentKey()); // Stack: mt, parent mt | nil + + if (lua_isnil(L, -1)) // Stack: mt, nil + { + lua_remove(L, -2); // Stack: nil + return 1; + } + + // Removethe metatable and repeat the search in the parent one. + assert(lua_istable(L, -1)); // Stack: mt, parent mt + lua_remove(L, -2); // Stack: parent mt + } + + // no return +} + +//================================================================================================= +/** + * @brief __newindex metamethod for non-static members. + * + * Retrieves properties from propset tables. + */ +inline int newindex_metamethod(lua_State* L, bool pushSelf) +{ + assert(lua_istable(L, 1) || lua_isuserdata(L, 1)); // Stack (further not shown): table | userdata, name, new value + + lua_getmetatable(L, 1); // Stack: metatable (mt) + assert(lua_istable(L, -1)); + + for (;;) + { + lua_rawgetp(L, -1, getPropsetKey()); // Stack: mt, propset table (ps) | nil + + if (lua_isnil(L, -1)) // Stack: mt, nil + { + lua_pop(L, 2); // Stack: - + return luaL_error(L, "No member named '%s'", lua_tostring(L, 2)); + } + + assert(lua_istable(L, -1)); + + lua_pushvalue(L, 2); // Stack: mt, ps, field name + lua_rawget(L, -2); // Stack: mt, ps, setter | nil + lua_remove(L, -2); // Stack: mt, setter | nil + + if (lua_iscfunction(L, -1)) // Stack: mt, setter + { + lua_remove(L, -2); // Stack: setter + if (pushSelf) + lua_pushvalue(L, 1); // Stack: setter, table | userdata + lua_pushvalue(L, 3); // Stack: setter, table | userdata, new value + lua_call(L, pushSelf ? 2 : 1, 0); // Stack: - + return 0; + } + + assert(lua_isnil(L, -1)); // Stack: mt, nil + lua_pop(L, 1); // Stack: mt + + lua_rawgetp(L, -1, getParentKey()); // Stack: mt, parent mt | nil + + if (lua_isnil(L, -1)) // Stack: mt, nil + { + lua_pop(L, 1); // Stack: - + return luaL_error(L, "No writable member '%s'", lua_tostring(L, 2)); + } + + assert(lua_istable(L, -1)); // Stack: mt, parent mt + lua_remove(L, -2); // Stack: parent mt + // Repeat the search in the parent + } + + // no return +} + +//================================================================================================= +/** + * @brief __newindex metamethod for objects. + */ +inline int newindex_object_metamethod(lua_State* L) +{ + return newindex_metamethod(L, true); +} + +//================================================================================================= +/** + * @brief __newindex metamethod for namespace or class static members. + * + * Retrieves properties from propset tables. + */ +inline int newindex_static_metamethod(lua_State* L) +{ + return newindex_metamethod(L, false); +} + +//================================================================================================= +/** + * @brief lua_CFunction to report an error writing to a read-only value. + * + * The name of the variable is in the first upvalue. + */ +inline int read_only_error(lua_State* L) +{ + std::string s; + + s = s + "'" + lua_tostring(L, lua_upvalueindex(1)) + "' is read-only"; + + return luaL_error(L, s.c_str()); +} + +//================================================================================================= +/** + * @brief __gc metamethod for a class. + */ +template +static int gc_metamethod(lua_State* L) +{ + Userdata* ud = Userdata::getExact(L, 1); + assert(ud); + + ud->~Userdata(); + + return 0; +} + +//================================================================================================= + +template +struct property_getter; + +/** + * @brief lua_CFunction to get a variable. + * + * This is used for global variables or class static data members. The pointer to the data is in the first upvalue. + */ +template +struct property_getter +{ + static int call(lua_State* L) + { + assert(lua_islightuserdata(L, lua_upvalueindex(1))); + + T* ptr = static_cast(lua_touserdata(L, lua_upvalueindex(1))); + assert(ptr != nullptr); + + std::error_code ec; + if (! Stack::push(L, *ptr, ec)) + luaL_error(L, ec.message().c_str()); + + return 1; + } +}; + +#if 0 +template +struct property_getter, void> +{ + static int call(lua_State* L) + { + assert(lua_islightuserdata(L, lua_upvalueindex(1))); + + std::reference_wrapper* ptr = static_cast*>(lua_touserdata(L, lua_upvalueindex(1))); + assert(ptr != nullptr); + + std::error_code ec; + if (! Stack::push(L, ptr->get(), ec)) + luaL_error(L, ec.message().c_str()); + + return 1; + } +}; +#endif + +/** + * @brief lua_CFunction to get a class data member. + * + * The pointer-to-member is in the first upvalue. The class userdata object is at the top of the Lua stack. + */ +template +struct property_getter +{ + static int call(lua_State* L) + { + C* c = Userdata::get(L, 1, true); + + T C::** mp = static_cast(lua_touserdata(L, lua_upvalueindex(1))); + +#if LUABRIDGE_HAS_EXCEPTIONS + try + { +#endif + std::error_code ec; + if (! Stack::push(L, c->**mp, ec)) + luaL_error(L, ec.message().c_str()); + +#if LUABRIDGE_HAS_EXCEPTIONS + } + catch (const std::exception& e) + { + luaL_error(L, e.what()); + } + catch (...) + { + luaL_error(L, "Error while getting property"); + } +#endif + + return 1; + } +}; + +/** + * @brief Helper function to push a property getter on a table at a specific index. + */ +inline void add_property_getter(lua_State* L, const char* name, int tableIndex) +{ + assert(name != nullptr); + assert(lua_istable(L, tableIndex)); + assert(lua_iscfunction(L, -1)); // Stack: getter + + lua_rawgetp(L, tableIndex, getPropgetKey()); // Stack: getter, propget table (pg) + lua_pushvalue(L, -2); // Stack: getter, pg, getter + rawsetfield(L, -2, name); // Stack: getter, pg + lua_pop(L, 2); // Stack: - +} + +//================================================================================================= + +template +struct property_setter; + +/** + * @brief lua_CFunction to set a variable. + * + * This is used for global variables or class static data members. The pointer to the data is in the first upvalue. + */ +template +struct property_setter +{ + static int call(lua_State* L) + { + assert(lua_islightuserdata(L, lua_upvalueindex(1))); + + T* ptr = static_cast(lua_touserdata(L, lua_upvalueindex(1))); + assert(ptr != nullptr); + + *ptr = Stack::get(L, 1); + + return 0; + } +}; + +#if 0 +template +struct property_setter, void> +{ + static int call(lua_State* L) + { + assert(lua_islightuserdata(L, lua_upvalueindex(1))); + + std::reference_wrapper* ptr = static_cast*>(lua_touserdata(L, lua_upvalueindex(1))); + assert(ptr != nullptr); + + ptr->get() = Stack::get(L, 1); + + return 0; + } +}; +#endif + +/** + * @brief lua_CFunction to set a class data member. + * + * The pointer-to-member is in the first upvalue. The class userdata object is at the top of the Lua stack. + */ +template +struct property_setter +{ + static int call(lua_State* L) + { + C* c = Userdata::get(L, 1, false); + + T C::** mp = static_cast(lua_touserdata(L, lua_upvalueindex(1))); + +#if LUABRIDGE_HAS_EXCEPTIONS + try + { +#endif + c->** mp = Stack::get(L, 2); + +#if LUABRIDGE_HAS_EXCEPTIONS + } + catch (const std::exception& e) + { + luaL_error(L, e.what()); + } + catch (...) + { + luaL_error(L, "Error while setting property"); + } +#endif + + return 0; + } +}; + +/** + * @brief Helper function to push a property setter on a table at a specific index. + */ +inline void add_property_setter(lua_State* L, const char* name, int tableIndex) +{ + assert(name != nullptr); + assert(lua_istable(L, tableIndex)); + assert(lua_iscfunction(L, -1)); // Stack: setter + + lua_rawgetp(L, tableIndex, getPropsetKey()); // Stack: setter, propset table (ps) + lua_pushvalue(L, -2); // Stack: setter, ps, setter + rawsetfield(L, -2, name); // Stack: setter, ps + lua_pop(L, 2); // Stack: - +} + +//================================================================================================= +/** + * @brief lua_CFunction to call a class member function with a return value. + * + * The member function pointer is in the first upvalue. The class userdata object is at the top of the Lua stack. + */ +template +int invoke_member_function(lua_State* L) +{ + using FnTraits = detail::function_traits; + + assert(isfulluserdata(L, lua_upvalueindex(1))); + + T* ptr = Userdata::get(L, 1, false); + + const F& func = *static_cast(lua_touserdata(L, lua_upvalueindex(1))); + assert(func != nullptr); + + return function::call(L, ptr, func); +} + +template +int invoke_const_member_function(lua_State* L) +{ + using FnTraits = detail::function_traits; + + assert(isfulluserdata(L, lua_upvalueindex(1))); + + const T* ptr = Userdata::get(L, 1, true); + + const F& func = *static_cast(lua_touserdata(L, lua_upvalueindex(1))); + assert(func != nullptr); + + return function::call(L, ptr, func); +} + +//================================================================================================= +/** + * @brief lua_CFunction to call a class member lua_CFunction. + * + * The member function pointer is in the first upvalue. The object userdata ('this') value is at top ot the Lua stack. + */ +template +int invoke_member_cfunction(lua_State* L) +{ + using F = int (T::*)(lua_State * L); + + assert(isfulluserdata(L, lua_upvalueindex(1))); + + T* t = Userdata::get(L, 1, false); + + const F& func = *static_cast(lua_touserdata(L, lua_upvalueindex(1))); + assert(func != nullptr); + + return (t->*func)(L); +} + +template +int invoke_const_member_cfunction(lua_State* L) +{ + using F = int (T::*)(lua_State * L) const; + + assert(isfulluserdata(L, lua_upvalueindex(1))); + + const T* t = Userdata::get(L, 1, true); + + const F& func = *static_cast(lua_touserdata(L, lua_upvalueindex(1))); + assert(func != nullptr); + + return (t->*func)(L); +} + +//================================================================================================= +/** + * @brief lua_CFunction to call on a object via function pointer. + * + * The proxy function pointer (lightuserdata) is in the first upvalue. The class userdata object is at the top of the Lua stack. + */ +template +int invoke_proxy_function(lua_State* L) +{ + using FnTraits = detail::function_traits; + + assert(lua_islightuserdata(L, lua_upvalueindex(1))); + + auto func = reinterpret_cast(lua_touserdata(L, lua_upvalueindex(1))); + assert(func != nullptr); + + return function::call(L, func); +} + +//================================================================================================= +/** + * @brief lua_CFunction to call on a object via functor (lambda wrapped in a std::function). + * + * The proxy std::function (lightuserdata) is in the first upvalue. The class userdata object is at the top of the Lua stack. + */ +template +int invoke_proxy_functor(lua_State* L) +{ + using FnTraits = detail::function_traits; + + assert(isfulluserdata(L, lua_upvalueindex(1))); + + auto& func = *align(lua_touserdata(L, lua_upvalueindex(1))); + + return function::call(L, func); +} + +} // namespace detail +} // namespace luabridge + +// End File: Source/LuaBridge/detail/CFunctions.h + +// Begin File: Source/LuaBridge/detail/LuaRef.h + +// https://github.com/kunitoki/LuaBridge3 +// Copyright 2020, Lucio Asnaghi +// Copyright 2019, George Tokmaji +// Copyright 2018, Dmitry Tarakanov +// Copyright 2012, Vinnie Falco +// Copyright 2008, Nigel Atkinson +// SPDX-License-Identifier: MIT + +namespace luabridge { + +class LuaResult; + +//================================================================================================= +/** + * @brief Type tag for representing LUA_TNIL. + * + * Construct one of these using `LuaNil ()` to represent a Lua nil. This is faster than creating a reference in the registry to nil. + * Example: + * + * @code + * LuaRef t (LuaRef::createTable (L)); + * ... + * t ["k"] = LuaNil (); // assign nil + * @endcode + */ +struct LuaNil +{ +}; + +/** + * @brief Stack specialization for LuaNil. + */ +template <> +struct Stack +{ + static bool push(lua_State* L, const LuaNil&, std::error_code&) + { + lua_pushnil(L); + return true; + } + + static bool isInstance(lua_State* L, int index) + { + return lua_type(L, index) == LUA_TNIL; + } +}; + +//================================================================================================= +/** + * @brief Base class for Lua variables and table item reference classes. + */ +template +class LuaRefBase +{ +protected: + //============================================================================================= + /** + * @brief Pop the Lua stack. + * + * Pops the specified number of stack items on destruction. We use this when returning objects, to avoid an explicit temporary + * variable, since the destructor executes after the return statement. For example: + * + * @code + * template + * U cast (lua_State* L) + * { + * StackPop p (L, 1); + * ... + * return U (); // Destructor called after this line + * } + * @endcode + * + * @note The `StackPop` object must always be a named local variable. + */ + class StackPop + { + public: + /** + * @brief Create a StackPop object. + * + * @param L A Lua state. + * @param count The number of stack entries to pop on destruction. + */ + StackPop(lua_State* L, int count) + : m_L(L) + , m_count(count) { + } + + /** + * @brief Destroy a StackPop object. + * + * In case an exception is in flight before the destructor is called, stack is potentially cleared by lua. So we never pop more than + * the actual size of the stack. + */ + ~StackPop() + { + const int stackSize = lua_gettop(m_L); + + lua_pop(m_L, stackSize < m_count ? stackSize : m_count); + } + + /** + * @brief Set a new number to pop. + * + * @param newCount The new number of stack entries to pop on destruction. + */ + void popCount(int newCount) + { + m_count = newCount; + } + + private: + lua_State* m_L = nullptr; + int m_count = 0; + }; + + friend struct Stack; + + //============================================================================================= + /** + * @brief Type tag for stack construction. + */ + struct FromStack + { + }; + + LuaRefBase(lua_State* L) + : m_L(L) + { + } + + //============================================================================================= + /** + * @brief Create a reference to this reference. + * + * @returns An index in the Lua registry. + */ + int createRef() const + { + impl().push(); + + return luaL_ref(m_L, LUA_REGISTRYINDEX); + } + +public: + //============================================================================================= + /** + * @brief Convert to a string using lua_tostring function. + * + * @returns A string representation of the referred Lua value. + */ + std::string tostring() const + { + StackPop p(m_L, 1); + + lua_getglobal(m_L, "tostring"); + + impl().push(); + + lua_call(m_L, 1, 1); + + const char* str = lua_tostring(m_L, -1); + return str != nullptr ? str : ""; + } + + //============================================================================================= + /** + * @brief Print a text description of the value to a stream. + * + * This is used for diagnostics. + * + * @param os An output stream. + */ + void print(std::ostream& os) const + { + switch (type()) + { + case LUA_TNIL: + os << "nil"; + break; + + case LUA_TNUMBER: + os << cast(); + break; + + case LUA_TBOOLEAN: + os << (cast() ? "true" : "false"); + break; + + case LUA_TSTRING: + os << '"' << cast() << '"'; + break; + + case LUA_TTABLE: + os << "table: " << tostring(); + break; + + case LUA_TFUNCTION: + os << "function: " << tostring(); + break; + + case LUA_TUSERDATA: + os << "userdata: " << tostring(); + break; + + case LUA_TTHREAD: + os << "thread: " << tostring(); + break; + + case LUA_TLIGHTUSERDATA: + os << "lightuserdata: " << tostring(); + break; + + default: + os << "unknown"; + break; + } + } + + //============================================================================================= + /** + * @brief Insert a Lua value or table item reference to a stream. + * + * @param os An output stream. + * @param ref A Lua reference. + * + * @returns The output stream. + */ + friend std::ostream& operator<<(std::ostream& os, const LuaRefBase& ref) + { + ref.print(os); + return os; + } + + //============================================================================================= + /** + * @brief Retrieve the lua_State associated with the reference. + * + * @returns A Lua state. + */ + lua_State* state() const + { + return m_L; + } + + //============================================================================================= + /** + * @brief Place the object onto the Lua stack. + * + * @param L A Lua state. + */ + void push(lua_State* L) const + { + assert(equalstates(L, m_L)); + (void) L; + + impl().push(); + } + + //============================================================================================= + /** + * @brief Pop the top of Lua stack and assign it to the reference. + * + * @param L A Lua state. + */ + void pop(lua_State* L) + { + assert(equalstates(L, m_L)); + (void) L; + + impl().pop(); + } + + //============================================================================================= + /** + * @brief Return the Lua type of the referred value. + * + * This invokes lua_type(). + * + * @returns The type of the referred value. + * + * @see lua_type() + */ + int type() const + { + StackPop p(m_L, 1); + + impl().push(); + + const int refType = lua_type(m_L, -1); + + return refType; + } + + /** + * @brief Indicate whether it is a nil reference. + * + * @returns True if this is a nil reference, false otherwise. + */ + bool isNil() const { return type() == LUA_TNIL; } + + /** + * @brief Indicate whether it is a reference to a boolean. + * + * @returns True if it is a reference to a boolean, false otherwise. + */ + bool isBool() const { return type() == LUA_TBOOLEAN; } + + /** + * @brief Indicate whether it is a reference to a number. + * + * @returns True if it is a reference to a number, false otherwise. + */ + bool isNumber() const { return type() == LUA_TNUMBER; } + + /** + * @brief Indicate whether it is a reference to a string. + * + * @returns True if it is a reference to a string, false otherwise. + */ + bool isString() const { return type() == LUA_TSTRING; } + + /** + * @brief Indicate whether it is a reference to a table. + * + * @returns True if it is a reference to a table, false otherwise. + */ + bool isTable() const { return type() == LUA_TTABLE; } + + /** + * @brief Indicate whether it is a reference to a function. + * + * @returns True if it is a reference to a function, false otherwise. + */ + bool isFunction() const { return type() == LUA_TFUNCTION; } + + /** + * @brief Indicate whether it is a reference to a full userdata. + * + * @returns True if it is a reference to a full userdata, false otherwise. + */ + bool isUserdata() const { return type() == LUA_TUSERDATA; } + + /** + * @brief Indicate whether it is a reference to a lua thread (coroutine). + * + * @returns True if it is a reference to a lua thread, false otherwise. + */ + bool isThread() const { return type() == LUA_TTHREAD; } + + /** + * @brief Indicate whether it is a reference to a light userdata. + * + * @returns True if it is a reference to a light userdata, false otherwise. + */ + bool isLightUserdata() const { return type() == LUA_TLIGHTUSERDATA; } + + /** + * @brief Indicate whether it is a callable. + * + * @returns True if it is a callable, false otherwise. + */ + bool isCallable() const + { + if (isFunction()) + return true; + + auto metatable = getMetatable(); + return metatable.isTable() && metatable["__call"].isFunction(); + } + + //============================================================================================= + /** + * @brief Perform an explicit conversion to the type T. + * + * @returns A value of the type T converted from this reference. + */ + template + T cast() const + { + StackPop p(m_L, 1); + + impl().push(); + + return Stack::get(m_L, -1); + } + + //============================================================================================= + /** + * @brief Indicate if this reference is convertible to the type T. + * + * @returns True if the referred value is convertible to the type T, false otherwise. + */ + template + bool isInstance() const + { + StackPop p(m_L, 1); + + impl().push(); + + return Stack::isInstance(m_L, -1); + } + + //============================================================================================= + /** + * @brief Type cast operator. + * + * @returns A value of the type T converted from this reference. + */ + template + operator T() const + { + return cast(); + } + + //============================================================================================= + /** + * @brief Get the metatable for the LuaRef. + * + * @returns A LuaRef holding the metatable of the lua object. + */ + LuaRef getMetatable() const + { + if (isNil()) + return LuaRef(m_L); + + StackPop p(m_L, 2); + + impl().push(); + + if (! lua_getmetatable(m_L, -1)) + { + p.popCount(1); + return LuaRef(m_L); + } + + return LuaRef::fromStack(m_L); + } + + //============================================================================================= + /** + * @brief Compare this reference with a specified value using lua_compare(). + * + * This invokes metamethods. + * + * @param rhs A value to compare with. + * + * @returns True if the referred value is equal to the specified one. + */ + template + bool operator==(T rhs) const + { + StackPop p(m_L, 2); + + impl().push(); + + std::error_code ec; + if (! Stack::push(m_L, rhs, ec)) + { + p.popCount(1); + return false; + } + + return lua_compare(m_L, -2, -1, LUA_OPEQ) == 1; + } + + /** + * @brief Compare this reference with a specified value using lua_compare(). + * + * This invokes metamethods. + * + * @param rhs A value to compare with. + * + * @returns True if the referred value is not equal to the specified one. + */ + template + bool operator!=(T rhs) const + { + return !(*this == rhs); + } + + /** + * @brief Compare this reference with a specified value using lua_compare(). + * + * This invokes metamethods. + * + * @param rhs A value to compare with. + * + * @returns True if the referred value is less than the specified one. + */ + template + bool operator<(T rhs) const + { + StackPop p(m_L, 2); + + impl().push(); + + std::error_code ec; + if (! Stack::push(m_L, rhs, ec)) + { + p.popCount(1); + return false; + } + + const int lhsType = lua_type(m_L, -2); + const int rhsType = lua_type(m_L, -1); + if (lhsType != rhsType) + return lhsType < rhsType; + + return lua_compare(m_L, -2, -1, LUA_OPLT) == 1; + } + + /** + * @brief Compare this reference with a specified value using lua_compare(). + * + * This invokes metamethods. + * + * @param rhs A value to compare with. + * + * @returns True if the referred value is less than or equal to the specified one. + */ + template + bool operator<=(T rhs) const + { + StackPop p(m_L, 2); + + impl().push(); + + std::error_code ec; + if (! Stack::push(m_L, rhs, ec)) + { + p.popCount(1); + return false; + } + + const int lhsType = lua_type(m_L, -2); + const int rhsType = lua_type(m_L, -1); + if (lhsType != rhsType) + return lhsType <= rhsType; + + return lua_compare(m_L, -2, -1, LUA_OPLE) == 1; + } + + /** + * @brief Compare this reference with a specified value using lua_compare(). + * + * This invokes metamethods. + * + * @param rhs A value to compare with. + * + * @returns True if the referred value is greater than the specified one. + */ + template + bool operator>(T rhs) const + { + StackPop p(m_L, 2); + + impl().push(); + + std::error_code ec; + if (! Stack::push(m_L, rhs, ec)) + { + p.popCount(1); + return false; + } + + const int lhsType = lua_type(m_L, -2); + const int rhsType = lua_type(m_L, -1); + if (lhsType != rhsType) + return lhsType > rhsType; + + return lua_compare(m_L, -1, -2, LUA_OPLT) == 1; + } + + /** + * @brief Compare this reference with a specified value using lua_compare(). + * + * This invokes metamethods. + * + * @param rhs A value to compare with. + * + * @returns True if the referred value is greater than or equal to the specified one. + */ + template + bool operator>=(T rhs) const + { + StackPop p(m_L, 2); + + impl().push(); + + std::error_code ec; + if (! Stack::push(m_L, rhs, ec)) + { + p.popCount(1); + return false; + } + + const int lhsType = lua_type(m_L, -2); + const int rhsType = lua_type(m_L, -1); + if (lhsType != rhsType) + return lhsType >= rhsType; + + return lua_compare(m_L, -1, -2, LUA_OPLE) == 1; + } + + /** + * @brief Compare this reference with a specified value using lua_compare(). + * + * This does not invoke metamethods. + * + * @param rhs A value to compare with. + * + * @returns True if the referred value is equal to the specified one. + */ + template + bool rawequal(T v) const + { + StackPop p(m_L, 2); + + impl().push(); + + std::error_code ec; + if (! Stack::push(m_L, v, ec)) + { + p.popCount(1); + return false; + } + + return lua_rawequal(m_L, -1, -2) == 1; + } + + //============================================================================================= + /** + * @brief Append a value to a referred table. + * + * If the table is a sequence this will add another element to it. + * + * @param v A value to append to the table. + */ + template + void append(T v) const + { + StackPop p(m_L, 1); + + impl().push(); + + std::error_code ec; + if (! Stack::push(m_L, v, ec)) + return; + + luaL_ref(m_L, -2); + } + + //============================================================================================= + /** + * @brief Return the length of a referred array. + * + * This is identical to applying the Lua # operator. + * + * @returns The length of the referred array. + */ + int length() const + { + StackPop p(m_L, 1); + + impl().push(); + + return get_length(m_L, -1); + } + + //============================================================================================= + /** + * @brief Call Lua code. + * + * The return value is provided as a LuaRef (which may be LUA_REFNIL). + * + * If an error occurs, a LuaException is thrown (only if exceptions are enabled). + * + * @returns A result of the call. + */ + template + LuaResult operator()(Args&&... args) const; + +protected: + lua_State* m_L = nullptr; + +private: + const Impl& impl() const { return static_cast(*this); } + + Impl& impl() { return static_cast(*this); } +}; + +//================================================================================================= +/** + * @brief Lightweight reference to a Lua object. + * + * The reference is maintained for the lifetime of the C++ object. + */ +class LuaRef : public LuaRefBase +{ + //============================================================================================= + /** + * @brief A proxy for representing table values. + */ + class TableItem : public LuaRefBase + { + friend class LuaRef; + + public: + //========================================================================================= + /** + * @brief Construct a TableItem from a table value. + * + * The table is in the registry, and the key is at the top of the stack. + * The key is popped off the stack. + * + * @param L A lua state. + * @param tableRef The index of a table in the Lua registry. + */ + TableItem(lua_State* L, int tableRef) + : LuaRefBase(L) + , m_tableRef(LUA_NOREF) + , m_keyRef(luaL_ref(L, LUA_REGISTRYINDEX)) + { + lua_rawgeti(m_L, LUA_REGISTRYINDEX, tableRef); + m_tableRef = luaL_ref(L, LUA_REGISTRYINDEX); + } + + //========================================================================================= + /** + * @brief Create a TableItem via copy constructor. + * + * It is best to avoid code paths that invoke this, because it creates an extra temporary Lua reference. Typically this is done by + * passing the TableItem parameter as a `const` reference. + * + * @param other Another Lua table item reference. + */ + TableItem(const TableItem& other) + : LuaRefBase(other.m_L) + , m_tableRef(LUA_NOREF) + , m_keyRef(LUA_NOREF) + { + lua_rawgeti(m_L, LUA_REGISTRYINDEX, other.m_tableRef); + m_tableRef = luaL_ref(m_L, LUA_REGISTRYINDEX); + + lua_rawgeti(m_L, LUA_REGISTRYINDEX, other.m_keyRef); + m_keyRef = luaL_ref(m_L, LUA_REGISTRYINDEX); + } + + //========================================================================================= + /** + * @brief Destroy the proxy. + * + * This does not destroy the table value. + */ + ~TableItem() + { + if (m_keyRef != LUA_NOREF) + luaL_unref(m_L, LUA_REGISTRYINDEX, m_keyRef); + + if (m_tableRef != LUA_NOREF) + luaL_unref(m_L, LUA_REGISTRYINDEX, m_tableRef); + } + + //========================================================================================= + /** + * @brief Assign a new value to this table key. + * + * This may invoke metamethods. + * + * @tparam T The type of a value to assing. + * + * @param v A value to assign. + * + * @returns This reference. + */ + template + TableItem& operator=(T v) + { + StackPop p(m_L, 1); + lua_rawgeti(m_L, LUA_REGISTRYINDEX, m_tableRef); + lua_rawgeti(m_L, LUA_REGISTRYINDEX, m_keyRef); + + std::error_code ec; + if (! Stack::push(m_L, v, ec)) + return *this; + + lua_settable(m_L, -3); + return *this; + } + + //========================================================================================= + /** + * @brief Assign a new value to this table key. + * + * The assignment is raw, no metamethods are invoked. + * + * @tparam T The type of a value to assing. + * + * @param v A value to assign. + * + * @returns This reference. + */ + template + TableItem& rawset(T v) + { + StackPop p(m_L, 1); + lua_rawgeti(m_L, LUA_REGISTRYINDEX, m_tableRef); + lua_rawgeti(m_L, LUA_REGISTRYINDEX, m_keyRef); + + std::error_code ec; + if (! Stack::push(m_L, v, ec)) + return *this; + + lua_rawset(m_L, -3); + return *this; + } + + //========================================================================================= + /** + * @brief Push the value onto the Lua stack. + */ + using LuaRefBase::push; + + void push() const + { + lua_rawgeti(m_L, LUA_REGISTRYINDEX, m_tableRef); + lua_rawgeti(m_L, LUA_REGISTRYINDEX, m_keyRef); + lua_gettable(m_L, -2); + lua_remove(m_L, -2); // remove the table + } + + //========================================================================================= + /** + * @brief Access a table value using a key. + * + * This invokes metamethods. + * + * @tparam T The type of a key. + * + * @param key A key value. + * + * @returns A Lua table item reference. + */ + template + TableItem operator[](T key) const + { + return LuaRef(*this)[key]; + } + + //========================================================================================= + /** + * @brief Access a table value using a key. + * + * The operation is raw, metamethods are not invoked. The result is passed by value and may not be modified. + * + * @tparam T The type of a key. + * + * @param key A key value. + * + * @returns A Lua value reference. + */ + template + LuaRef rawget(T key) const + { + return LuaRef(*this).rawget(key); + } + + private: + int m_tableRef; + int m_keyRef; + }; + + friend struct Stack; + friend struct Stack; + + //========================================================================================= + /** + * @brief Create a reference to an object at the top of the Lua stack and pop it. + * + * This constructor is private and not invoked directly. Instead, use the `fromStack` function. + * + * @param L A Lua state. + * + * @note The object is popped. + */ + LuaRef(lua_State* L, FromStack) + : LuaRefBase(L) + , m_ref(luaL_ref(m_L, LUA_REGISTRYINDEX)) + { + } + + //========================================================================================= + /** + * @brief Create a reference to an object on the Lua stack. + * + * This constructor is private and not invoked directly. Instead, use the `fromStack` function. + * + * @param L A Lua state. + * + * @param index The index of the value on the Lua stack. + * + * @note The object is not popped. + */ + LuaRef(lua_State* L, int index, FromStack) + : LuaRefBase(L) + , m_ref(LUA_NOREF) + { + lua_pushvalue(m_L, index); + m_ref = luaL_ref(m_L, LUA_REGISTRYINDEX); + } + +public: + //============================================================================================= + /** + * @brief Create an invalid reference that will be treated as nil. + * + * The Lua reference may be assigned later. + * + * @param L A Lua state. + */ + LuaRef(lua_State* L) + : LuaRefBase(L) + , m_ref(LUA_NOREF) + { + } + + //============================================================================================= + /** + * @brief Push a value onto a Lua stack and return a reference to it. + * + * @param L A Lua state. + * @param v A value to push. + */ + template + LuaRef(lua_State* L, T v) + : LuaRefBase(L) + , m_ref(LUA_NOREF) + { + std::error_code ec; + if (! Stack::push(m_L, v, ec)) + return; + + m_ref = luaL_ref(m_L, LUA_REGISTRYINDEX); + } + + //============================================================================================= + /** + * @brief Create a reference to a table item. + * + * @param v A table item reference. + */ + LuaRef(const TableItem& v) + : LuaRefBase(v.state()) + , m_ref(v.createRef()) + { + } + + //============================================================================================= + /** + * @brief Create a new reference to an existing Lua value. + * + * @param other An existing reference. + */ + LuaRef(const LuaRef& other) + : LuaRefBase(other.m_L) + , m_ref(other.createRef()) + { + } + + //============================================================================================= + /** + * @brief Destroy a reference. + * + * The corresponding Lua registry reference will be released. + * + * @note If the state refers to a thread, it is the responsibility of the caller to ensure that the thread still exists when the LuaRef is destroyed. + */ + ~LuaRef() + { + if (m_ref != LUA_NOREF) + luaL_unref(m_L, LUA_REGISTRYINDEX, m_ref); + } + + //============================================================================================= + /** + * @brief Return a reference to a top Lua stack item. + * + * The stack item is not popped. + * + * @param L A Lua state. + * + * @returns A reference to a value on the top of a Lua stack. + */ + static LuaRef fromStack(lua_State* L) + { + return LuaRef(L, FromStack()); + } + + //============================================================================================= + /** + * @brief Return a reference to a Lua stack item with a specified index. + * + * The stack item is not removed. + * + * @param L A Lua state. + * @param index An index in the Lua stack. + * + * @returns A reference to a value in a Lua stack. + */ + static LuaRef fromStack(lua_State* L, int index) + { + lua_pushvalue(L, index); + return LuaRef(L, FromStack()); + } + + //============================================================================================= + /** + * @brief Create a new empty table on the top of a Lua stack and return a reference to it. + * + * @param L A Lua state. + * + * @returns A reference to the newly created table. + * + * @see luabridge::newTable() + */ + static LuaRef newTable(lua_State* L) + { + lua_newtable(L); + return LuaRef(L, FromStack()); + } + + //============================================================================================= + /** + * @brief Return a reference to a named global Lua variable. + * + * @param L A Lua state. + * @param name The name of a global variable. + * + * @returns A reference to the Lua variable. + * + * @see luabridge::getGlobal() + */ + static LuaRef getGlobal(lua_State* L, const char* name) + { + lua_getglobal(L, name); + return LuaRef(L, FromStack()); + } + + //============================================================================================= + /** + * @brief Indicate whether it is an invalid reference. + * + * @returns True if this is an invalid reference, false otherwise. + */ + bool isValid() const { return m_ref != LUA_NOREF; } + + //============================================================================================= + /** + * @brief Assign another LuaRef to this LuaRef. + * + * @param rhs A reference to assign from. + * + * @returns This reference. + */ + LuaRef& operator=(const LuaRef& rhs) + { + LuaRef ref(rhs); + swap(ref); + return *this; + } + + //============================================================================================= + /** + * @brief Assign a table item reference. + * + * @param rhs A table item reference. + * + * @returns This reference. + */ + LuaRef& operator=(const LuaRef::TableItem& rhs) + { + LuaRef ref(rhs); + swap(ref); + return *this; + } + + //============================================================================================= + /** + * @brief Assign nil to this reference. + * + * @returns This reference. + */ + LuaRef& operator=(const LuaNil&) + { + LuaRef ref(m_L); + swap(ref); + return *this; + } + + //============================================================================================= + /** + * @brief Assign a different value to this reference. + * + * @param rhs A value to assign. + * + * @returns This reference. + */ + template + LuaRef& operator=(T rhs) + { + LuaRef ref(m_L, rhs); + swap(ref); + return *this; + } + + //============================================================================================= + /** + * @brief Place the object onto the Lua stack. + */ + using LuaRefBase::push; + + void push() const + { + lua_rawgeti(m_L, LUA_REGISTRYINDEX, m_ref); + } + + //============================================================================================= + /** + * @brief Pop the top of Lua stack and assign the ref to m_ref + */ + void pop() + { + luaL_unref(m_L, LUA_REGISTRYINDEX, m_ref); + m_ref = luaL_ref(m_L, LUA_REGISTRYINDEX); + } + + //============================================================================================= + /** + * @brief Access a table value using a key. + * + * This invokes metamethods. + * + * @param key A key in the table. + * + * @returns A reference to the table item. + */ + template + TableItem operator[](T key) const + { + std::error_code ec; + if (! Stack::push(m_L, key, ec)) + return TableItem(m_L, m_ref); + + return TableItem(m_L, m_ref); + } + + //============================================================================================= + /** + * @brief Access a table value using a key. + * + * The operation is raw, metamethods are not invoked. The result is passed by value and may not be modified. + * + * @param key A key in the table. + * + * @returns A reference to the table item. + */ + template + LuaRef rawget(T key) const + { + StackPop(m_L, 1); + + push(m_L); + + std::error_code ec; + if (! Stack::push(m_L, key, ec)) + return LuaRef(m_L); + + lua_rawget(m_L, -2); + return LuaRef(m_L, FromStack()); + } + +private: + void swap(LuaRef& other) + { + using std::swap; + + swap(m_L, other.m_L); + swap(m_ref, other.m_ref); + } + + int m_ref = LUA_NOREF; +}; + +//================================================================================================= +/** + * @brief Stack specialization for `LuaRef`. + */ +template <> +struct Stack +{ + static bool push(lua_State* L, const LuaRef& v, std::error_code&) + { + return v.push(L), true; + } + + static LuaRef get(lua_State* L, int index) + { + return LuaRef::fromStack(L, index); + } +}; + +//================================================================================================= +/** + * @brief Stack specialization for `TableItem`. + */ +template <> +struct Stack +{ + static bool push(lua_State* L, const LuaRef::TableItem& v, std::error_code&) + { + return v.push(L), true; + } +}; + +//================================================================================================= +/** + * @brief Create a reference to a new, empty table. + * + * This is a syntactic abbreviation for LuaRef::newTable (). + */ +inline LuaRef newTable(lua_State* L) +{ + return LuaRef::newTable(L); +} + +//================================================================================================= +/** + * @brief Create a reference to a value in the global table. + * + * This is a syntactic abbreviation for LuaRef::getGlobal (). + */ +inline LuaRef getGlobal(lua_State* L, const char* name) +{ + return LuaRef::getGlobal(L, name); +} + +//================================================================================================= +/** + * @brief C++ like cast syntax. + */ +template +T cast(const LuaRef& ref) +{ + return ref.cast(); +} + +} // namespace luabridge + +// End File: Source/LuaBridge/detail/LuaRef.h + +// Begin File: Source/LuaBridge/detail/Invoke.h + +// https://github.com/kunitoki/LuaBridge3 +// Copyright 2021, Lucio Asnaghi +// SPDX-License-Identifier: MIT + +namespace luabridge { + +//================================================================================================= +/** + * @brief Result of a lua invocation. + */ +class LuaResult +{ +public: + /** + * @brief Get if the result was ok and didn't raise a lua error. + */ + explicit operator bool() const noexcept + { + return !m_ec; + } + + /** + * @brief Return if the invocation was ok and didn't raise a lua error. + */ + bool wasOk() const noexcept + { + return !m_ec; + } + + /** + * @brief Return if the invocation did raise a lua error. + */ + bool hasFailed() const noexcept + { + return !!m_ec; + } + + /** + * @brief Return the error code, if any. + * + * In case the invcation didn't raise any lua error, the value returned equals to a + * default constructed std::error_code. + */ + std::error_code errorCode() const noexcept + { + return m_ec; + } + + /** + * @brief Return the error message, if any. + */ + std::string errorMessage() const noexcept + { + if (std::holds_alternative(m_data)) + { + const auto& message = std::get(m_data); + return message.empty() ? m_ec.message() : message; + } + + return {}; + } + + /** + * @brief Return the number of return values. + */ + std::size_t size() const noexcept + { + if (std::holds_alternative>(m_data)) + return std::get>(m_data).size(); + + return 0; + } + + /** + * @brief Get a return value at a specific index. + */ + LuaRef operator[](std::size_t index) const + { + assert(m_ec == std::error_code()); + + if (std::holds_alternative>(m_data)) + { + const auto& values = std::get>(m_data); + + assert(index < values.size()); + return values[index]; + } + + return LuaRef(m_L); + } + +private: + template + friend LuaResult call(const LuaRef&, Args&&...); + + static LuaResult errorFromStack(lua_State* L, std::error_code ec) + { + auto errorString = lua_tostring(L, -1); + lua_pop(L, 1); + + return LuaResult(L, ec, errorString ? errorString : ec.message()); + } + + static LuaResult valuesFromStack(lua_State* L, int stackTop) + { + std::vector values; + + const int numReturnedValues = lua_gettop(L) - stackTop; + if (numReturnedValues > 0) + { + values.reserve(numReturnedValues); + + for (int index = numReturnedValues; index > 0; --index) + values.emplace_back(LuaRef::fromStack(L, -index)); + + lua_pop(L, numReturnedValues); + } + + return LuaResult(L, std::move(values)); + } + + LuaResult(lua_State* L, std::error_code ec, std::string_view errorString) + : m_L(L) + , m_ec(ec) + , m_data(std::string(errorString)) + { + } + + explicit LuaResult(lua_State* L, std::vector values) noexcept + : m_L(L) + , m_data(std::move(values)) + { + } + + lua_State* m_L = nullptr; + std::error_code m_ec; + std::variant, std::string> m_data; +}; + +//================================================================================================= +/** + * @brief Safely call Lua code. + * + * These overloads allow Lua code to be called throught lua_pcall. The return value is provided as + * a LuaResult which will hold the return values or an error if the call failed. + * + * If an error occurs, a LuaException is thrown or if exceptions are disabled the FunctionResult will + * contain a error code and evaluate false. + * + * @note The function might throw a LuaException if the application is compiled with exceptions on + * and they are enabled globally by calling `enableExceptions` in two cases: + * - one of the arguments passed cannot be pushed in the stack, for example a unregistered C++ class + * - the lua invaction calls the panic handler, which is converted to a C++ exception + * + * @return A result object. +*/ +template +LuaResult call(const LuaRef& object, Args&&... args) +{ + lua_State* L = object.state(); + const int stackTop = lua_gettop(L); + + object.push(); + + { + std::error_code ec; + auto pushedArgs = detail::push_arguments(L, std::forward_as_tuple(args...), ec); + if (ec) + { + lua_pop(L, static_cast(pushedArgs) + 1); + return LuaResult(L, ec, ec.message()); + } + } + + int code = lua_pcall(L, sizeof...(Args), LUA_MULTRET, 0); + if (code != LUABRIDGE_LUA_OK) + { + auto ec = makeErrorCode(ErrorCode::LuaFunctionCallFailed); + +#if LUABRIDGE_HAS_EXCEPTIONS + if (LuaException::areExceptionsEnabled()) + LuaException::raise(LuaException(L, ec)); +#else + return LuaResult::errorFromStack(L, ec); +#endif + } + + return LuaResult::valuesFromStack(L, stackTop); +} + +//============================================================================================= +/** + * @brief Wrapper for lua_pcall that throws if exceptions are enabled. + */ +inline int pcall(lua_State* L, int nargs = 0, int nresults = 0, int msgh = 0) +{ + const int code = lua_pcall(L, nargs, nresults, msgh); + +#if LUABRIDGE_HAS_EXCEPTIONS + if (code != LUABRIDGE_LUA_OK && LuaException::areExceptionsEnabled()) + LuaException::raise(LuaException(L, makeErrorCode(ErrorCode::LuaFunctionCallFailed))); +#endif + + return code; +} + +//============================================================================================= +template +template +LuaResult LuaRefBase::operator()(Args&&... args) const +{ + return call(*this, std::forward(args)...); +} + +} // namespace luabridge + +// End File: Source/LuaBridge/detail/Invoke.h + +// Begin File: Source/LuaBridge/detail/Iterator.h + +// https://github.com/kunitoki/LuaBridge3 +// Copyright 2020, Lucio Asnaghi +// Copyright 2018, Dmitry Tarakanov +// Copyright 2012, Vinnie Falco +// SPDX-License-Identifier: MIT + +namespace luabridge { + +//================================================================================================= +/** + * @brief Iterator class to allow table iteration. + * + * @see Range class. + */ +class Iterator +{ +public: + explicit Iterator(const LuaRef& table, bool isEnd = false) + : m_L(table.state()) + , m_table(table) + , m_key(table.state()) // m_key is nil + , m_value(table.state()) // m_value is nil + { + if (! isEnd) + { + next(); // get the first (key, value) pair from table + } + } + + /** + * @brief Return an associated Lua state. + * + * @return A Lua state. + */ + lua_State* state() const noexcept + { + return m_L; + } + + /** + * @brief Dereference the iterator. + * + * @return A key-value pair for a current table entry. + */ + std::pair operator*() const + { + return std::make_pair(m_key, m_value); + } + + /** + * @brief Return the value referred by the iterator. + * + * @return A value for the current table entry. + */ + LuaRef operator->() const + { + return m_value; + } + + /** + * @brief Compare two iterators. + * + * @param rhs Another iterator. + * + * @return True if iterators point to the same entry of the same table, false otherwise. + */ + bool operator!=(const Iterator& rhs) const + { + assert(m_L == rhs.m_L); + + return ! m_table.rawequal(rhs.m_table) || ! m_key.rawequal(rhs.m_key); + } + + /** + * @brief Move the iterator to the next table entry. + * + * @return This iterator. + */ + Iterator& operator++() + { + if (isNil()) + { + // if the iterator reaches the end, do nothing + return *this; + } + else + { + next(); + return *this; + } + } + + /** + * @brief Check if the iterator points after the last table entry. + * + * @return True if there are no more table entries to iterate, false otherwise. + */ + bool isNil() const noexcept + { + return m_key.isNil(); + } + + /** + * @brief Return the key for the current table entry. + * + * @return A reference to the entry key. + */ + LuaRef key() const + { + return m_key; + } + + /** + * @brief Return the key for the current table entry. + * + * @return A reference to the entry value. + */ + LuaRef value() const + { + return m_value; + } + +private: + // Don't use postfix increment, it is less efficient + Iterator operator++(int); + + void next() + { + m_table.push(); + m_key.push(); + + if (lua_next(m_L, -2)) + { + m_value.pop(); + m_key.pop(); + } + else + { + m_key = LuaNil(); + m_value = LuaNil(); + } + + lua_pop(m_L, 1); + } + + lua_State* m_L = nullptr; + LuaRef m_table; + LuaRef m_key; + LuaRef m_value; +}; + +//================================================================================================= +/** + * @brief Range class taking two table iterators. + */ +class Range +{ +public: + Range(const Iterator& begin, const Iterator& end) + : m_begin(begin) + , m_end(end) + { + } + + const Iterator& begin() const noexcept + { + return m_begin; + } + + const Iterator& end() const noexcept + { + return m_end; + } + +private: + Iterator m_begin; + Iterator m_end; +}; + +//================================================================================================= +/** + * @brief Return a range for the Lua table reference. + * + * @return A range suitable for range-based for statement. + */ +inline Range pairs(const LuaRef& table) +{ + return Range{ Iterator(table, false), Iterator(table, true) }; +} + +} // namespace luabridge + +// End File: Source/LuaBridge/detail/Iterator.h + +// Begin File: Source/LuaBridge/detail/Security.h + +// https://github.com/vinniefalco/LuaBridge +// Copyright 2021, Lucio Asnaghi +// Copyright 2012, Vinnie Falco +// SPDX-License-Identifier: MIT + +namespace luabridge { + +//================================================================================================= +/** + * @brief Security options. + */ +class Security +{ +public: + static bool hideMetatables() noexcept + { + return getSettings().hideMetatables; + } + + static void setHideMetatables(bool shouldHide) noexcept + { + getSettings().hideMetatables = shouldHide; + } + +private: + struct Settings + { + Settings() noexcept + : hideMetatables(true) + { + } + + bool hideMetatables; + }; + + static Settings& getSettings() noexcept + { + static Settings settings; + return settings; + } +}; + +//================================================================================================= +/** + * @brief Get a global value from the lua_State. + * + * @note This works on any type specialized by `Stack`, including `LuaRef` and its table proxies. +*/ +template +T getGlobal(lua_State* L, const char* name) +{ + lua_getglobal(L, name); + + auto result = luabridge::Stack::get(L, -1); + + lua_pop(L, 1); + + return result; +} + +//================================================================================================= +/** + * @brief Set a global value in the lua_State. + * + * @note This works on any type specialized by `Stack`, including `LuaRef` and its table proxies. +*/ +template +bool setGlobal(lua_State* L, T&& t, const char* name) +{ + std::error_code ec; + if (push(L, std::forward(t), ec)) + { + lua_setglobal(L, name); + return true; + } + + return false; +} + +//================================================================================================= +/** + * @brief Change whether or not metatables are hidden (on by default). + */ +inline void setHideMetatables(bool shouldHide) noexcept +{ + Security::setHideMetatables(shouldHide); +} + +} // namespace luabridge + +// End File: Source/LuaBridge/detail/Security.h + +// Begin File: Source/LuaBridge/detail/Namespace.h + +// https://github.com/kunitoki/LuaBridge3 +// Copyright 2020, Lucio Asnaghi +// Copyright 2019, Dmitry Tarakanov +// Copyright 2012, Vinnie Falco +// Copyright 2007, Nathan Reed +// SPDX-License-Identifier: MIT + +namespace luabridge { +namespace detail { + +//================================================================================================= +/** + * @brief Base for class and namespace registration. + * + * Maintains Lua stack in the proper state. Once beginNamespace, beginClass or deriveClass is called the parent object upon its destruction + * may no longer clear the Lua stack. + * + * Then endNamespace or endClass is called, a new parent is created and the child transfers the responsibility for clearing stack to it. + * + * So there can be maximum one "active" registrar object. + */ +class Registrar +{ +protected: + Registrar(lua_State* L) + : L(L) + , m_stackSize(0) + { + } + + Registrar(lua_State* L, int skipStackPops) + : L(L) + , m_stackSize(0) + , m_skipStackPops(skipStackPops) + { + } + + Registrar(const Registrar& rhs) + : L(rhs.L) + , m_stackSize(std::exchange(rhs.m_stackSize, 0)) + , m_skipStackPops(std::exchange(rhs.m_skipStackPops, 0)) + { + } + + Registrar& operator=(const Registrar& rhs) + { + using std::swap; + + Registrar tmp(rhs); + + swap(m_stackSize, tmp.m_stackSize); + + return *this; + } + + ~Registrar() + { + const int popsCount = m_stackSize - m_skipStackPops; + if (popsCount > 0) + { + assert(popsCount <= lua_gettop(L)); + + lua_pop(L, popsCount); + } + } + + void assertIsActive() const + { + if (m_stackSize == 0) + { + throw_or_assert("Unable to continue registration"); + } + } + + lua_State* const L = nullptr; + int mutable m_stackSize = 0; + int mutable m_skipStackPops = 0; +}; + +} // namespace detail + +//================================================================================================= +/** + * @brief Provides C++ to Lua registration capabilities. + * + * This class is not instantiated directly, call `getGlobalNamespace` to start the registration process. + */ +class Namespace : public detail::Registrar +{ + //============================================================================================= +#if 0 + /** + Error reporting. + + VF: This function looks handy, why aren't we using it? + */ + static int luaError (lua_State* L, std::string message) + { + assert (lua_isstring (L, lua_upvalueindex (1))); + std::string s; + + // Get information on the caller's caller to format the message, + // so the error appears to originate from the Lua source. + lua_Debug ar; + int result = lua_getstack (L, 2, &ar); + if (result != 0) + { + lua_getinfo (L, "Sl", &ar); + s = ar.short_src; + if (ar.currentline != -1) + { + // poor mans int to string to avoid . + lua_pushnumber (L, ar.currentline); + s = s + ":" + lua_tostring (L, -1) + ": "; + lua_pop (L, 1); + } + } + + s = s + message; + + return luaL_error (L, s.c_str ()); + } +#endif + + //============================================================================================= + /** + * @brief Factored base to reduce template instantiations. + */ + class ClassBase : public detail::Registrar + { + public: + explicit ClassBase(Namespace& parent) + : Registrar(parent) + { + } + + using Registrar::operator=; + + protected: + //========================================================================================= + /** + * @brief Create the const table. + */ + void createConstTable(const char* name, bool trueConst = true) + { + assert(name != nullptr); + + std::string type_name = std::string(trueConst ? "const " : "") + name; + + // Stack: namespace table (ns) + lua_newtable(L); // Stack: ns, const table (co) + lua_pushvalue(L, -1); // Stack: ns, co, co + lua_setmetatable(L, -2); // co.__metatable = co. Stack: ns, co + + lua_pushstring(L, type_name.c_str()); + lua_rawsetp(L, -2, detail::getTypeKey()); // co [typeKey] = name. Stack: ns, co + + lua_pushcfunction(L, &detail::index_metamethod); + rawsetfield(L, -2, "__index"); + + lua_pushcfunction(L, &detail::newindex_object_metamethod); + rawsetfield(L, -2, "__newindex"); + + lua_newtable(L); + lua_rawsetp(L, -2, detail::getPropgetKey()); + + if (Security::hideMetatables()) + { + lua_pushnil(L); + rawsetfield(L, -2, "__metatable"); + } + } + + //========================================================================================= + /** + * @brief Create the class table. + * + * The Lua stack should have the const table on top. + */ + void createClassTable(const char* name) + { + assert(name != nullptr); + + // Stack: namespace table (ns), const table (co) + + // Class table is the same as const table except the propset table + createConstTable(name, false); // Stack: ns, co, cl + + lua_newtable(L); // Stack: ns, co, cl, propset table (ps) + lua_rawsetp(L, -2, detail::getPropsetKey()); // cl [propsetKey] = ps. Stack: ns, co, cl + + lua_pushvalue(L, -2); // Stack: ns, co, cl, co + lua_rawsetp(L, -2, detail::getConstKey()); // cl [constKey] = co. Stack: ns, co, cl + + lua_pushvalue(L, -1); // Stack: ns, co, cl, cl + lua_rawsetp(L, -3, detail::getClassKey()); // co [classKey] = cl. Stack: ns, co, cl + } + + //========================================================================================= + /** + * @brief Create the static table. + */ + void createStaticTable(const char* name) + { + assert(name != nullptr); + + // Stack: namespace table (ns), const table (co), class table (cl) + lua_newtable(L); // Stack: ns, co, cl, visible static table (vst) + lua_newtable(L); // Stack: ns, co, cl, st, static metatable (st) + lua_pushvalue(L, -1); // Stack: ns, co, cl, vst, st, st + lua_setmetatable(L, -3); // st.__metatable = mt. Stack: ns, co, cl, vst, st + lua_insert(L, -2); // Stack: ns, co, cl, st, vst + rawsetfield(L, -5, name); // ns [name] = vst. Stack: ns, co, cl, st + +#if 0 + lua_pushlightuserdata (L, this); + lua_pushcclosure (L, &tostringMetaMethod, 1); + rawsetfield (L, -2, "__tostring"); +#endif + + lua_pushcfunction(L, &detail::index_metamethod); + rawsetfield(L, -2, "__index"); + + lua_pushcfunction(L, &detail::newindex_static_metamethod); + rawsetfield(L, -2, "__newindex"); + + lua_newtable(L); // Stack: ns, co, cl, st, proget table (pg) + lua_rawsetp(L, -2, detail::getPropgetKey()); // st [propgetKey] = pg. Stack: ns, co, cl, st + + lua_newtable(L); // Stack: ns, co, cl, st, propset table (ps) + lua_rawsetp(L, -2, detail::getPropsetKey()); // st [propsetKey] = pg. Stack: ns, co, cl, st + + lua_pushvalue(L, -2); // Stack: ns, co, cl, st, cl + lua_rawsetp(L, -2, detail::getClassKey()); // st [classKey] = cl. Stack: ns, co, cl, st + + if (Security::hideMetatables()) + { + lua_pushnil(L); + rawsetfield(L, -2, "__metatable"); + } + } + + //========================================================================================= + /** + * @brief lua_CFunction to construct a class object wrapped in a container. + */ + template + static int ctorContainerProxy(lua_State* L) + { + using T = typename ContainerTraits::Type; + + T* object = detail::constructor::call(detail::make_arguments_list(L)); + + std::error_code ec; + if (! detail::UserdataSharedHelper::push(L, object, ec)) + luaL_error(L, ec.message().c_str()); + + return 1; + } + + //========================================================================================= + /** + * @brief lua_CFunction to construct a class object in-place in the userdata. + */ + template + static int ctorPlacementProxy(lua_State* L) + { + std::error_code ec; + detail::UserdataValue* value = detail::UserdataValue::place(L, ec); + if (! value) + luaL_error(L, ec.message().c_str()); + + detail::constructor::call(value->getObject(), detail::make_arguments_list(L)); + + value->commit(); + + return 1; + } + + //========================================================================================= + /** + * @brief Asserts on stack state. + */ + void assertStackState() const + { + // Stack: const table (co), class table (cl), static table (st) + assert(lua_istable(L, -3)); + assert(lua_istable(L, -2)); + assert(lua_istable(L, -1)); + } + }; + + //============================================================================================= + /** + * @brief Provides a class registration in a lua_State. + * + * After construction the Lua stack holds these objects: + * -1 static table + * -2 class table + * -3 const table + * -4 enclosing namespace table + */ + template + class Class : public ClassBase + { + public: + //========================================================================================= + + /** + * @brief Register a new class or add to an existing class registration. + * + * @param name The new class name. + * @param parent A parent namespace object. + */ + Class(const char* name, Namespace& parent) + : ClassBase(parent) + { + assert(name != nullptr); + assert(lua_istable(L, -1)); // Stack: namespace table (ns) + + rawgetfield(L, -1, name); // Stack: ns, static table (st) | nil + + if (lua_isnil(L, -1)) // Stack: ns, nil + { + lua_pop(L, 1); // Stack: ns + + createConstTable(name); // Stack: ns, const table (co) + lua_pushcfunction(L, &detail::gc_metamethod); // Stack: ns, co, function + rawsetfield(L, -2, "__gc"); // co ["__gc"] = function. Stack: ns, co + ++m_stackSize; + + createClassTable(name); // Stack: ns, co, class table (cl) + lua_pushcfunction(L, &detail::gc_metamethod); // Stack: ns, co, cl, function + rawsetfield(L, -2, "__gc"); // cl ["__gc"] = function. Stack: ns, co, cl + ++m_stackSize; + + createStaticTable(name); // Stack: ns, co, cl, st + ++m_stackSize; + + // Map T back to its tables. + lua_pushvalue(L, -1); // Stack: ns, co, cl, st, st + lua_rawsetp(L, LUA_REGISTRYINDEX, detail::getStaticRegistryKey()); // Stack: ns, co, cl, st + lua_pushvalue(L, -2); // Stack: ns, co, cl, st, cl + lua_rawsetp(L, LUA_REGISTRYINDEX, detail::getClassRegistryKey()); // Stack: ns, co, cl, st + lua_pushvalue(L, -3); // Stack: ns, co, cl, st, co + lua_rawsetp(L, LUA_REGISTRYINDEX, detail::getConstRegistryKey()); // Stack: ns, co, cl, st + } + else + { + assert(lua_istable(L, -1)); // Stack: ns, st + ++m_stackSize; + + // Map T back from its stored tables + + lua_rawgetp(L, LUA_REGISTRYINDEX, detail::getConstRegistryKey()); // Stack: ns, st, co + lua_insert(L, -2); // Stack: ns, co, st + ++m_stackSize; + + lua_rawgetp(L, LUA_REGISTRYINDEX, detail::getClassRegistryKey()); // Stack: ns, co, st, cl + lua_insert(L, -2); // Stack: ns, co, cl, st + ++m_stackSize; + } + } + + //========================================================================================= + /** + * @brief Derive a new class. + * + * @param name The class name. + * @param parent A parent namespace object. + * @param staticKey Key where the class is stored. + */ + Class(const char* name, Namespace& parent, void const* const staticKey) + : ClassBase(parent) + { + assert(name != nullptr); + assert(lua_istable(L, -1)); // Stack: namespace table (ns) + + createConstTable(name); // Stack: ns, const table (co) + lua_pushcfunction(L, &detail::gc_metamethod); // Stack: ns, co, function + rawsetfield(L, -2, "__gc"); // co ["__gc"] = function. Stack: ns, co + ++m_stackSize; + + createClassTable(name); // Stack: ns, co, class table (cl) + lua_pushcfunction(L, &detail::gc_metamethod); // Stack: ns, co, cl, function + rawsetfield(L, -2, "__gc"); // cl ["__gc"] = function. Stack: ns, co, cl + ++m_stackSize; + + createStaticTable(name); // Stack: ns, co, cl, st + ++m_stackSize; + + lua_rawgetp( L, LUA_REGISTRYINDEX, staticKey); // Stack: ns, co, cl, st, parent st (pst) | nil + if (lua_isnil(L, -1)) // Stack: ns, co, cl, st, nil + { + ++m_stackSize; + + throw_or_assert("Base class is not registered"); + return; + } + + assert(lua_istable(L, -1)); // Stack: ns, co, cl, st, pst + + lua_rawgetp(L, -1, detail::getClassKey()); // Stack: ns, co, cl, st, pst, parent cl (pcl) + assert(lua_istable(L, -1)); + + lua_rawgetp(L, -1, detail::getConstKey()); // Stack: ns, co, cl, st, pst, pcl, parent co (pco) + assert(lua_istable(L, -1)); + + lua_rawsetp(L, -6, detail::getParentKey()); // co [parentKey] = pco. Stack: ns, co, cl, st, pst, pcl + lua_rawsetp(L, -4, detail::getParentKey()); // cl [parentKey] = pcl. Stack: ns, co, cl, st, pst + lua_rawsetp(L, -2, detail::getParentKey()); // st [parentKey] = pst. Stack: ns, co, cl, st + + lua_pushvalue(L, -1); // Stack: ns, co, cl, st, st + lua_rawsetp(L, LUA_REGISTRYINDEX, detail::getStaticRegistryKey()); // Stack: ns, co, cl, st + lua_pushvalue(L, -2); // Stack: ns, co, cl, st, cl + lua_rawsetp(L, LUA_REGISTRYINDEX, detail::getClassRegistryKey()); // Stack: ns, co, cl, st + lua_pushvalue(L, -3); // Stack: ns, co, cl, st, co + lua_rawsetp(L, LUA_REGISTRYINDEX, detail::getConstRegistryKey()); // Stack: ns, co, cl, st + } + + //========================================================================================= + /** + * @brief Continue registration in the enclosing namespace. + * + * @returns A parent registration object. + */ + Namespace endClass() + { + assert(m_stackSize > 3); + + m_stackSize -= 3; + lua_pop(L, 3); + return Namespace(*this); + } + + //========================================================================================= + /** + * @brief Add or replace a static property. + * + * @tparam U The type of the property. + * + * @param name The property name. + * @param value A property value pointer. + * @param isWritable True for a read-write, false for read-only property. + * + * @returns This class registration object. + */ + template + Class& addStaticProperty(const char* name, U* value, bool isWritable = true) + { + assert(name != nullptr); + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + lua_pushlightuserdata(L, value); // Stack: co, cl, st, pointer + lua_pushcclosure(L, &detail::property_getter::call, 1); // Stack: co, cl, st, getter + detail::add_property_getter(L, name, -2); // Stack: co, cl, st + + if (isWritable) + { + lua_pushlightuserdata(L, value); // Stack: co, cl, st, ps, pointer + lua_pushcclosure(L, &detail::property_setter::call, 1); // Stack: co, cl, st, ps, setter + } + else + { + lua_pushstring(L, name); // Stack: co, cl, st, name + lua_pushcclosure(L, &detail::read_only_error, 1); // Stack: co, cl, st, function + } + + detail::add_property_setter(L, name, -2); // Stack: co, cl, st + + return *this; + } + + //========================================================================================= + /** + * @brief Add or replace a static property member. + * + * @tparam U The type of the property. + * + * @param name The property name. + * @param get A property getter function pointer. + * @param set A property setter function pointer, optional, nullable. Omit or pass nullptr for a read-only property. + * + * @returns This class registration object. + */ + template + Class& addStaticProperty(const char* name, U (*get)(), void (*set)(U) = nullptr) + { + assert(name != nullptr); + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + lua_pushlightuserdata(L, reinterpret_cast(get)); // Stack: co, cl, st, function ptr + lua_pushcclosure(L, &detail::invoke_proxy_function, 1); // Stack: co, cl, st, getter + detail::add_property_getter(L, name, -2); // Stack: co, cl, st + + if (set != nullptr) + { + lua_pushlightuserdata(L, reinterpret_cast(set)); // Stack: co, cl, st, function ptr + lua_pushcclosure(L, &detail::invoke_proxy_function, 1); // Stack: co, cl, st, setter + } + else + { + lua_pushstring(L, name); // Stack: co, cl, st, ps, name + lua_pushcclosure(L, &detail::read_only_error, 1); // Stack: co, cl, st, function + } + + detail::add_property_setter(L, name, -2); // Stack: co, cl, st + + return *this; + } + + //========================================================================================= + /** + * @brief Add or replace a static member function. + */ + template >> + Class& addStaticFunction(const char* name, Function fp) + { + assert(name != nullptr); + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + lua_pushlightuserdata(L, reinterpret_cast(fp)); // Stack: co, cl, st, function ptr + lua_pushcclosure(L, &detail::invoke_proxy_function, 1); // co, cl, st, function + rawsetfield(L, -2, name); // co, cl, st + + return *this; + } + + //========================================================================================= + /** + * @brief Add or replace a static member function for constructible by std::function. + */ + template >> + Class addStaticFunction(const char* name, Function function) + { + using FnType = decltype(function); + + assert(name != nullptr); + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + lua_newuserdata_aligned(L, std::move(function)); // Stack: co, cl, st, function userdata (ud) + lua_newtable(L); // Stack: co, cl, st, ud, ud metatable (mt) + lua_pushcfunction(L, &lua_deleteuserdata_aligned); // Stack: co, cl, st, ud, mt, gc function + rawsetfield(L, -2, "__gc"); // Stack: co, cl, st, ud, mt + lua_setmetatable(L, -2); // Stack: co, cl, st, ud + lua_pushcclosure(L, &detail::invoke_proxy_functor, 1); // Stack: co, cl, st, function + rawsetfield(L, -2, name); // Stack: co, cl, st + + return *this; + } + + //========================================================================================= + /** + * @brief Add or replace a lua_CFunction. + * + * @param name The name of the function. + * @param fp A C-function pointer. + * + * @returns This class registration object. + */ + Class& addStaticFunction(const char* name, lua_CFunction fp) + { + assert(name != nullptr); + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + lua_pushcfunction(L, fp); // co, cl, st, function + rawsetfield(L, -2, name); // co, cl, st + + return *this; + } + + //========================================================================================= + /** + * @brief Add or replace a property member. + */ + template + Class& addProperty(const char* name, U V::*mp, bool isWritable = true) + { + static_assert(std::is_base_of_v); + + using MemberPtrType = decltype(mp); + + assert(name != nullptr); + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + new (lua_newuserdata(L, sizeof(MemberPtrType))) MemberPtrType(mp); // Stack: co, cl, st, field ptr + lua_pushcclosure(L, &detail::property_getter::call, 1); // Stack: co, cl, st, getter + lua_pushvalue(L, -1); // Stack: co, cl, st, getter, getter + detail::add_property_getter(L, name, -5); // Stack: co, cl, st, getter + detail::add_property_getter(L, name, -3); // Stack: co, cl, st + + if (isWritable) + { + new (lua_newuserdata(L, sizeof(MemberPtrType))) MemberPtrType(mp); // Stack: co, cl, st, field ptr + lua_pushcclosure(L, &detail::property_setter::call, 1); // Stack: co, cl, st, setter + detail::add_property_setter(L, name, -3); // Stack: co, cl, st + } + + return *this; + } + + //========================================================================================= + /** + * @brief Add or replace a property member. + */ + template + Class& addProperty(const char* name, TG (T::*get)() const, void (T::*set)(TS) = nullptr) + { + using GetType = TG (T::*)() const; + using SetType = void (T::*)(TS); + + assert(name != nullptr); + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + new (lua_newuserdata(L, sizeof(GetType))) GetType(get); // Stack: co, cl, st, funcion ptr + lua_pushcclosure(L, &detail::invoke_const_member_function, 1); // Stack: co, cl, st, getter + lua_pushvalue(L, -1); // Stack: co, cl, st, getter, getter + detail::add_property_getter(L, name, -5); // Stack: co, cl, st, getter + detail::add_property_getter(L, name, -3); // Stack: co, cl, st + + if (set != nullptr) + { + new (lua_newuserdata(L, sizeof(SetType))) SetType(set); // Stack: co, cl, st, function ptr + lua_pushcclosure(L, &detail::invoke_member_function, 1); // Stack: co, cl, st, setter + detail::add_property_setter(L, name, -3); // Stack: co, cl, st + } + + return *this; + } + + //========================================================================================= + /** + * @brief Add or replace a property member. + */ + template + Class& addProperty(const char* name, TG (T::*get)(lua_State*) const, void (T::*set)(TS, lua_State*) = nullptr) + { + using GetType = TG (T::*)(lua_State*) const; + using SetType = void (T::*)(TS, lua_State*); + + assert(name != nullptr); + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + new (lua_newuserdata(L, sizeof(GetType))) GetType(get); // Stack: co, cl, st, funcion ptr + lua_pushcclosure(L, &detail::invoke_const_member_function, 1); // Stack: co, cl, st, getter + lua_pushvalue(L, -1); // Stack: co, cl, st, getter, getter + detail::add_property_getter(L, name, -5); // Stack: co, cl, st, getter + detail::add_property_getter(L, name, -3); // Stack: co, cl, st + + if (set != nullptr) + { + new (lua_newuserdata(L, sizeof(SetType))) SetType(set); // Stack: co, cl, st, function ptr + lua_pushcclosure(L, &detail::invoke_member_function, 1); // Stack: co, cl, st, setter + detail::add_property_setter(L, name, -3); // Stack: co, cl, st + } + + return *this; + } + + //========================================================================================= + /** + * @brief Add or replace a property member, by proxy. + * + * When a class is closed for modification and does not provide (or cannot provide) the function signatures necessary to implement + * get or set for a property, this will allow non-member functions act as proxies. + * + * Both the get and the set functions require a T const* and T* in the first argument respectively. + */ + template + Class& addProperty(const char* name, TG (*get)(T const*), void (*set)(T*, TS) = nullptr) + { + assert(name != nullptr); + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + lua_pushlightuserdata(L, reinterpret_cast(get)); // Stack: co, cl, st, function ptr + lua_pushcclosure(L, &detail::invoke_proxy_function, 1); // Stack: co, cl, st, getter + lua_pushvalue(L, -1); // Stack: co, cl, st,, getter, getter + detail::add_property_getter(L, name, -5); // Stack: co, cl, st, getter + detail::add_property_getter(L, name, -3); // Stack: co, cl, st + + if (set != nullptr) + { + lua_pushlightuserdata( L, reinterpret_cast(set)); // Stack: co, cl, st, function ptr + lua_pushcclosure(L, &detail::invoke_proxy_function, 1); // Stack: co, cl, st, setter + detail::add_property_setter(L, name, -3); // Stack: co, cl, st + } + + return *this; + } + + //========================================================================================= + /** + * @brief Add or replace a property member, by proxy C-function. + * + * When a class is closed for modification and does not provide (or cannot provide) the function signatures necessary to implement + * get or set for a property, this will allow non-member functions act as proxies. + * + * The object userdata ('this') value is at the index 1. + * The new value for set function is at the index 2. + */ + Class& addProperty(const char* name, lua_CFunction get, lua_CFunction set = nullptr) + { + assert(name != nullptr); + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + lua_pushcfunction(L, get); + lua_pushvalue(L, -1); // Stack: co, cl, st,, getter, getter + detail::add_property_getter(L, name, -5); // Stack: co, cl, st,, getter + detail::add_property_getter(L, name, -3); // Stack: co, cl, st, + + if (set != nullptr) + { + lua_pushcfunction(L, set); + detail::add_property_setter(L, name, -3); // Stack: co, cl, st, + } + + return *this; + } + + //========================================================================================= + /** + * @brief Add or replace a property member, by constructible by std::function. + */ + template >> + Class& addProperty(const char* name, Getter get) + { + using FirstArg = detail::function_argument_t<0, Getter>; + static_assert(std::is_same_v>, T>); + + assert(name != nullptr); + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + using GetType = decltype(get); + + lua_newuserdata_aligned(L, std::move(get)); // Stack: co, cl, st, function userdata (ud) + lua_newtable(L); // Stack: co, cl, st, ud, ud metatable (mt) + lua_pushcfunction(L, &lua_deleteuserdata_aligned); // Stack: co, cl, st, ud, mt, gc function + rawsetfield(L, -2, "__gc"); // Stack: co, cl, st, ud, mt + lua_setmetatable(L, -2); // Stack: co, cl, st, ud + lua_pushcclosure(L, &detail::invoke_proxy_functor, 1); // Stack: co, cl, st, getter + lua_pushvalue(L, -1); // Stack: co, cl, st, getter, getter + detail::add_property_getter(L, name, -4); // Stack: co, cl, st, getter + detail::add_property_getter(L, name, -4); // Stack: co, cl, st + + return *this; + } + + template && !std::is_pointer_v>> + Class& addProperty(const char* name, Getter get, Setter set) + { + addProperty(name, std::move(get)); + + using FirstArg = detail::function_argument_t<0, Setter>; + static_assert(std::is_same_v>, T>); + + assert(name != nullptr); + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + using SetType = decltype(set); + + lua_newuserdata_aligned(L, std::move(set)); // Stack: co, cl, st, function userdata (ud) + lua_newtable(L); // Stack: co, cl, st, ud, ud metatable (mt) + lua_pushcfunction(L, &lua_deleteuserdata_aligned); // Stack: co, cl, st, ud, mt, gc function + rawsetfield(L, -2, "__gc"); // Stack: co, cl, st, ud, mt + lua_setmetatable(L, -2); // Stack: co, cl, st, ud + lua_pushcclosure(L, &detail::invoke_proxy_functor, 1); // Stack: co, cl, st, setter + detail::add_property_setter(L, name, -3); // Stack: co, cl, st + + return *this; + } + + //========================================================================================= + /** + * @brief Add or replace a namespace function by convertible to std::function (capturing lambdas). + */ + template != 0>> + Class addFunction(const char* name, Function function) + { + using FnType = decltype(function); + + using FirstArg = detail::function_argument_t<0, Function>; + static_assert(std::is_same_v>, T>); + + assert(name != nullptr); + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + if (name == std::string_view("__gc")) + { + throw_or_assert("__gc metamethod registration is forbidden"); + return *this; + } + + lua_newuserdata_aligned(L, std::move(function)); // Stack: co, cl, st, function userdata (ud) + lua_newtable(L); // Stack: co, cl, st, ud, ud metatable (mt) + lua_pushcfunction(L, &lua_deleteuserdata_aligned); // Stack: co, cl, st, ud, mt, gc function + rawsetfield(L, -2, "__gc"); // Stack: co, cl, st, ud, mt + lua_setmetatable(L, -2); // Stack: co, cl, st, ud + + lua_pushcclosure(L, &detail::invoke_proxy_functor, 1); // Stack: co, cl, st, function + + if constexpr (! std::is_const_v>>) + { + rawsetfield(L, -3, name); // Stack: co, cl, st + } + else + { + lua_pushvalue(L, -1); // Stack: co, cl, st, function, function + rawsetfield(L, -4, name); // Stack: co, cl, st, function + rawsetfield(L, -4, name); // Stack: co, cl, st + } + + return *this; + } + + //========================================================================================= + /** + * @brief Add or replace a member function. + */ + template + Class& addFunction(const char* name, ReturnType (U::*mf)(Params...)) + { + static_assert(std::is_base_of_v); + + using MemFn = decltype(mf); + + assert(name != nullptr); + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + if (name == std::string_view("__gc")) + { + throw_or_assert("__gc metamethod registration is forbidden"); + return *this; + } + + new (lua_newuserdata(L, sizeof(MemFn))) MemFn(mf); + lua_pushcclosure(L, &detail::invoke_member_function, 1); + rawsetfield(L, -3, name); // class table + + return *this; + } + + template + Class& addFunction(const char* name, ReturnType (U::*mf)(Params...) const) + { + static_assert(std::is_base_of_v); + + using MemFn = decltype(mf); + + assert(name != nullptr); + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + if (name == std::string_view("__gc")) + { + throw_or_assert("__gc metamethod registration is forbidden"); + return *this; + } + + new (lua_newuserdata(L, sizeof(MemFn))) MemFn(mf); + lua_pushcclosure(L, &detail::invoke_const_member_function, 1); + lua_pushvalue(L, -1); + rawsetfield(L, -5, name); // const table + rawsetfield(L, -3, name); // class table + + return *this; + } + + //========================================================================================= + /** + * @brief Add or replace a proxy function. + */ + template + Class& addFunction(const char* name, ReturnType (*proxyFn)(T* object, Params...)) + { + using FnType = decltype(proxyFn); + + assert(name != nullptr); + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + if (name == std::string_view("__gc")) + { + throw_or_assert("__gc metamethod registration is forbidden"); + return *this; + } + + lua_pushlightuserdata(L, reinterpret_cast(proxyFn)); // Stack: co, cl, st, function ptr + lua_pushcclosure(L, &detail::invoke_proxy_function, 1); // Stack: co, cl, st, function + rawsetfield(L, -3, name); // Stack: co, cl, st + + return *this; + } + + template + Class& addFunction(const char* name, ReturnType (*proxyFn)(const T* object, Params...)) + { + using FnType = decltype(proxyFn); + + assert(name != nullptr); + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + if (name == std::string_view("__gc")) + { + throw_or_assert("__gc metamethod registration is forbidden"); + return *this; + } + + lua_pushlightuserdata(L, reinterpret_cast(proxyFn)); // Stack: co, cl, st, function ptr + lua_pushcclosure(L, &detail::invoke_proxy_function, 1); // Stack: co, cl, st, function + lua_pushvalue(L, -1); // Stack: co, cl, st, function, function + rawsetfield(L, -4, name); // Stack: co, cl, st, function + rawsetfield(L, -4, name); // Stack: co, cl, st + + return *this; + } + + //========================================================================================= + /** + * @brief Add or replace a member lua_CFunction. + */ + template + Class& addFunction(const char* name, int (U::*mfp)(lua_State*)) + { + static_assert(std::is_base_of_v); + + using F = decltype(mfp); + + assert(name != nullptr); + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + if (name == std::string_view("__gc")) + { + throw_or_assert("__gc metamethod registration is forbidden"); + return *this; + } + + new (lua_newuserdata(L, sizeof(mfp))) F(mfp); // Stack: co, cl, st, function ptr + lua_pushcclosure(L, &detail::invoke_member_cfunction, 1); // Stack: co, cl, st, function + rawsetfield(L, -3, name); // Stack: co, cl, st + + return *this; + } + + //========================================================================================= + /** + * @brief Add or replace a const member lua_CFunction. + */ + template + Class& addFunction(const char* name, int (U::*mfp)(lua_State*) const) + { + static_assert(std::is_base_of_v); + + using F = decltype(mfp); + + assert(name != nullptr); + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + if (name == std::string_view("__gc")) + { + throw_or_assert("__gc metamethod registration is forbidden"); + return *this; + } + + new (lua_newuserdata(L, sizeof(mfp))) F(mfp); + lua_pushcclosure(L, &detail::invoke_const_member_cfunction, 1); + lua_pushvalue(L, -1); // Stack: co, cl, st, function, function + rawsetfield(L, -4, name); // Stack: co, cl, st, function + rawsetfield(L, -4, name); // Stack: co, cl, st + + return *this; + } + + //========================================================================================= + /** + * @brief Add or replace a free lua_CFunction that works as a member. + * + * This object is at top of the stack, then all other arguments. + */ + Class& addFunction(const char* name, lua_CFunction fp) + { + assert(name != nullptr); + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + if (name == std::string_view("__gc")) + { + throw_or_assert("__gc metamethod registration is forbidden"); + return *this; + } + + lua_pushcfunction(L, fp); // Stack: co, cl, st, function + rawsetfield(L, -3, name); // Stack: co, cl, st + + return *this; + } + + //========================================================================================= + /** + * @brief Add or replace a primary Constructor. + * + * The primary Constructor is invoked when calling the class type table like a function. + * + * The template parameter should be a function pointer type that matches the desired Constructor (since you can't take the + * address of a Constructor and pass it as an argument). + */ + template + Class& addConstructor() + { + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + lua_pushcclosure(L, &ctorContainerProxy, C>, 0); + rawsetfield(L, -2, "__call"); + + return *this; + } + + template + Class& addConstructor() + { + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + lua_pushcclosure(L, &ctorPlacementProxy, T>, 0); + rawsetfield(L, -2, "__call"); + + return *this; + } + + //========================================================================================= + /** + * @brief Add or replace a factory. + * + * The primary Constructor is invoked when calling the class type table like a function. + * + * The template parameter should be a function pointer type that matches the desired Constructor (since you can't take the + * address of a Constructor and pass it as an argument). + */ + template + Class addConstructor(Function function) + { + assertStackState(); // Stack: const table (co), class table (cl), static table (st) + + auto factory = [function = std::move(function)](lua_State* L) -> T* + { + std::error_code ec; + detail::UserdataValue* value = detail::UserdataValue::place(L, ec); + if (! value) + luaL_error(L, ec.message().c_str()); + + using FnTraits = detail::function_traits; + using FnArgs = detail::remove_first_type_t; + + T* obj = detail::factory::call(value->getObject(), function, detail::make_arguments_list(L)); + + value->commit(); + + return obj; + }; + + using FactoryFnType = decltype(factory); + + lua_newuserdata_aligned(L, std::move(factory)); // Stack: co, cl, st, function userdata (ud) + lua_newtable(L); // Stack: co, cl, st, ud, ud metatable (mt) + lua_pushcfunction(L, &lua_deleteuserdata_aligned); // Stack: co, cl, st, ud, mt, gc function + rawsetfield(L, -2, "__gc"); // Stack: co, cl, st, ud, mt + lua_setmetatable(L, -2); // Stack: co, cl, st, ud + + lua_pushcclosure(L, &detail::invoke_proxy_functor, 1); // Stack: co, cl, st, function + rawsetfield(L, -2, "__call"); // Stack: co, cl, st + + return *this; + } + }; + +private: + struct FromStack {}; + + //============================================================================================= + /** + * @brief Open the global namespace for registrations. + * + * @param L A Lua state. + */ + explicit Namespace(lua_State* L) + : Registrar(L) + { + lua_getglobal(L, "_G"); + + ++m_stackSize; + } + + //============================================================================================= + /** + * @brief Open the a namespace for registrations from a table on top of the stack. + * + * @param L A Lua state. + */ + Namespace(lua_State* L, FromStack) + : Registrar(L, 1) + { + assert(lua_istable(L, -1)); + + { + lua_pushvalue(L, -1); // Stack: ns, mt + + // ns.__metatable = ns + lua_setmetatable(L, -2); // Stack: ns, mt + + // ns.__index = index_metamethod + lua_pushcfunction(L, &detail::index_metamethod); + rawsetfield(L, -2, "__index"); // Stack: ns + + lua_newtable(L); // Stack: ns, mt, propget table (pg) + lua_rawsetp(L, -2, detail::getPropgetKey()); // ns [propgetKey] = pg. Stack: ns + + lua_newtable(L); // Stack: ns, mt, propset table (ps) + lua_rawsetp(L, -2, detail::getPropsetKey()); // ns [propsetKey] = ps. Stack: ns + } + + ++m_stackSize; + } + + //============================================================================================= + /** + * @brief Open a namespace for registrations. + * + * The namespace is created if it doesn't already exist. + * + * @param name The namespace name. + * @param parent The parent namespace object. + * + * @pre The parent namespace is at the top of the Lua stack. + */ + Namespace(const char* name, Namespace& parent) + : Registrar(parent) + { + assert(name != nullptr); + assert(lua_istable(L, -1)); // Stack: parent namespace (pns) + + rawgetfield(L, -1, name); // Stack: pns, namespace (ns) | nil + + if (lua_isnil(L, -1)) // Stack: pns, nil + { + lua_pop(L, 1); // Stack: pns + + lua_newtable(L); // Stack: pns, ns + lua_pushvalue(L, -1); // Stack: pns, ns, mt + + // ns.__metatable = ns + lua_setmetatable(L, -2); // Stack: pns, ns + + // ns.__index = index_metamethod + lua_pushcfunction(L, &detail::index_metamethod); + rawsetfield(L, -2, "__index"); // Stack: pns, ns + + // ns.__newindex = newindex_static_metamethod + lua_pushcfunction(L, &detail::newindex_static_metamethod); + rawsetfield(L, -2, "__newindex"); // Stack: pns, ns + + lua_newtable(L); // Stack: pns, ns, propget table (pg) + lua_rawsetp(L, -2, detail::getPropgetKey()); // ns [propgetKey] = pg. Stack: pns, ns + + lua_newtable(L); // Stack: pns, ns, propset table (ps) + lua_rawsetp(L, -2, detail::getPropsetKey()); // ns [propsetKey] = ps. Stack: pns, ns + + // pns [name] = ns + lua_pushvalue(L, -1); // Stack: pns, ns, ns + rawsetfield(L, -3, name); // Stack: pns, ns + } + + ++m_stackSize; + } + + //============================================================================================= + /** + * @brief Close the class and continue the namespace registrations. + * + * @param child A child class registration object. + */ + explicit Namespace(ClassBase& child) + : Registrar(child) + { + } + + using Registrar::operator=; + +public: + //============================================================================================= + /** + * @brief Retrieve the global namespace. + * + * It is recommended to put your namespace inside the global namespace, and then add your classes and functions to it, rather than + * adding many classes and functions directly to the global namespace. + * + * @param L A Lua state. + * + * @returns A namespace registration object. + */ + static Namespace getGlobalNamespace(lua_State* L) + { + return Namespace(L); + } + + /** + * @brief Retrieve the namespace on top of the stack. + * + * You should have a table on top of the stack before calling this function. It will then use the table there as destination for registrations. + * + * @param L A Lua state. + * + * @returns A namespace registration object. + */ + static Namespace getNamespaceFromStack(lua_State* L) + { + return Namespace(L, FromStack{}); + } + + //============================================================================================= + /** + * @brief Open a new or existing namespace for registrations. + * + * @param name The namespace name. + * + * @returns A namespace registration object. + */ + Namespace beginNamespace(const char* name) + { + assertIsActive(); + return Namespace(name, *this); + } + + //============================================================================================= + /** + * @brief Continue namespace registration in the parent. + * + * Do not use this on the global namespace. + * + * @returns A parent namespace registration object. + */ + Namespace endNamespace() + { + if (m_stackSize == 1) + { + throw_or_assert("endNamespace() called on global namespace"); + + return Namespace(*this); + } + + assert(m_stackSize > 1); + --m_stackSize; + lua_pop(L, 1); + return Namespace(*this); + } + + //============================================================================================= + /** + * @brief Add or replace a property. + * + * @param name The property name. + * @param value A value pointer. + * @param isWritable True for a read-write, false for read-only property. + * + * @returns This namespace registration object. + */ + template + Namespace& addProperty(const char* name, T* value, bool isWritable = true) + { + if (m_stackSize == 1) + { + throw_or_assert("addProperty() called on global namespace"); + + return *this; + } + + assert(name != nullptr); + assert(lua_istable(L, -1)); // Stack: namespace table (ns) + + lua_pushlightuserdata(L, value); // Stack: ns, pointer + lua_pushcclosure(L, &detail::property_getter::call, 1); // Stack: ns, getter + detail::add_property_getter(L, name, -2); // Stack: ns + + if (isWritable) + { + lua_pushlightuserdata(L, value); // Stack: ns, pointer + lua_pushcclosure(L, &detail::property_setter::call, 1); // Stack: ns, setter + } + else + { + lua_pushstring(L, name); // Stack: ns, ps, name + lua_pushcclosure(L, &detail::read_only_error, 1); // Stack: ns, function + } + + detail::add_property_setter(L, name, -2); // Stack: ns + + return *this; + } + + //============================================================================================= + /** + * @brief Add or replace a property. + * + * If the set function is omitted or null, the property is read-only. + * + * @param name The property name. + * @param get A pointer to a property getter function. + * @param set A pointer to a property setter function, optional. + * + * @returns This namespace registration object. + */ + template + Namespace& addProperty(const char* name, TG (*get)(), void (*set)(TS) = nullptr) + { + if (m_stackSize == 1) + { + throw_or_assert("addProperty() called on global namespace"); + + return *this; + } + + assert(name != nullptr); + assert(lua_istable(L, -1)); // Stack: namespace table (ns) + + lua_pushlightuserdata(L, reinterpret_cast(get)); // Stack: ns, function ptr + lua_pushcclosure(L, &detail::invoke_proxy_function, 1); // Stack: ns, getter + detail::add_property_getter(L, name, -2); + + if (set != nullptr) + { + lua_pushlightuserdata(L, reinterpret_cast(set)); // Stack: ns, function ptr + lua_pushcclosure(L, &detail::invoke_proxy_function, 1); + } + else + { + lua_pushstring(L, name); + lua_pushcclosure(L, &detail::read_only_error, 1); + } + + detail::add_property_setter(L, name, -2); + + return *this; + } + + //============================================================================================= + /** + * @brief Add or replace a readonly property. + * + * @param name The property name. + * @param get A pointer to a property getter function. + * + * @returns This namespace registration object. + */ + template + Namespace& addProperty(const char* name, Getter get) + { + using GetType = decltype(get); + + assert(name != nullptr); + assert(lua_istable(L, -1)); // Stack: namespace table (ns) + + lua_newuserdata_aligned(L, std::move(get)); // Stack: ns, function userdata (ud) + lua_newtable(L); // Stack: ns, ud, ud metatable (mt) + lua_pushcfunction(L, &lua_deleteuserdata_aligned); // Stack: ns, ud, mt, gc function + rawsetfield(L, -2, "__gc"); // Stack: ns, ud, mt + lua_setmetatable(L, -2); // Stack: ns, ud + lua_pushcclosure(L, &detail::invoke_proxy_functor, 1); // Stack: ns, ud, getter + detail::add_property_getter(L, name, -2); // Stack: ns, ud, getter + + lua_pushstring(L, name); // Stack: ns, name + lua_pushcclosure(L, &detail::read_only_error, 1); // Stack: ns, name, function + detail::add_property_setter(L, name, -2); // Stack: ns + + return *this; + } + + /** + * @brief Add or replace a mutable property. + * + * @param name The property name. + * @param get A pointer to a property getter function. + * @param set A pointer to a property setter function. + * + * @returns This namespace registration object. + */ + template + Namespace& addProperty(const char* name, Getter get, Setter set) + { + assert(name != nullptr); + assert(lua_istable(L, -1)); // Stack: namespace table (ns) + + addProperty(name, std::move(get)); + + using SetType = decltype(set); + + lua_newuserdata_aligned(L, std::move(set)); // Stack: ns, function userdata (ud) + lua_newtable(L); // Stack: ns, ud, ud metatable (mt) + lua_pushcfunction(L, &lua_deleteuserdata_aligned); // Stack: ns, ud, mt, gc function + rawsetfield(L, -2, "__gc"); // Stack: ns, ud, mt + lua_setmetatable(L, -2); // Stack: ns, ud + lua_pushcclosure(L, &detail::invoke_proxy_functor, 1); // Stack: ns, ud, getter + detail::add_property_setter(L, name, -2); // Stack: ns, ud, getter + + return *this; + } + + //============================================================================================= + /** + * @brief Add or replace a property. + * + * If the set function is omitted or null, the property is read-only. + * + * @param name The property name. + * @param get A pointer to a property getter function. + * @param set A pointer to a property setter function, optional. + * + * @returns This namespace registration object. + */ + Namespace& addProperty(const char* name, lua_CFunction get, lua_CFunction set = nullptr) + { + assert(name != nullptr); + assert(lua_istable(L, -1)); // Stack: namespace table (ns) + + lua_pushcfunction(L, get); // Stack: ns, getter + detail::add_property_getter(L, name, -2); // Stack: ns + + if (set != nullptr) + { + lua_pushcfunction(L, set); // Stack: ns, setter + detail::add_property_setter(L, name, -2); // Stack: ns + } + else + { + lua_pushstring(L, name); // Stack: ns, name + lua_pushcclosure(L, &detail::read_only_error, 1); // Stack: ns, name, function + detail::add_property_setter(L, name, -2); // Stack: ns + } + + return *this; + } + + //============================================================================================= + /** + * @brief Add or replace a namespace function by convertible to std::function. + */ + template + Namespace& addFunction(const char* name, Function function) + { + using FnType = decltype(function); + + assert(name != nullptr); + assert(lua_istable(L, -1)); // Stack: namespace table (ns) + + lua_newuserdata_aligned(L, std::move(function)); // Stack: ns, function userdata (ud) + lua_newtable(L); // Stack: ns, ud, ud metatable (mt) + lua_pushcfunction(L, &lua_deleteuserdata_aligned); // Stack: ns, ud, mt, gc function + rawsetfield(L, -2, "__gc"); // Stack: ns, ud, mt + lua_setmetatable(L, -2); // Stack: ns, ud + lua_pushcclosure(L, &detail::invoke_proxy_functor, 1); // Stack: ns, function + rawsetfield(L, -2, name); // Stack: ns + + return *this; + } + + //============================================================================================= + /** + * @brief Add or replace a free function. + */ + template + Namespace& addFunction(const char* name, ReturnType (*fp)(Params...)) + { + using FnType = decltype(fp); + + assert(name != nullptr); + assert(lua_istable(L, -1)); // Stack: namespace table (ns) + + lua_pushlightuserdata(L, reinterpret_cast(fp)); // Stack: ns, function ptr + lua_pushcclosure(L, &detail::invoke_proxy_function, 1); // Stack: ns, function + rawsetfield(L, -2, name); // Stack: ns + + return *this; + } + + //============================================================================================= + /** + * @brief Add or replace a lua_CFunction. + * + * @param name The function name. + * @param fp A C-function pointer. + * + * @returns This namespace registration object. + */ + Namespace& addFunction(const char* name, lua_CFunction fp) + { + assert(name != nullptr); + assert(lua_istable(L, -1)); // Stack: namespace table (ns) + + lua_pushcfunction(L, fp); // Stack: ns, function + rawsetfield(L, -2, name); // Stack: ns + + return *this; + } + + //============================================================================================= + /** + * @brief Open a new or existing class for registrations. + * + * @param name The class name. + * + * @returns A class registration object. + */ + template + Class beginClass(const char* name) + { + assertIsActive(); + return Class(name, *this); + } + + //============================================================================================= + /** + * @brief Derive a new class for registrations. + * + * Call deriveClass() only once. To continue registrations for the class later, use beginClass(). + * + * @param name The class name. + * + * @returns A class registration object. + */ + template + Class deriveClass(const char* name) + { + assertIsActive(); + return Class(name, *this, detail::getStaticRegistryKey()); + } +}; + +//================================================================================================= +/** + * @brief Retrieve the global namespace. + * + * It is recommended to put your namespace inside the global namespace, and then add your classes and functions to it, rather than adding + * many classes and functions directly to the global namespace. + * + * @param L A Lua state. + * + * @returns A namespace registration object. + */ +inline Namespace getGlobalNamespace(lua_State* L) +{ + return Namespace::getGlobalNamespace(L); +} + +//================================================================================================= +/** + * @brief Retrieve the namespace on top of the stack. + * + * You should have a table on top of the stack before calling this function. It will then use the table there as destination for registrations. + * + * @param L A Lua state. + * + * @returns A namespace registration object. + */ +inline Namespace getNamespaceFromStack(lua_State* L) +{ + return Namespace::getNamespaceFromStack(L); +} + +} // namespace luabridge + +// End File: Source/LuaBridge/detail/Namespace.h + +// Begin File: Source/LuaBridge/LuaBridge.h + +// https://github.com/kunitoki/LuaBridge3 +// Copyright 2020, Lucio Asnaghi +// Copyright 2020, Dmitry Tarakanov +// Copyright 2012, Vinnie Falco +// Copyright 2007, Nathan Reed +// SPDX-License-Identifier: MIT + +// All #include dependencies are listed here +// instead of in the individual header files. + +#define LUABRIDGE_MAJOR_VERSION 3 +#define LUABRIDGE_MINOR_VERSION 1 +#define LUABRIDGE_VERSION 301 + +#ifndef LUA_VERSION_NUM +#error "Lua headers must be included prior to LuaBridge ones" +#endif + + +// End File: Source/LuaBridge/LuaBridge.h + +// Begin File: Source/LuaBridge/List.h + +// https://github.com/kunitoki/LuaBridge3 +// Copyright 2020, Lucio Asnaghi +// Copyright 2020, Dmitry Tarakanov +// SPDX-License-Identifier: MIT + +namespace luabridge { + +//================================================================================================= +/** + * @brief Stack specialization for `std::array`. + */ +template +struct Stack> +{ + using Type = std::list; + + static bool push(lua_State* L, const Type& list, std::error_code& ec) + { + const int initialStackSize = lua_gettop(L); + + lua_createtable(L, static_cast(list.size()), 0); + + auto it = list.cbegin(); + for (lua_Integer tableIndex = 1; it != list.cend(); ++tableIndex, ++it) + { + lua_pushinteger(L, tableIndex); + + std::error_code errorCode; + if (! Stack::push(L, *it, errorCode)) + { + ec = errorCode; + lua_pop(L, lua_gettop(L) - initialStackSize); + return false; + } + + lua_settable(L, -3); + } + + return true; + } + + static Type get(lua_State* L, int index) + { + if (!lua_istable(L, index)) + luaL_error(L, "#%d argument must be a table", index); + + Type list; + + int absIndex = lua_absindex(L, index); + lua_pushnil(L); + + while (lua_next(L, absIndex) != 0) + { + list.emplace_back(Stack::get(L, -1)); + lua_pop(L, 1); + } + + return list; + } + + static bool isInstance(lua_State* L, int index) + { + return lua_istable(L, index); + } +}; + +} // namespace luabridge + +// End File: Source/LuaBridge/List.h + +// Begin File: Source/LuaBridge/Array.h + +// https://github.com/kunitoki/LuaBridge3 +// Copyright 2020, Lucio Asnaghi +// Copyright 2020, Dmitry Tarakanov +// SPDX-License-Identifier: MIT + +namespace luabridge { + +//================================================================================================= +/** + * @brief Stack specialization for `std::array`. + */ +template +struct Stack> +{ + using Type = std::array; + + static bool push(lua_State* L, const Type& array, std::error_code& ec) + { + const int initialStackSize = lua_gettop(L); + + lua_createtable(L, static_cast(Size), 0); + + for (std::size_t i = 0; i < Size; ++i) + { + lua_pushinteger(L, static_cast(i + 1)); + + std::error_code errorCode; + bool result = Stack::push(L, array[i], errorCode); + if (!result) + { + ec = errorCode; + lua_pop(L, lua_gettop(L) - initialStackSize); + return false; + } + + lua_settable(L, -3); + } + + return true; + } + + static Type get(lua_State* L, int index) + { + if (!lua_istable(L, index)) + luaL_error(L, "#%d argment must be a table", index); + + if (get_length(L, index) != Size) + luaL_error(L, "table size should be %d but is %d", Size, get_length(L, index)); + + Type array; + + int absIndex = lua_absindex(L, index); + lua_pushnil(L); + + int arrayIndex = 0; + while (lua_next(L, absIndex) != 0) + { + array[arrayIndex++] = Stack::get(L, -1); + lua_pop(L, 1); + } + + return array; + } +}; + +} // namespace luabridge + +// End File: Source/LuaBridge/Array.h + +// Begin File: Source/LuaBridge/Vector.h + +// https://github.com/kunitoki/LuaBridge3 +// Copyright 2020, Lucio Asnaghi +// Copyright 2018, Dmitry Tarakanov +// SPDX-License-Identifier: MIT + +namespace luabridge { + +//================================================================================================= +/** + * @brief Stack specialization for `std::vector`. + */ +template +struct Stack> +{ + using Type = std::vector; + + static bool push(lua_State* L, const Type& vector, std::error_code& ec) + { + const int initialStackSize = lua_gettop(L); + + lua_createtable(L, static_cast(vector.size()), 0); + + for (std::size_t i = 0; i < vector.size(); ++i) + { + lua_pushinteger(L, static_cast(i + 1)); + + std::error_code errorCode; + if (! Stack::push(L, vector[i], errorCode)) + { + ec = errorCode; + lua_pop(L, lua_gettop(L) - initialStackSize); + return false; + } + + lua_settable(L, -3); + } + + return true; + } + + static Type get(lua_State* L, int index) + { + if (!lua_istable(L, index)) + luaL_error(L, "#%d argument must be a table", index); + + Type vector; + vector.reserve(static_cast(get_length(L, index))); + + int absIndex = lua_absindex(L, index); + lua_pushnil(L); + + while (lua_next(L, absIndex) != 0) + { + vector.emplace_back(Stack::get(L, -1)); + lua_pop(L, 1); + } + + return vector; + } + + static bool isInstance(lua_State* L, int index) + { + return lua_istable(L, index); + } +}; + +} // namespace luabridge + +// End File: Source/LuaBridge/Vector.h + +// Begin File: Source/LuaBridge/Set.h + +// https://github.com/kunitoki/LuaBridge3 +// Copyright 2020, Lucio Asnaghi +// SPDX-License-Identifier: MIT + +namespace luabridge { + +//================================================================================================= +/** + * @brief Stack specialization for `std::set`. + */ +template +struct Stack> +{ + using Type = std::set; + + static bool push(lua_State* L, const Type& set, std::error_code& ec) + { + const int initialStackSize = lua_gettop(L); + + lua_createtable(L, 0, static_cast(set.size())); + + for (auto it = set.begin(); it != set.end(); ++it) + { + std::error_code errorCodeKey; + if (! Stack::push(L, it->first, errorCodeKey)) + { + ec = errorCodeKey; + lua_pop(L, lua_gettop(L) - initialStackSize); + return false; + } + + std::error_code errorCodeValue; + if (! Stack::push(L, it->second, errorCodeValue)) + { + ec = errorCodeValue; + lua_pop(L, lua_gettop(L) - initialStackSize); + return false; + } + + lua_settable(L, -3); + } + + return true; + } + + static Type get(lua_State* L, int index) + { + if (!lua_istable(L, index)) + luaL_error(L, "#%d argument must be a table", index); + + Type set; + + int absIndex = lua_absindex(L, index); + lua_pushnil(L); + + while (lua_next(L, absIndex) != 0) + { + set.emplace(Stack::get(L, -2), Stack::get(L, -1)); + lua_pop(L, 1); + } + + return set; + } + + static bool isInstance(lua_State* L, int index) + { + return lua_istable(L, index); + } +}; + +} // namespace luabridge + +// End File: Source/LuaBridge/Set.h + +// Begin File: Source/LuaBridge/RefCountedObject.h + +// https://github.com/kunitoki/LuaBridge3 +// Copyright 2020, Lucio Asnaghi +// Copyright 2012, Vinnie Falco +// Copyright 2004-11 by Raw Material Software Ltd. +// SPDX-License-Identifier: MIT + +//============================================================================== +/* + This is a derivative work used by permission from part of + JUCE, available at http://www.rawaterialsoftware.com + + License: The MIT License (http://www.opensource.org/licenses/mit-license.php) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + This file incorporates work covered by the following copyright and + permission notice: + + This file is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-11 by Raw Material Software Ltd. +*/ +//============================================================================== + +namespace luabridge { + +//============================================================================== +/** + Adds reference-counting to an object. + + To add reference-counting to a class, derive it from this class, and + use the RefCountedObjectPtr class to point to it. + + e.g. @code + class MyClass : public RefCountedObjectType + { + void foo(); + + // This is a neat way of declaring a typedef for a pointer class, + // rather than typing out the full templated name each time.. + typedef RefCountedObjectPtr Ptr; + }; + + MyClass::Ptr p = new MyClass(); + MyClass::Ptr p2 = p; + p = 0; + p2->foo(); + @endcode + + Once a new RefCountedObjectType has been assigned to a pointer, be + careful not to delete the object manually. +*/ +template +class RefCountedObjectType +{ +public: + //============================================================================== + /** Increments the object's reference count. + + This is done automatically by the smart pointer, but is public just + in case it's needed for nefarious purposes. + */ + inline void incReferenceCount() const { ++refCount; } + + /** Decreases the object's reference count. + + If the count gets to zero, the object will be deleted. + */ + inline void decReferenceCount() const + { + assert(getReferenceCount() > 0); + + if (--refCount == 0) + delete this; + } + + /** Returns the object's current reference count. + * @returns The reference count. + */ + inline int getReferenceCount() const { return static_cast(refCount); } + +protected: + //============================================================================== + /** Creates the reference-counted object (with an initial ref count of zero). */ + RefCountedObjectType() : refCount() {} + + /** Destructor. */ + virtual ~RefCountedObjectType() + { + // it's dangerous to delete an object that's still referenced by something else! + assert(getReferenceCount() == 0); + } + +private: + //============================================================================== + CounterType mutable refCount; +}; + +//============================================================================== + +/** Non thread-safe reference counted object. + + This creates a RefCountedObjectType that uses a non-atomic integer + as the counter. +*/ +typedef RefCountedObjectType RefCountedObject; + +//============================================================================== +/** + A smart-pointer class which points to a reference-counted object. + + The template parameter specifies the class of the object you want to point + to - the easiest way to make a class reference-countable is to simply make + it inherit from RefCountedObjectType, but if you need to, you could roll + your own reference-countable class by implementing a pair of methods called + incReferenceCount() and decReferenceCount(). + + When using this class, you'll probably want to create a typedef to + abbreviate the full templated name - e.g. + + @code + + typedef RefCountedObjectPtr MyClassPtr; + + @endcode +*/ +template +class RefCountedObjectPtr +{ +public: + /** The class being referenced by this pointer. */ + typedef ReferenceCountedObjectClass ReferencedType; + + //============================================================================== + /** Creates a pointer to a null object. */ + inline RefCountedObjectPtr() : referencedObject(0) {} + + /** Creates a pointer to an object. + This will increment the object's reference-count if it is non-null. + + @param refCountedObject A reference counted object to own. + */ + inline RefCountedObjectPtr(ReferenceCountedObjectClass* const refCountedObject) + : referencedObject(refCountedObject) + { + if (refCountedObject != 0) + refCountedObject->incReferenceCount(); + } + + /** Copies another pointer. + This will increment the object's reference-count (if it is non-null). + + @param other Another pointer. + */ + inline RefCountedObjectPtr(const RefCountedObjectPtr& other) + : referencedObject(other.referencedObject) + { + if (referencedObject != 0) + referencedObject->incReferenceCount(); + } + + /** + Takes-over the object from another pointer. + + @param other Another pointer. + */ + inline RefCountedObjectPtr(RefCountedObjectPtr&& other) + : referencedObject(other.referencedObject) + { + other.referencedObject = 0; + } + + /** Copies another pointer. + This will increment the object's reference-count (if it is non-null). + + @param other Another pointer. + */ + template + inline RefCountedObjectPtr(const RefCountedObjectPtr& other) + : referencedObject(static_cast(other.getObject())) + { + if (referencedObject != 0) + referencedObject->incReferenceCount(); + } + + /** Changes this pointer to point at a different object. + + The reference count of the old object is decremented, and it might be + deleted if it hits zero. The new object's count is incremented. + + @param other A pointer to assign from. + @returns This pointer. + */ + RefCountedObjectPtr& operator=(const RefCountedObjectPtr& other) + { + return operator=(other.referencedObject); + } + + /** Changes this pointer to point at a different object. + The reference count of the old object is decremented, and it might be + deleted if it hits zero. The new object's count is incremented. + + @param other A pointer to assign from. + @returns This pointer. + */ + template + RefCountedObjectPtr& operator=(const RefCountedObjectPtr& other) + { + return operator=(static_cast(other.getObject())); + } + + /** + Takes-over the object from another pointer. + + @param other A pointer to assign from. + @returns This pointer. + */ + RefCountedObjectPtr& operator=(RefCountedObjectPtr&& other) + { + std::swap(referencedObject, other.referencedObject); + return *this; + } + + /** Changes this pointer to point at a different object. + The reference count of the old object is decremented, and it might be + deleted if it hits zero. The new object's count is incremented. + + @param newObject A reference counted object to own. + @returns This pointer. + */ + RefCountedObjectPtr& operator=(ReferenceCountedObjectClass* const newObject) + { + if (referencedObject != newObject) + { + if (newObject != 0) + newObject->incReferenceCount(); + + ReferenceCountedObjectClass* const oldObject = referencedObject; + referencedObject = newObject; + + if (oldObject != 0) + oldObject->decReferenceCount(); + } + + return *this; + } + + /** Destructor. + This will decrement the object's reference-count, and may delete it if it + gets to zero. + */ + ~RefCountedObjectPtr() + { + if (referencedObject != 0) + referencedObject->decReferenceCount(); + } + + /** Returns the object that this pointer references. + The returned pointer may be null. + + @returns The pointee. + */ + operator ReferenceCountedObjectClass*() const { return referencedObject; } + + /** Returns the object that this pointer references. + The returned pointer may be null. + + @returns The pointee. + */ + ReferenceCountedObjectClass* operator->() const { return referencedObject; } + + /** Returns the object that this pointer references. + The returned pointer may be null. + + @returns The pointee. + */ + ReferenceCountedObjectClass* getObject() const { return referencedObject; } + +private: + //============================================================================== + ReferenceCountedObjectClass* referencedObject; +}; + +/** Compares two ReferenceCountedObjectPointers. */ +template +bool operator==(const RefCountedObjectPtr& object1, + ReferenceCountedObjectClass* const object2) +{ + return object1.getObject() == object2; +} + +/** Compares two ReferenceCountedObjectPointers. */ +template +bool operator==(const RefCountedObjectPtr& object1, + const RefCountedObjectPtr& object2) +{ + return object1.getObject() == object2.getObject(); +} + +/** Compares two ReferenceCountedObjectPointers. */ +template +bool operator==(ReferenceCountedObjectClass* object1, + RefCountedObjectPtr& object2) +{ + return object1 == object2.getObject(); +} + +/** Compares two ReferenceCountedObjectPointers. */ +template +bool operator!=(const RefCountedObjectPtr& object1, + const ReferenceCountedObjectClass* object2) +{ + return object1.getObject() != object2; +} + +/** Compares two ReferenceCountedObjectPointers. */ +template +bool operator!=(const RefCountedObjectPtr& object1, + RefCountedObjectPtr& object2) +{ + return object1.getObject() != object2.getObject(); +} + +/** Compares two ReferenceCountedObjectPointers. */ +template +bool operator!=(ReferenceCountedObjectClass* object1, + RefCountedObjectPtr& object2) +{ + return object1 != object2.getObject(); +} + +//============================================================================== + +template +struct ContainerTraits> +{ + using Type = T; + + static RefCountedObjectPtr construct(T* c) { return c; } + + static T* get(RefCountedObjectPtr const& c) { return c.getObject(); } +}; + +//============================================================================== + +} // namespace luabridge + +// End File: Source/LuaBridge/RefCountedObject.h + +// Begin File: Source/LuaBridge/detail/Dump.h + +// https://github.com/kunitoki/LuaBridge3 +// Copyright 2020, Lucio Asnaghi +// Copyright 2019, Dmitry Tarakanov +// Copyright 2012, Vinnie Falco +// Copyright 2007, Nathan Reed +// SPDX-License-Identifier: MIT + +namespace luabridge { +namespace debug { + +inline void putIndent(std::ostream& stream, unsigned level) +{ + for (unsigned i = 0; i < level; ++i) + { + stream << " "; + } +} + +inline void dumpTable(lua_State* L, int index, std::ostream& stream, unsigned level); + +inline void dumpValue(lua_State* L, int index, std::ostream& stream, unsigned level = 0) +{ + const int type = lua_type(L, index); + switch (type) + { + case LUA_TNIL: + stream << "nil"; + break; + + case LUA_TBOOLEAN: + stream << (lua_toboolean(L, index) ? "true" : "false"); + break; + + case LUA_TNUMBER: + stream << lua_tonumber(L, index); + break; + + case LUA_TSTRING: + stream << '"' << lua_tostring(L, index) << '"'; + break; + + case LUA_TFUNCTION: + if (lua_iscfunction(L, index)) + { + stream << "cfunction@" << lua_topointer(L, index); + } + else + { + stream << "function@" << lua_topointer(L, index); + } + break; + + case LUA_TTHREAD: + stream << "thread@" << lua_tothread(L, index); + break; + + case LUA_TLIGHTUSERDATA: + stream << "lightuserdata@" << lua_touserdata(L, index); + break; + + case LUA_TTABLE: + dumpTable(L, index, stream, level); + break; + + case LUA_TUSERDATA: + stream << "userdata@" << lua_touserdata(L, index); + break; + + default: + stream << lua_typename(L, type); + ; + break; + } +} + +inline void dumpTable(lua_State* L, int index, std::ostream& stream, unsigned level) +{ + stream << "table@" << lua_topointer(L, index); + + if (level > 0) + { + return; + } + + index = lua_absindex(L, index); + stream << " {"; + lua_pushnil(L); // Initial key + while (lua_next(L, index)) + { + stream << "\n"; + putIndent(stream, level + 1); + dumpValue(L, -2, stream, level + 1); // Key + stream << ": "; + dumpValue(L, -1, stream, level + 1); // Value + lua_pop(L, 1); // Value + } + putIndent(stream, level); + stream << "\n}"; +} + +inline void dumpState(lua_State* L, std::ostream& stream = std::cerr) +{ + int top = lua_gettop(L); + for (int i = 1; i <= top; ++i) + { + stream << "stack #" << i << ": "; + dumpValue(L, i, stream, 0); + stream << "\n"; + } +} + +} // namespace debug +} // namespace luabridge + +// End File: Source/LuaBridge/detail/Dump.h + +// clang-format on \ No newline at end of file diff --git a/sources/Component/IAControllable/IAControllableComponent.cpp b/sources/Component/IAControllable/IAControllableComponent.cpp index 11d40b2c..16c3b745 100644 --- a/sources/Component/IAControllable/IAControllableComponent.cpp +++ b/sources/Component/IAControllable/IAControllableComponent.cpp @@ -5,6 +5,7 @@ ** IAControllableComponent */ +#include "Map/MapInfo.hpp" #include "Component/IAControllable/IAControllableComponent.hpp" namespace BBM @@ -12,10 +13,17 @@ namespace BBM IAControllableComponent::IAControllableComponent(WAL::Entity &entity, std::string scriptPath) : Component(entity), _scriptPath(scriptPath), state(luaL_newstate()) { + luaL_openlibs(state); + luabridge::getGlobalNamespace(state) + .beginNamespace ("luaBBM") + .beginClass("MapInfo") + .addProperty("x", &MapInfo::x) + .addProperty("y", &MapInfo::y) + .addProperty("z", &MapInfo::z) + .addProperty("type", &MapInfo::type) + .endClass() + .endNamespace(); luaL_dofile(state, scriptPath.c_str()); - lua_getglobal(state, "Update"); - if (!lua_isfunction(state, -1)) - std::cout << "No update function in the script" << std::endl; } WAL::Component *IAControllableComponent::clone(WAL::Entity &entity) const diff --git a/sources/Component/IAControllable/IAControllableComponent.hpp b/sources/Component/IAControllable/IAControllableComponent.hpp index ab8b572e..9ff60a90 100644 --- a/sources/Component/IAControllable/IAControllableComponent.hpp +++ b/sources/Component/IAControllable/IAControllableComponent.hpp @@ -12,6 +12,7 @@ #include "Entity/Entity.hpp" #include "Models/Vector3.hpp" #include "lua.hpp" +#include "LuaBridge.hpp" namespace BBM { diff --git a/sources/Map/Map.hpp b/sources/Map/Map.hpp index f6b082a8..d0191ddc 100644 --- a/sources/Map/Map.hpp +++ b/sources/Map/Map.hpp @@ -27,7 +27,7 @@ namespace BBM class MapGenerator { - private: + public: //! @brief Enum of the block available. enum BlockType { NOTHING, @@ -40,10 +40,26 @@ namespace BBM SPAWNER, UNBREAKABLE }; - using MapElem = std::function scene)>; using MapBlock = std::map, BlockType>; + static void wallCollide(WAL::Entity &entity, const WAL::Entity &wall); + + + //! @param width Width of the map + //! @param height Height of the map + //! @brief Generate map of block to be loaded + static MapBlock createMap(int width, int height); + + //! @param width Width of the map + //! @param height Height of the map + //! @param map Map to load with block declared inside + //! @param scene Scene where the map is instanced + //! @brief Generate the map + static void loadMap(int width, int height, MapBlock map, std::shared_ptr scene); + + private: + //! @brief Generate random block type static BlockType getRandomBlockType(); @@ -155,21 +171,5 @@ namespace BBM static const std::string secondFloorHolePath; - public: - static void wallCollide(WAL::Entity &entity, const WAL::Entity &wall); - - - //! @param width Width of the map - //! @param height Height of the map - //! @brief Generate map of block to be loaded - static MapBlock createMap(int width, int height); - - //! @param width Width of the map - //! @param height Height of the map - //! @param map Map to load with block declared inside - //! @param scene Scene where the map is instanced - //! @brief Generate the map - static void loadMap(int width, int height, MapBlock map, std::shared_ptr scene); - }; } // namespace BBM \ No newline at end of file diff --git a/sources/Map/MapInfo.cpp b/sources/Map/MapInfo.cpp new file mode 100644 index 00000000..45723f3a --- /dev/null +++ b/sources/Map/MapInfo.cpp @@ -0,0 +1,21 @@ +// +// Created by Louis Auzuret 09/06/21 +// + +#include "MapInfo.hpp" + +namespace BBM +{ + MapInfo::MapInfo(Vector3f pos, MapGenerator::BlockType type) + : x(pos.x), y(pos.y), z(pos.z), type(type) + { } + + MapInfo &MapInfo::operator=(MapInfo &other) + { + this->x = other.x; + this->y = other.y; + this->z = other.z; + this->type = other.type; + return *this; + } +} \ No newline at end of file diff --git a/sources/Map/MapInfo.hpp b/sources/Map/MapInfo.hpp new file mode 100644 index 00000000..472b1542 --- /dev/null +++ b/sources/Map/MapInfo.hpp @@ -0,0 +1,37 @@ +// +// Created by Louis Auzuret on 09/06/21 +// + +#include "Map.hpp" + +namespace BBM +{ + class MapInfo + { + private: + public: + //! @brief Position on the x axis + float x; + + //! @brief Position on the y axis + float y; + + //! @brief Position on the z axis + float z; + + //! @brief Type of the block + MapGenerator::BlockType type; + + //! @brief Constructor + MapInfo(Vector3f pos, MapGenerator::BlockType type); + + //! @brief Default destructor + ~MapInfo() = default; + + //! @brief Default copy constructor + MapInfo(MapInfo &) = default; + + //! @brief Assignment operator + MapInfo &operator=(MapInfo &); + }; +} \ No newline at end of file diff --git a/sources/System/IAControllable/IAControllableSystem.cpp b/sources/System/IAControllable/IAControllableSystem.cpp index 55b32e07..87ed564e 100644 --- a/sources/System/IAControllable/IAControllableSystem.cpp +++ b/sources/System/IAControllable/IAControllableSystem.cpp @@ -2,6 +2,7 @@ // Created by Louis Auzuret on 06/07/21 // +#include "Map/MapInfo.hpp" #include "Component/Controllable/ControllableComponent.hpp" #include "Component/IAControllable/IAControllableComponent.hpp" #include "System/IAControllable/IAControllableSystem.hpp" @@ -43,19 +44,18 @@ namespace BBM { auto &ia = entity.get(); auto &controllable = entity.get(); + MapInfo info({1, 2, 3}, MapGenerator::NOTHING); - lua_getglobal(ia.state, "Update"); - if (!lua_isfunction(ia.state, -1)) + luabridge::LuaRef updateFunc = luabridge::getGlobal(ia.state, "Update"); + if (!updateFunc.isFunction()) + return; + luabridge::LuaResult res = updateFunc(info); + + if (res.hasFailed() || res.size() != 4) return; - //std::vector<> players; - //std::vector<> map; - //push parameters - int nbParams = 0; - int nbReturn = 4; - lua_pcall(ia.state, nbParams, nbReturn, 0); - controllable.bomb = getReturnBool(ia.state); - controllable.jump = getReturnBool(ia.state); - controllable.move.y = getReturnNumber(ia.state); - controllable.move.x = getReturnNumber(ia.state); + controllable.bomb = res[3]; + controllable.jump = res[2]; + controllable.move.y = res[1]; + controllable.move.x = res[0]; } } \ No newline at end of file From 5f7bcf2a8f43dc82970118b42ce7cad2ec64e968 Mon Sep 17 00:00:00 2001 From: Bluub Date: Wed, 9 Jun 2021 14:53:41 +0200 Subject: [PATCH 11/78] type check --- ai_scripts/john.lua | 8 +++++++- sources/Map/MapInfo.cpp | 4 ++++ sources/Map/MapInfo.hpp | 4 ++-- .../IAControllable/IAControllableSystem.cpp | 20 ++++++++++++------- 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/ai_scripts/john.lua b/ai_scripts/john.lua index 5bec036a..304a89da 100644 --- a/ai_scripts/john.lua +++ b/ai_scripts/john.lua @@ -2,7 +2,13 @@ function Sum(a,b) return a + b; end -function Update(info) +function Update(infos) + for i, info in ipairs(infos) do + print (info.x); + print (info.y); + print (info.z); + print (info.type); + end return 1, 1, false, false; --return info.x, info.y, (info.z ~= 1), (info.type ~= 0); end \ No newline at end of file diff --git a/sources/Map/MapInfo.cpp b/sources/Map/MapInfo.cpp index 45723f3a..f7c8f7c8 100644 --- a/sources/Map/MapInfo.cpp +++ b/sources/Map/MapInfo.cpp @@ -10,6 +10,10 @@ namespace BBM : x(pos.x), y(pos.y), z(pos.z), type(type) { } + MapInfo::MapInfo(const MapInfo &other) + : x(other.x), y(other.y), z(other.z), type(other.type) + { } + MapInfo &MapInfo::operator=(MapInfo &other) { this->x = other.x; diff --git a/sources/Map/MapInfo.hpp b/sources/Map/MapInfo.hpp index 472b1542..78d10a83 100644 --- a/sources/Map/MapInfo.hpp +++ b/sources/Map/MapInfo.hpp @@ -20,7 +20,7 @@ namespace BBM float z; //! @brief Type of the block - MapGenerator::BlockType type; + int type; //! @brief Constructor MapInfo(Vector3f pos, MapGenerator::BlockType type); @@ -29,7 +29,7 @@ namespace BBM ~MapInfo() = default; //! @brief Default copy constructor - MapInfo(MapInfo &) = default; + MapInfo(const MapInfo &); //! @brief Assignment operator MapInfo &operator=(MapInfo &); diff --git a/sources/System/IAControllable/IAControllableSystem.cpp b/sources/System/IAControllable/IAControllableSystem.cpp index 87ed564e..9e20998c 100644 --- a/sources/System/IAControllable/IAControllableSystem.cpp +++ b/sources/System/IAControllable/IAControllableSystem.cpp @@ -6,6 +6,8 @@ #include "Component/Controllable/ControllableComponent.hpp" #include "Component/IAControllable/IAControllableComponent.hpp" #include "System/IAControllable/IAControllableSystem.hpp" +#include +#include namespace BBM { @@ -44,18 +46,22 @@ namespace BBM { auto &ia = entity.get(); auto &controllable = entity.get(); - MapInfo info({1, 2, 3}, MapGenerator::NOTHING); + std::vector infos; luabridge::LuaRef updateFunc = luabridge::getGlobal(ia.state, "Update"); if (!updateFunc.isFunction()) - return; - luabridge::LuaResult res = updateFunc(info); + return; + luabridge::LuaResult res = updateFunc(infos); if (res.hasFailed() || res.size() != 4) return; - controllable.bomb = res[3]; - controllable.jump = res[2]; - controllable.move.y = res[1]; - controllable.move.x = res[0]; + if (res[3].isBool()) + controllable.bomb = res[3]; + if (res[2].isBool()) + controllable.jump = res[2]; + if (res[1].isNumber()) + controllable.move.y = res[1]; + if (res[0].isNumber()) + controllable.move.x = res[0]; } } \ No newline at end of file From a96c5b770dd9c5399f92332fce9c4b055e62652e Mon Sep 17 00:00:00 2001 From: Bluub Date: Wed, 9 Jun 2021 15:55:59 +0200 Subject: [PATCH 12/78] add unbreakable tag --- sources/Component/Tag/TagComponent.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sources/Component/Tag/TagComponent.hpp b/sources/Component/Tag/TagComponent.hpp index 00fa27d5..b5a58625 100644 --- a/sources/Component/Tag/TagComponent.hpp +++ b/sources/Component/Tag/TagComponent.hpp @@ -51,4 +51,6 @@ namespace BBM }; constexpr const char Blowable[] = "Blowable"; + constexpr const char Unbreakable[] = "Unbreakable"; + } From a1ddc170dc17d25226564a617f2cb1223b48767c Mon Sep 17 00:00:00 2001 From: Bluub Date: Wed, 9 Jun 2021 16:23:25 +0200 Subject: [PATCH 13/78] adding tag on creation --- sources/Component/Tag/TagComponent.hpp | 4 +++- sources/Map/Map.cpp | 7 ++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/sources/Component/Tag/TagComponent.hpp b/sources/Component/Tag/TagComponent.hpp index b5a58625..25b6df37 100644 --- a/sources/Component/Tag/TagComponent.hpp +++ b/sources/Component/Tag/TagComponent.hpp @@ -52,5 +52,7 @@ namespace BBM constexpr const char Blowable[] = "Blowable"; constexpr const char Unbreakable[] = "Unbreakable"; - + constexpr const char Breakable[] = "Breakable"; + constexpr const char Hole[] = "Hole"; + constexpr const char Bumper[] = "Bumper"; } diff --git a/sources/Map/Map.cpp b/sources/Map/Map.cpp index b5ca0268..96766f29 100644 --- a/sources/Map/Map.cpp +++ b/sources/Map/Map.cpp @@ -57,6 +57,7 @@ namespace BBM scene->addEntity("Unbreakable Wall") .addComponent(i, 0, j) .addComponent>() + .addComponent>() .addComponent( WAL::Callback(), &MapGenerator::wallCollide, 0.25, .75) @@ -152,6 +153,7 @@ namespace BBM scene->addEntity("Breakable Block") .addComponent(coords) .addComponent>() + .addComponent>() .addComponent(1, &MapGenerator::wallDestroyed) .addComponent( WAL::Callback(), @@ -189,6 +191,7 @@ namespace BBM scene->addEntity("Unbreakable Block") .addComponent(coords) .addComponent>() + .addComponent>() .addComponent( WAL::Callback(), &MapGenerator::wallCollide, 0.25, .75) @@ -205,7 +208,8 @@ namespace BBM WAL::Entity &holeEntity = scene->addEntity("Hole Block"); - holeEntity.addComponent(Vector3f(coords.x, coords.y - 1, coords.z)); + holeEntity.addComponent(Vector3f(coords.x, coords.y - 1, coords.z)) + .addComponent>(); if (coords.y == 0) holeEntity.addComponent(holeObj, std::make_pair(MAP_DIFFUSE, holePng)); @@ -227,6 +231,7 @@ namespace BBM scene->addEntity("Bumper Block") .addComponent(Vector3f(coords.x, coords.y, coords.z)) + .addComponent>() .addComponent(bumperObj, std::make_pair(MAP_DIFFUSE, bumperPng)); /* .addComponent([](const WAL::Entity &entity, WAL::Entity &other) { if (other.hasComponent()) { From 620812107bb8ee26d363c283e6e4ad88ee58491a Mon Sep 17 00:00:00 2001 From: Bluub Date: Wed, 9 Jun 2021 16:50:56 +0200 Subject: [PATCH 14/78] send player and other players to the lua function --- ai_scripts/john.lua | 22 ++++---- sources/Component/Tag/TagComponent.hpp | 1 + sources/Runner/Runner.cpp | 1 + .../IAControllable/IAControllableSystem.cpp | 55 +++++++++---------- .../IAControllable/IAControllableSystem.hpp | 10 ++-- 5 files changed, 43 insertions(+), 46 deletions(-) diff --git a/ai_scripts/john.lua b/ai_scripts/john.lua index 304a89da..67eb2762 100644 --- a/ai_scripts/john.lua +++ b/ai_scripts/john.lua @@ -1,14 +1,16 @@ -function Sum(a,b) - return a + b; -end - -function Update(infos) +function Update(player, infos, players) + print(player.x); + print(player.y); + print(player.z); for i, info in ipairs(infos) do - print (info.x); - print (info.y); - print (info.z); - print (info.type); + --print("x"); + --print (info.x); + --print("y"); + --print (info.y); + --print("z"); + --print (info.z); + --print("type"); + --print (info.type); end return 1, 1, false, false; - --return info.x, info.y, (info.z ~= 1), (info.type ~= 0); end \ No newline at end of file diff --git a/sources/Component/Tag/TagComponent.hpp b/sources/Component/Tag/TagComponent.hpp index 25b6df37..fe07f70e 100644 --- a/sources/Component/Tag/TagComponent.hpp +++ b/sources/Component/Tag/TagComponent.hpp @@ -55,4 +55,5 @@ namespace BBM constexpr const char Breakable[] = "Breakable"; constexpr const char Hole[] = "Hole"; constexpr const char Bumper[] = "Bumper"; + constexpr const char Player[] = "Player"; } diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 9fb1fbd7..8f327f9c 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -96,6 +96,7 @@ namespace BBM .addComponent() .addComponent() .addComponent() + .addComponent("./ai_scripts/john.lua") .addComponent>() //.addComponent(0) .addComponent(RAY::ModelAnimations("assets/player/player.iqm"), 3) diff --git a/sources/System/IAControllable/IAControllableSystem.cpp b/sources/System/IAControllable/IAControllableSystem.cpp index 83e52a68..822a93df 100644 --- a/sources/System/IAControllable/IAControllableSystem.cpp +++ b/sources/System/IAControllable/IAControllableSystem.cpp @@ -3,6 +3,7 @@ // #include "Map/MapInfo.hpp" +#include "Component/Tag/TagComponent.hpp" #include "Component/Controllable/ControllableComponent.hpp" #include "Component/IAControllable/IAControllableComponent.hpp" #include "System/IAControllable/IAControllableSystem.hpp" @@ -12,46 +13,40 @@ namespace BBM { IAControllableSystem::IAControllableSystem(WAL::Wal &wal) - : System(wal) + : System(wal), _wal(wal) { } - float IAControllableSystem::getReturnNumber(lua_State *state) - { - float res = 0; - - if (lua_isnil(state, -1)) - return res; - if (!lua_isnumber(state, -1)) - return res; - res = lua_tonumber(state, -1); - lua_pop(state, 1); - - return res; - } - - bool IAControllableSystem::getReturnBool(lua_State *state) - { - bool res = false; - - if (lua_isnil(state, -1)) - return res; - if (!lua_isboolean(state, -1)) - return res; - res = lua_toboolean(state, -1); - lua_pop(state, 1); - return res; - } - - void IAControllableSystem::onFixedUpdate(WAL::ViewEntity &entity) + void IAControllableSystem::onFixedUpdate(WAL::ViewEntity &entity) { auto &ia = entity.get(); auto &controllable = entity.get(); + auto &pos = entity.get(); + MapInfo player(pos.position, MapGenerator::NOTHING); std::vector infos; + std::vector players; + + for (auto &[other, pos, _] : _wal.scene->view>()) + infos.push_back(MapInfo(pos.position, MapGenerator::BREAKABLE)); + + for (auto &[other, pos, _] : _wal.scene->view>()) + infos.push_back(MapInfo(pos.position, MapGenerator::UNBREAKABLE)); + + for (auto &[other, pos, _] : _wal.scene->view>()) + infos.push_back(MapInfo(pos.position, MapGenerator::BUMPER)); + + for (auto &[other, pos, _] : _wal.scene->view>()) + infos.push_back(MapInfo(pos.position, MapGenerator::HOLE)); + + for (auto &[other, pos, _] : _wal.scene->view>()) { + if (static_cast(entity).getUid() == other.getUid()) + continue; + players.push_back(MapInfo(pos.position, MapGenerator::NOTHING)); + } luabridge::LuaRef updateFunc = luabridge::getGlobal(ia.state, "Update"); if (!updateFunc.isFunction()) return; - luabridge::LuaResult res = updateFunc(infos); + luabridge::LuaResult res = updateFunc(player, infos, players); if (res.hasFailed() || res.size() != 4) return; diff --git a/sources/System/IAControllable/IAControllableSystem.hpp b/sources/System/IAControllable/IAControllableSystem.hpp index b851e800..03c60dea 100644 --- a/sources/System/IAControllable/IAControllableSystem.hpp +++ b/sources/System/IAControllable/IAControllableSystem.hpp @@ -9,16 +9,14 @@ namespace BBM { //! @brief A system to handle keyboard entities. - class IAControllableSystem : public WAL::System + class IAControllableSystem : public WAL::System { private: - //! @brief extract a number from the lua stack - float getReturnNumber(lua_State *state); - //! @brief extract a bool from the lua stack - bool getReturnBool(lua_State *state); + //! @brief Reference to wal to get Views + WAL::Wal &_wal; public: //! @inherit - void onFixedUpdate(WAL::ViewEntity &entity) override; + void onFixedUpdate(WAL::ViewEntity &entity) override; //! @brief A default constructor IAControllableSystem(WAL::Wal &wal); From 1a730dd5818641bc7d250f5f54f62a3b5d17ddd8 Mon Sep 17 00:00:00 2001 From: Bluub Date: Thu, 10 Jun 2021 15:25:27 +0200 Subject: [PATCH 15/78] update map infos function for all ia --- ai_scripts/john.lua | 64 +++++++++++--- .../IAControllable/IAControllableSystem.cpp | 88 ++++++++++++++----- .../IAControllable/IAControllableSystem.hpp | 19 ++++ todolua | 7 ++ 4 files changed, 142 insertions(+), 36 deletions(-) create mode 100644 todolua diff --git a/ai_scripts/john.lua b/ai_scripts/john.lua index 67eb2762..adb71290 100644 --- a/ai_scripts/john.lua +++ b/ai_scripts/john.lua @@ -1,16 +1,54 @@ -function Update(player, infos, players) - print(player.x); - print(player.y); - print(player.z); +------------ JOHN AI + + +local debug = true +--local debug = false +if not debug then + log = function() end +end + +function PrintMap(map, maxX, maxZ) + for i=0,maxX + 1 do + local s = "| " + for j=0,maxZ + 1 do + s = s .. tostring(map[i][j]) .. " | "; + end + log(s) + log(string.rep("-", (maxZ - 1) * 5 - 1)) + end +end + +function CreateMyMap(infos, maxX, maxZ) + local map = {} + for i=0,maxX + 1 do + map[i] = {} + for j=0,maxZ + 1 do + map[i][j] = 0 + end + end for i, info in ipairs(infos) do - --print("x"); - --print (info.x); - --print("y"); - --print (info.y); - --print("z"); - --print (info.z); - --print("type"); - --print (info.type); - end + map[info.x][info.z] = info.type + end + PrintMap(map, maxX, maxZ) + return map +end + +function Update(player, infos, players) + local maxX = 0 + local maxZ = 0 + for i, info in ipairs(infos) do + if info.x > maxX then + maxX = info.x + end + if info.z > maxZ then + maxZ = info.z + end + end + local myMap = CreateMyMap(infos, maxX, maxZ); + if (isInExplosionRange()) then + --play defensive RUN + else + --play offensive + end return 1, 1, false, false; end \ No newline at end of file diff --git a/sources/System/IAControllable/IAControllableSystem.cpp b/sources/System/IAControllable/IAControllableSystem.cpp index 822a93df..40e963d5 100644 --- a/sources/System/IAControllable/IAControllableSystem.cpp +++ b/sources/System/IAControllable/IAControllableSystem.cpp @@ -2,12 +2,10 @@ // Created by Louis Auzuret on 06/07/21 // -#include "Map/MapInfo.hpp" #include "Component/Tag/TagComponent.hpp" #include "Component/Controllable/ControllableComponent.hpp" #include "Component/IAControllable/IAControllableComponent.hpp" #include "System/IAControllable/IAControllableSystem.hpp" -#include #include namespace BBM @@ -15,6 +13,54 @@ namespace BBM IAControllableSystem::IAControllableSystem(WAL::Wal &wal) : System(wal), _wal(wal) { } +/* + float IAControllableSystem::getReturnNumber(lua_State *state) + { + float res = 0; + + if (lua_isnil(state, -1)) + return res; + if (!lua_isnumber(state, -1)) + return res; + res = lua_tonumber(state, -1); + lua_pop(state, 1); + + return res; + } + + bool IAControllableSystem::getReturnBool(lua_State *state) + { + bool res = false; + + if (lua_isnil(state, -1)) + return res; + if (!lua_isboolean(state, -1)) + return res; + res = lua_toboolean(state, -1); + lua_pop(state, 1); + return res; + }*/ + + void IAControllableSystem::UpdateMapInfos(WAL::Entity entity) + { + if (_cached) + return; + for (auto &[other, pos, _] : _wal.scene->view>()) + _map.push_back(MapInfo(pos.position, MapGenerator::BREAKABLE)); + for (auto &[other, pos, _] : _wal.scene->view>()) + _map.push_back(MapInfo(pos.position, MapGenerator::UNBREAKABLE)); + for (auto &[other, pos, _] : _wal.scene->view>()) + _map.push_back(MapInfo(pos.position, MapGenerator::BUMPER)); + for (auto &[other, pos, _] : _wal.scene->view>()) + _map.push_back(MapInfo(pos.position, MapGenerator::HOLE)); + for (auto &[other, pos, _] : _wal.scene->view>()) { + if (entity.getUid() == other.getUid()) + continue; + _players.push_back(MapInfo(pos.position, MapGenerator::NOTHING)); + } + _cached = true; + + } void IAControllableSystem::onFixedUpdate(WAL::ViewEntity &entity) { @@ -22,31 +68,12 @@ namespace BBM auto &controllable = entity.get(); auto &pos = entity.get(); MapInfo player(pos.position, MapGenerator::NOTHING); - std::vector infos; - std::vector players; - - for (auto &[other, pos, _] : _wal.scene->view>()) - infos.push_back(MapInfo(pos.position, MapGenerator::BREAKABLE)); - - for (auto &[other, pos, _] : _wal.scene->view>()) - infos.push_back(MapInfo(pos.position, MapGenerator::UNBREAKABLE)); - - for (auto &[other, pos, _] : _wal.scene->view>()) - infos.push_back(MapInfo(pos.position, MapGenerator::BUMPER)); - - for (auto &[other, pos, _] : _wal.scene->view>()) - infos.push_back(MapInfo(pos.position, MapGenerator::HOLE)); - - for (auto &[other, pos, _] : _wal.scene->view>()) { - if (static_cast(entity).getUid() == other.getUid()) - continue; - players.push_back(MapInfo(pos.position, MapGenerator::NOTHING)); - } + UpdateMapInfos(static_cast(entity)); luabridge::LuaRef updateFunc = luabridge::getGlobal(ia.state, "Update"); if (!updateFunc.isFunction()) return; - luabridge::LuaResult res = updateFunc(player, infos, players); + luabridge::LuaResult res = updateFunc(player, _map, _players); if (res.hasFailed() || res.size() != 4) return; @@ -59,4 +86,19 @@ namespace BBM if (res[3].isBool()) controllable.bomb = res[3]; } + + void IAControllableSystem::onSelfUpdate() + { + _cached = false; + _map.clear(); + _players.clear(); + } + + bool IAControllableSystem::isInExplosionRange(float x, float y, float z) + { + return false; + //for (auto &bomb : bombs) { + // + //} + } } \ No newline at end of file diff --git a/sources/System/IAControllable/IAControllableSystem.hpp b/sources/System/IAControllable/IAControllableSystem.hpp index 03c60dea..3a56ab62 100644 --- a/sources/System/IAControllable/IAControllableSystem.hpp +++ b/sources/System/IAControllable/IAControllableSystem.hpp @@ -4,6 +4,8 @@ #pragma once +#include +#include "Map/MapInfo.hpp" #include "System/System.hpp" namespace BBM @@ -14,10 +16,25 @@ namespace BBM private: //! @brief Reference to wal to get Views WAL::Wal &_wal; + + //! @brief Are the infos cached for current update + bool _cached; + + //! @brief All blocks in the map + std::vector _map; + + //! @brief All players in the map + std::vector _players; + + //! @brief + void UpdateMapInfos(WAL::Entity entity); public: //! @inherit void onFixedUpdate(WAL::ViewEntity &entity) override; + //! @inherit + void onSelfUpdate() override; + //! @brief A default constructor IAControllableSystem(WAL::Wal &wal); //! @brief A keyboard system is copy constructable @@ -26,5 +43,7 @@ namespace BBM ~IAControllableSystem() override = default; //! @brief A keyboard system is assignable. IAControllableSystem &operator=(const IAControllableSystem &) = default; + + static bool isInExplosionRange(float x, float y, float z); }; } diff --git a/todolua b/todolua new file mode 100644 index 00000000..ccf1ad93 --- /dev/null +++ b/todolua @@ -0,0 +1,7 @@ +[ ] Metatable for MapInfo +[ ] Metatable for Vector of MapInfo +[ ] C++ helper function for ai + [ ] Closest Player + [ ] GetPath to Point + [ ] Closest Bonus + [ ] isInExplosionrRange \ No newline at end of file From 24bf2462692e59ccf9b0e78b2067cfe67d1c66ea Mon Sep 17 00:00:00 2001 From: Bluub Date: Fri, 11 Jun 2021 09:34:22 +0200 Subject: [PATCH 16/78] update map info --- ai_scripts/john.lua | 14 ++++--- lib/LuaGate/LuaGate.cpp | 34 +++++++++++++++++ lib/LuaGate/LuaGate.hpp | 37 +++++++++++++++++++ sources/System/Collision/CollisionSystem.cpp | 1 - .../IAControllable/IAControllableSystem.cpp | 9 ++++- .../IAControllable/IAControllableSystem.hpp | 2 + 6 files changed, 89 insertions(+), 8 deletions(-) create mode 100644 lib/LuaGate/LuaGate.cpp create mode 100644 lib/LuaGate/LuaGate.hpp diff --git a/ai_scripts/john.lua b/ai_scripts/john.lua index adb71290..ac9c5de1 100644 --- a/ai_scripts/john.lua +++ b/ai_scripts/john.lua @@ -5,6 +5,10 @@ local debug = true --local debug = false if not debug then log = function() end +else + log = function(a) + print(a) + end end function PrintMap(map, maxX, maxZ) @@ -45,10 +49,10 @@ function Update(player, infos, players) end end local myMap = CreateMyMap(infos, maxX, maxZ); - if (isInExplosionRange()) then - --play defensive RUN - else - --play offensive - end + --if (isInExplosionRange()) then + -- --play defensive RUN + --else + -- --play offensive + --end return 1, 1, false, false; end \ No newline at end of file diff --git a/lib/LuaGate/LuaGate.cpp b/lib/LuaGate/LuaGate.cpp new file mode 100644 index 00000000..33180dae --- /dev/null +++ b/lib/LuaGate/LuaGate.cpp @@ -0,0 +1,34 @@ +// +// Created by Louis Auzuret on 10/06/21 +// + +#include "LuaGate.hpp" + +namespace LuaG +{ + State::State() + : _state(luaL_newstate()) + { + luaL_openlibs(_state); + } + + State::~State() + { + lua_close(_state); + } + + LuaState *State::getState(void) + { + return _state; + } + + void State::dofile(std::string filepath) + { + luaL_dofile(_state, filepath.c_str()); + } + + void State::dostring(std::string str) + { + luaL_dostring(_state, str.c_str()); + } +} \ No newline at end of file diff --git a/lib/LuaGate/LuaGate.hpp b/lib/LuaGate/LuaGate.hpp new file mode 100644 index 00000000..6d372439 --- /dev/null +++ b/lib/LuaGate/LuaGate.hpp @@ -0,0 +1,37 @@ +// +// Created by Louis Auzuret on 10/06/21 +// + +#include +#include "lua.hpp" + +namespace LuaG +{ + class State + { + private: + LuaState *_state; + public: + //! @brief ctor + State(); + + //! @brief dtor + ~State(); + + //! @brief No copy constrructor + State &State(State &) = delete; + + //! @brief No assign operator + State &operator() = delete; + + //! @brief Get Lua state + LuaState *getState(void); + + //! @brief Execute a file in this state + void dofile(std::string filepath); + + //! @brief Execute a string in this state + void dostring(std::string str); + + } +} \ No newline at end of file diff --git a/sources/System/Collision/CollisionSystem.cpp b/sources/System/Collision/CollisionSystem.cpp index db68e3c0..60217ff3 100644 --- a/sources/System/Collision/CollisionSystem.cpp +++ b/sources/System/Collision/CollisionSystem.cpp @@ -7,7 +7,6 @@ #include "Component/Collision/CollisionComponent.hpp" #include "System/Collision/CollisionSystem.hpp" #include "Scene/Scene.hpp" - namespace BBM { CollisionSystem::CollisionSystem(WAL::Wal &wal) diff --git a/sources/System/IAControllable/IAControllableSystem.cpp b/sources/System/IAControllable/IAControllableSystem.cpp index 40e963d5..51342a09 100644 --- a/sources/System/IAControllable/IAControllableSystem.cpp +++ b/sources/System/IAControllable/IAControllableSystem.cpp @@ -11,7 +11,7 @@ namespace BBM { IAControllableSystem::IAControllableSystem(WAL::Wal &wal) - : System(wal), _wal(wal) + : System(wal), _wal(wal), _map(), _players(), _cached(false) { } /* float IAControllableSystem::getReturnNumber(lua_State *state) @@ -45,6 +45,8 @@ namespace BBM { if (_cached) return; + if (!_wal.scene.get()) + return; for (auto &[other, pos, _] : _wal.scene->view>()) _map.push_back(MapInfo(pos.position, MapGenerator::BREAKABLE)); for (auto &[other, pos, _] : _wal.scene->view>()) @@ -58,6 +60,8 @@ namespace BBM continue; _players.push_back(MapInfo(pos.position, MapGenerator::NOTHING)); } + //for (auto &[other, pos, bomb] : _wal.getScene()->view()) + // _bombs.push_back(std::make_pair(pos.position, bomb.explosionRadius)); _cached = true; } @@ -69,7 +73,7 @@ namespace BBM auto &pos = entity.get(); MapInfo player(pos.position, MapGenerator::NOTHING); - UpdateMapInfos(static_cast(entity)); + //UpdateMapInfos(static_cast(entity)); luabridge::LuaRef updateFunc = luabridge::getGlobal(ia.state, "Update"); if (!updateFunc.isFunction()) return; @@ -91,6 +95,7 @@ namespace BBM { _cached = false; _map.clear(); + _bombs.clear(); _players.clear(); } diff --git a/sources/System/IAControllable/IAControllableSystem.hpp b/sources/System/IAControllable/IAControllableSystem.hpp index 3a56ab62..06c8c0d7 100644 --- a/sources/System/IAControllable/IAControllableSystem.hpp +++ b/sources/System/IAControllable/IAControllableSystem.hpp @@ -26,6 +26,8 @@ namespace BBM //! @brief All players in the map std::vector _players; + std::vector> _bombs; + //! @brief void UpdateMapInfos(WAL::Entity entity); public: From e759a2ed6c5585a9c27dfeb8fc4ee0eb48dceac9 Mon Sep 17 00:00:00 2001 From: Bluub Date: Fri, 11 Jun 2021 09:42:54 +0200 Subject: [PATCH 17/78] fix static cast at wrong place --- sources/System/IAControllable/IAControllableSystem.cpp | 6 +++--- sources/System/IAControllable/IAControllableSystem.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sources/System/IAControllable/IAControllableSystem.cpp b/sources/System/IAControllable/IAControllableSystem.cpp index 51342a09..9110ee7c 100644 --- a/sources/System/IAControllable/IAControllableSystem.cpp +++ b/sources/System/IAControllable/IAControllableSystem.cpp @@ -41,7 +41,7 @@ namespace BBM return res; }*/ - void IAControllableSystem::UpdateMapInfos(WAL::Entity entity) + void IAControllableSystem::UpdateMapInfos(WAL::ViewEntity &entity) { if (_cached) return; @@ -56,7 +56,7 @@ namespace BBM for (auto &[other, pos, _] : _wal.scene->view>()) _map.push_back(MapInfo(pos.position, MapGenerator::HOLE)); for (auto &[other, pos, _] : _wal.scene->view>()) { - if (entity.getUid() == other.getUid()) + if (static_cast(entity).getUid() == other.getUid()) continue; _players.push_back(MapInfo(pos.position, MapGenerator::NOTHING)); } @@ -73,7 +73,7 @@ namespace BBM auto &pos = entity.get(); MapInfo player(pos.position, MapGenerator::NOTHING); - //UpdateMapInfos(static_cast(entity)); + UpdateMapInfos(entity); luabridge::LuaRef updateFunc = luabridge::getGlobal(ia.state, "Update"); if (!updateFunc.isFunction()) return; diff --git a/sources/System/IAControllable/IAControllableSystem.hpp b/sources/System/IAControllable/IAControllableSystem.hpp index 06c8c0d7..56fe0336 100644 --- a/sources/System/IAControllable/IAControllableSystem.hpp +++ b/sources/System/IAControllable/IAControllableSystem.hpp @@ -29,7 +29,7 @@ namespace BBM std::vector> _bombs; //! @brief - void UpdateMapInfos(WAL::Entity entity); + void UpdateMapInfos(WAL::ViewEntity &entity); public: //! @inherit void onFixedUpdate(WAL::ViewEntity &entity) override; From a6140f60871ab91fb2804369a68345ac1c0afcec Mon Sep 17 00:00:00 2001 From: Bluub Date: Mon, 14 Jun 2021 11:26:26 +0200 Subject: [PATCH 18/78] random boy ai --- ai_scripts/john.lua | 20 ++++++- ai_scripts/randboi.lua | 5 ++ lib/LuaGate/CMakeLists.txt | 28 +++++++++ lib/LuaGate/LuaGate.cpp | 36 ++++++++++++ lib/LuaGate/LuaGate.hpp | 18 ++++-- lua_bind_info | 48 +++++++++++++++ .../IAControllableComponent.cpp | 3 + sources/Runner/Runner.cpp | 2 +- .../IAControllable/IAControllableSystem.cpp | 58 ++++++++----------- .../IAControllable/IAControllableSystem.hpp | 2 + 10 files changed, 178 insertions(+), 42 deletions(-) create mode 100644 ai_scripts/randboi.lua create mode 100644 lib/LuaGate/CMakeLists.txt create mode 100644 lua_bind_info diff --git a/ai_scripts/john.lua b/ai_scripts/john.lua index ac9c5de1..81356efa 100644 --- a/ai_scripts/john.lua +++ b/ai_scripts/john.lua @@ -1,7 +1,7 @@ ------------ JOHN AI -local debug = true +local debug = false --local debug = false if not debug then log = function() end @@ -37,6 +37,10 @@ function CreateMyMap(infos, maxX, maxZ) return map end +function isInExplosionRange() + return true +end + function Update(player, infos, players) local maxX = 0 local maxZ = 0 @@ -48,11 +52,21 @@ function Update(player, infos, players) maxZ = info.z end end - local myMap = CreateMyMap(infos, maxX, maxZ); + local myMap = CreateMyMap(infos, maxX, maxZ) + local x = math.random() + local y = math.random() + if (math.random() < 0.5) then + x = x * -1 + end + if (math.random() < 0.5) then + y = y * -1 + end + return x, y, false, true; --if (isInExplosionRange()) then + -- return 0, , false, true -- --play defensive RUN --else + -- return 1, 1, false, false; -- --play offensive --end - return 1, 1, false, false; end \ No newline at end of file diff --git a/ai_scripts/randboi.lua b/ai_scripts/randboi.lua new file mode 100644 index 00000000..a92c0b43 --- /dev/null +++ b/ai_scripts/randboi.lua @@ -0,0 +1,5 @@ +math.randomseed(os.time()) + +function Update(player, infos, players) + return (math.random() < 0.5), (math.random() < 0.5), false, false; +end \ No newline at end of file diff --git a/lib/LuaGate/CMakeLists.txt b/lib/LuaGate/CMakeLists.txt new file mode 100644 index 00000000..ae7c7c4d --- /dev/null +++ b/lib/LuaGate/CMakeLists.txt @@ -0,0 +1,28 @@ +#Definition of CMake version to use +CMAKE_MINIMUM_REQUIRED(VERSION 3.11) +set(CMAKE_CXX_STANDARD 20) +set(LIB_NAME "LuaGate") + +project("${LIB_NAME}") +include_directories(${LIB_NAME} ./sources) + +if (CMAKE_COMPILER_IS_GNUCXX) + set(GCC_COVERAGE_COMPILE_FLAGS "-Wall -Wextra -Werror -Wshadow") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}") +endif () + + +find_package(Lua REQUIRED) +include_directories(${LIB_NAME} ${LUA_INCLUDE_DIR}) + +set(HEADERS + sources/LuaGate.hpp +) + +set(SRC + sources/LuaGate.cpp +) + +add_library(${LIB_NAME} STATIC ${SRC} ${HEADERS}) +target_compile_definitions(${LIB_NAME} INTERFACE INTERNAL=private PRIVATE INTERNAL=public) +target_link_libraries(${LIB_NAME} ${LUA_LIBRARIES}) \ No newline at end of file diff --git a/lib/LuaGate/LuaGate.cpp b/lib/LuaGate/LuaGate.cpp index 33180dae..d006f2f5 100644 --- a/lib/LuaGate/LuaGate.cpp +++ b/lib/LuaGate/LuaGate.cpp @@ -31,4 +31,40 @@ namespace LuaG { luaL_dostring(_state, str.c_str()); } + + float State::getReturnNumber(void) + { + float res = 0; + + if (lua_isnil(_state, -1)) + return res; + if (!lua_isnumber(_state, -1)) + return res; + res = lua_tonumber(_state, -1); + lua_pop(_state, 1); + + return res; + } + + bool State::getReturnBool(void) + { + bool res = false; + + if (lua_isnil(_state, -1)) + return res; + if (!lua_isboolean(_state, -1)) + return res; + res = lua_toboolean(_state, -1); + lua_pop(_state, 1); + return res; + } + + bool State::callFunction(std::string funcName, int nbParams, int nbReturns) + { + lua_getglobal(_state, funcName.c_str()); + if (!lua_isfunction(_state, -1)) + return false; + lua_pcall(_state, nbParams, nbReturns, 0); + return true; + } } \ No newline at end of file diff --git a/lib/LuaGate/LuaGate.hpp b/lib/LuaGate/LuaGate.hpp index 6d372439..f6d05a3f 100644 --- a/lib/LuaGate/LuaGate.hpp +++ b/lib/LuaGate/LuaGate.hpp @@ -10,7 +10,7 @@ namespace LuaG class State { private: - LuaState *_state; + lua_State *_state; public: //! @brief ctor State(); @@ -19,19 +19,27 @@ namespace LuaG ~State(); //! @brief No copy constrructor - State &State(State &) = delete; + State(State &) = delete; //! @brief No assign operator - State &operator() = delete; + State &operator=(State &) = delete; //! @brief Get Lua state - LuaState *getState(void); + lua_State *getState(void); //! @brief Execute a file in this state void dofile(std::string filepath); //! @brief Execute a string in this state void dostring(std::string str); - + + //! @brief Get return Number + float getReturnNumber(void); + + //! @brief Get return Number + bool getReturnBool(void); + + //! @brief call a lua function + bool callFunction(std::string funcName, int nbParams, int nbReturns); } } \ No newline at end of file diff --git a/lua_bind_info b/lua_bind_info new file mode 100644 index 00000000..72b27905 --- /dev/null +++ b/lua_bind_info @@ -0,0 +1,48 @@ +Create a "Object" metatable +map function to member function and get the instance using lua_userdata + +Constructor for Object instance +link to the Object metatable with __index + +Pass a Map object to the lua Update +function Update(Map) + +Or Map is global and set it before calling Update + +Map->infos = { + { x = 0, y = 0, z = 0, type = TYPE}, + , + +} + +Map->player = { + x, y, z +} + +Map->Ennemies = { + {x, y, z} +} + +Map->Bombs = { + { x, y, z, radius, timeLeft } +} + +Algos ? +Minimax, ExpectiMax, Alpha beta pruning + +Alpha beta, determine heuristic value of one node + +-in bomb range ++closer to player ++ bomb breaks wall + + +6 moves by turn +[ +1, 0, false, false +-1, 0, false, false +0, 1, false, false +0, -1, false, false +0, 0, false, true +0, 0, false, false +] diff --git a/sources/Component/IAControllable/IAControllableComponent.cpp b/sources/Component/IAControllable/IAControllableComponent.cpp index 16c3b745..db536945 100644 --- a/sources/Component/IAControllable/IAControllableComponent.cpp +++ b/sources/Component/IAControllable/IAControllableComponent.cpp @@ -7,6 +7,7 @@ #include "Map/MapInfo.hpp" #include "Component/IAControllable/IAControllableComponent.hpp" +//#include "System/IAControllable/IAControllableSystem.hpp" namespace BBM { @@ -14,6 +15,7 @@ namespace BBM : Component(entity), _scriptPath(scriptPath), state(luaL_newstate()) { luaL_openlibs(state); + luabridge::getGlobalNamespace(state) .beginNamespace ("luaBBM") .beginClass("MapInfo") @@ -23,6 +25,7 @@ namespace BBM .addProperty("type", &MapInfo::type) .endClass() .endNamespace(); + luaL_dofile(state, scriptPath.c_str()); } diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 62ed4b04..a3279b5d 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -531,7 +531,7 @@ namespace BBM .addComponent("assets/player/player.iqm", true, std::make_pair(MAP_DIFFUSE, "assets/player/blue.png")) .addComponent() .addComponent() - .addComponent() + //.addComponent() .addComponent("./ai_scripts/john.lua") .addComponent("assets/shaders/glsl330/predator.fs") .addComponent>() diff --git a/sources/System/IAControllable/IAControllableSystem.cpp b/sources/System/IAControllable/IAControllableSystem.cpp index f1ab55dd..4fc632a9 100644 --- a/sources/System/IAControllable/IAControllableSystem.cpp +++ b/sources/System/IAControllable/IAControllableSystem.cpp @@ -2,6 +2,7 @@ // Created by Louis Auzuret on 06/07/21 // +#include "Component/Bomb/BasicBombComponent.hpp" #include "Component/Tag/TagComponent.hpp" #include "Component/Controllable/ControllableComponent.hpp" #include "Component/IAControllable/IAControllableComponent.hpp" @@ -11,35 +12,8 @@ namespace BBM { IAControllableSystem::IAControllableSystem(WAL::Wal &wal) - : System(wal), _wal(wal), _map(), _players(), _cached(false) + : System(wal), _wal(wal), _cached(false) { } -/* - float IAControllableSystem::getReturnNumber(lua_State *state) - { - float res = 0; - - if (lua_isnil(state, -1)) - return res; - if (!lua_isnumber(state, -1)) - return res; - res = lua_tonumber(state, -1); - lua_pop(state, 1); - - return res; - } - - bool IAControllableSystem::getReturnBool(lua_State *state) - { - bool res = false; - - if (lua_isnil(state, -1)) - return res; - if (!lua_isboolean(state, -1)) - return res; - res = lua_toboolean(state, -1); - lua_pop(state, 1); - return res; - }*/ void IAControllableSystem::UpdateMapInfos(WAL::ViewEntity &entity) { @@ -60,8 +34,8 @@ namespace BBM continue; _players.push_back(MapInfo(pos.position, MapGenerator::NOTHING)); } - //for (auto &[other, pos, bomb] : _wal.getScene()->view()) - // _bombs.push_back(std::make_pair(pos.position, bomb.explosionRadius)); + for (auto &[other, pos, bomb] : _wal.getScene()->view()) + _bombs.push_back(std::make_pair(pos.position, bomb.explosionRadius)); _cached = true; } @@ -74,6 +48,11 @@ namespace BBM MapInfo player(pos.position, MapGenerator::NOTHING); UpdateMapInfos(entity); + + luabridge::getGlobalNamespace(ia.state) + .beginNamespace ("luaBBM") + .addFunction("isInExplosionRange", IAControllableSystem::isInExplosionRange) + .endNamespace(); luabridge::LuaRef updateFunc = luabridge::getGlobal(ia.state, "Update"); if (!updateFunc.isFunction()) return; @@ -101,9 +80,22 @@ namespace BBM bool IAControllableSystem::isInExplosionRange(float x, float y, float z) { - return false; - //for (auto &bomb : bombs) { - // + Vector3f pos(x, y, z); + //pos = pos.round(); + //for (auto &bomb : _bombs) { + // Vector3f bombPos = std::get<0>(bomb); + // int bombRadius = std::get<1>(bomb); + // for (int i = 1; i < bombRadius; i++) { + // if (pos == bombPos - Vector3f(i, 0, 0)) + // return true; + // if (pos == bombPos - Vector3f(-i, 0, 0)) + // return true; + // if (pos == bombPos - Vector3f(0, 0, i)) + // return true; + // if (pos == bombPos - Vector3f(0, 0, -i)) + // return true; + // } //} + return true; } } \ No newline at end of file diff --git a/sources/System/IAControllable/IAControllableSystem.hpp b/sources/System/IAControllable/IAControllableSystem.hpp index 56fe0336..62f5ddf4 100644 --- a/sources/System/IAControllable/IAControllableSystem.hpp +++ b/sources/System/IAControllable/IAControllableSystem.hpp @@ -26,11 +26,13 @@ namespace BBM //! @brief All players in the map std::vector _players; + //! @brief All bombs on the map std::vector> _bombs; //! @brief void UpdateMapInfos(WAL::ViewEntity &entity); public: + //! @inherit void onFixedUpdate(WAL::ViewEntity &entity) override; From fb53f4b5b7cbd83a4eaa5b5f6aae18dfcd16ed09 Mon Sep 17 00:00:00 2001 From: Bluub Date: Mon, 14 Jun 2021 15:32:07 +0200 Subject: [PATCH 19/78] compile with luagate --- CMakeLists.txt | 4 +++- ai_scripts/john.lua | 24 +++++++++---------- lib/LuaGate/{ => sources}/LuaGate.cpp | 2 +- lib/LuaGate/{ => sources}/LuaGate.hpp | 7 +++--- .../IAControllableComponent.cpp | 5 +++- .../IAControllableComponent.hpp | 5 +++- .../IAControllable/IAControllableSystem.cpp | 14 ++++++----- 7 files changed, 36 insertions(+), 25 deletions(-) rename lib/LuaGate/{ => sources}/LuaGate.cpp (97%) rename lib/LuaGate/{ => sources}/LuaGate.hpp (87%) diff --git a/CMakeLists.txt b/CMakeLists.txt index cc15ce25..a99ac474 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,11 +7,13 @@ find_package(Lua REQUIRED) include_directories(bomberman ${LUA_INCLUDE_DIR}) include_directories(bomberman lib/Ray/sources) include_directories(bomberman lib/wal/sources) +include_directories(bomberman lib/LuaGate/sources) include_directories(bomberman lib/LuaBridge) include_directories(bomberman sources) add_subdirectory(${PROJECT_SOURCE_DIR}/lib/wal) add_subdirectory(${PROJECT_SOURCE_DIR}/lib/Ray) +add_subdirectory(${PROJECT_SOURCE_DIR}/lib/LuaGate) if (EMSCRIPTEN) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 -s ASYNCIFY") @@ -128,7 +130,7 @@ add_executable(bomberman ) target_include_directories(bomberman PUBLIC sources ${LUA_INCLUDE_DIR} lib/LuaBridge) -target_link_libraries(bomberman PUBLIC wal ray ${LUA_LIBRARIES}) +target_link_libraries(bomberman PUBLIC wal ray ${LUA_LIBRARIES} LuaGate) add_executable(unit_tests EXCLUDE_FROM_ALL ${SOURCES} diff --git a/ai_scripts/john.lua b/ai_scripts/john.lua index 81356efa..ceca8853 100644 --- a/ai_scripts/john.lua +++ b/ai_scripts/john.lua @@ -41,18 +41,18 @@ function isInExplosionRange() return true end -function Update(player, infos, players) - local maxX = 0 - local maxZ = 0 - for i, info in ipairs(infos) do - if info.x > maxX then - maxX = info.x - end - if info.z > maxZ then - maxZ = info.z - end - end - local myMap = CreateMyMap(infos, maxX, maxZ) +function Update() + --local maxX = 0 + --local maxZ = 0 + --for i, info in ipairs(infos) do + -- if info.x > maxX then + -- maxX = info.x + -- end + -- if info.z > maxZ then + -- maxZ = info.z + -- end + --end + --local myMap = CreateMyMap(infos, maxX, maxZ) local x = math.random() local y = math.random() if (math.random() < 0.5) then diff --git a/lib/LuaGate/LuaGate.cpp b/lib/LuaGate/sources/LuaGate.cpp similarity index 97% rename from lib/LuaGate/LuaGate.cpp rename to lib/LuaGate/sources/LuaGate.cpp index d006f2f5..c3d567ed 100644 --- a/lib/LuaGate/LuaGate.cpp +++ b/lib/LuaGate/sources/LuaGate.cpp @@ -17,7 +17,7 @@ namespace LuaG lua_close(_state); } - LuaState *State::getState(void) + lua_State *State::getState(void) { return _state; } diff --git a/lib/LuaGate/LuaGate.hpp b/lib/LuaGate/sources/LuaGate.hpp similarity index 87% rename from lib/LuaGate/LuaGate.hpp rename to lib/LuaGate/sources/LuaGate.hpp index f6d05a3f..446f87b6 100644 --- a/lib/LuaGate/LuaGate.hpp +++ b/lib/LuaGate/sources/LuaGate.hpp @@ -10,6 +10,7 @@ namespace LuaG class State { private: + //! @”rief Lua state lua_State *_state; public: //! @brief ctor @@ -19,10 +20,10 @@ namespace LuaG ~State(); //! @brief No copy constrructor - State(State &) = delete; + State(const State &) = delete; //! @brief No assign operator - State &operator=(State &) = delete; + State &operator=(const State &) = delete; //! @brief Get Lua state lua_State *getState(void); @@ -41,5 +42,5 @@ namespace LuaG //! @brief call a lua function bool callFunction(std::string funcName, int nbParams, int nbReturns); - } + }; } \ No newline at end of file diff --git a/sources/Component/IAControllable/IAControllableComponent.cpp b/sources/Component/IAControllable/IAControllableComponent.cpp index db536945..d07e688b 100644 --- a/sources/Component/IAControllable/IAControllableComponent.cpp +++ b/sources/Component/IAControllable/IAControllableComponent.cpp @@ -12,10 +12,12 @@ namespace BBM { IAControllableComponent::IAControllableComponent(WAL::Entity &entity, std::string scriptPath) - : Component(entity), _scriptPath(scriptPath), state(luaL_newstate()) + : Component(entity), _scriptPath(scriptPath), state(luaL_newstate()), _state() { luaL_openlibs(state); + _state.dofile(scriptPath); + /* luabridge::getGlobalNamespace(state) .beginNamespace ("luaBBM") .beginClass("MapInfo") @@ -27,6 +29,7 @@ namespace BBM .endNamespace(); luaL_dofile(state, scriptPath.c_str()); + */ } WAL::Component *IAControllableComponent::clone(WAL::Entity &entity) const diff --git a/sources/Component/IAControllable/IAControllableComponent.hpp b/sources/Component/IAControllable/IAControllableComponent.hpp index 9ff60a90..16f075f6 100644 --- a/sources/Component/IAControllable/IAControllableComponent.hpp +++ b/sources/Component/IAControllable/IAControllableComponent.hpp @@ -12,7 +12,7 @@ #include "Entity/Entity.hpp" #include "Models/Vector3.hpp" #include "lua.hpp" -#include "LuaBridge.hpp" +#include "LuaGate.hpp" namespace BBM { @@ -25,6 +25,9 @@ namespace BBM //! @brief Lua executing state lua_State *state; + //! @brief LuaGate state + LuaG::State _state; + //! @inherit WAL::Component *clone(WAL::Entity &entity) const override; diff --git a/sources/System/IAControllable/IAControllableSystem.cpp b/sources/System/IAControllable/IAControllableSystem.cpp index 4fc632a9..2b576360 100644 --- a/sources/System/IAControllable/IAControllableSystem.cpp +++ b/sources/System/IAControllable/IAControllableSystem.cpp @@ -48,12 +48,13 @@ namespace BBM MapInfo player(pos.position, MapGenerator::NOTHING); UpdateMapInfos(entity); - - luabridge::getGlobalNamespace(ia.state) - .beginNamespace ("luaBBM") - .addFunction("isInExplosionRange", IAControllableSystem::isInExplosionRange) - .endNamespace(); - luabridge::LuaRef updateFunc = luabridge::getGlobal(ia.state, "Update"); + ia._state.callFunction("Update", 0, 4); + controllable.bomb = ia._state.getReturnBool(); + controllable.jump = ia._state.getReturnBool(); + controllable.move.y = ia._state.getReturnNumber(); + controllable.move.x = ia._state.getReturnNumber(); + /* + luabridge::LuaRef updateFunc = luabridge::getGlobal(ia.state, "Update"); if (!updateFunc.isFunction()) return; luabridge::LuaResult res = updateFunc(player, _map, _players); @@ -68,6 +69,7 @@ namespace BBM controllable.jump = res[2]; if (res[3].isBool()) controllable.bomb = res[3]; + */ } void IAControllableSystem::onSelfUpdate() From 4c0e765f415474455a990c28e902388dd20629a2 Mon Sep 17 00:00:00 2001 From: Bluub Date: Mon, 14 Jun 2021 17:39:07 +0200 Subject: [PATCH 20/78] push tables correctly, pushing player and raw map info --- ai_scripts/john.lua | 25 +++++---- ai_scripts/randboi.lua | 13 ++++- lib/LuaGate/sources/LuaGate.cpp | 27 +++++++-- lib/LuaGate/sources/LuaGate.hpp | 12 ++++ .../IAControllable/IAControllableSystem.cpp | 56 ++++++++++++++++++- .../IAControllable/IAControllableSystem.hpp | 11 +++- 6 files changed, 124 insertions(+), 20 deletions(-) diff --git a/ai_scripts/john.lua b/ai_scripts/john.lua index ceca8853..f9e51d88 100644 --- a/ai_scripts/john.lua +++ b/ai_scripts/john.lua @@ -1,8 +1,16 @@ ------------ JOHN AI +--[[ +Info available to the ai +mapinfo.player { x, y, z } +mapinfo.raw { {x, y, z, type }, ...} +mapinfo.dist { } +]] +------------ + local debug = false ---local debug = false + if not debug then log = function() end else @@ -41,7 +49,10 @@ function isInExplosionRange() return true end -function Update() +function Update(mapinfo) + print(mapinfo.raw[0].x) + print(mapinfo.raw[0].y) + print(mapinfo.raw[0].z) --local maxX = 0 --local maxZ = 0 --for i, info in ipairs(infos) do @@ -53,15 +64,7 @@ function Update() -- end --end --local myMap = CreateMyMap(infos, maxX, maxZ) - local x = math.random() - local y = math.random() - if (math.random() < 0.5) then - x = x * -1 - end - if (math.random() < 0.5) then - y = y * -1 - end - return x, y, false, true; + return 1, 1, false, false; --if (isInExplosionRange()) then -- return 0, , false, true -- --play defensive RUN diff --git a/ai_scripts/randboi.lua b/ai_scripts/randboi.lua index a92c0b43..0979d7ae 100644 --- a/ai_scripts/randboi.lua +++ b/ai_scripts/randboi.lua @@ -1,5 +1,14 @@ math.randomseed(os.time()) -function Update(player, infos, players) - return (math.random() < 0.5), (math.random() < 0.5), false, false; +function Update(mapinfo) + + local x = math.random() + local y = math.random() + if (math.random() < 0.5) then + x = x * -1 + end + if (math.random() < 0.5) then + y = y * -1 + end + return x, y, false, true; end \ No newline at end of file diff --git a/lib/LuaGate/sources/LuaGate.cpp b/lib/LuaGate/sources/LuaGate.cpp index c3d567ed..cbc5580d 100644 --- a/lib/LuaGate/sources/LuaGate.cpp +++ b/lib/LuaGate/sources/LuaGate.cpp @@ -59,12 +59,29 @@ namespace LuaG return res; } - bool State::callFunction(std::string funcName, int nbParams, int nbReturns) + bool State::callFunction(std::string , int nbParams, int nbReturns) { - lua_getglobal(_state, funcName.c_str()); - if (!lua_isfunction(_state, -1)) - return false; lua_pcall(_state, nbParams, nbReturns, 0); return true; } -} \ No newline at end of file + + void State::setTable(void) + { + lua_settable(_state, -3); + } + + void State::push(float val) + { + lua_pushnumber(_state, val); + } + + void State::push(std::string str) + { + lua_pushstring(_state, str.c_str()); + } + + void State::newTable(void) + { + lua_newtable(_state); + } +} diff --git a/lib/LuaGate/sources/LuaGate.hpp b/lib/LuaGate/sources/LuaGate.hpp index 446f87b6..1ee38c96 100644 --- a/lib/LuaGate/sources/LuaGate.hpp +++ b/lib/LuaGate/sources/LuaGate.hpp @@ -42,5 +42,17 @@ namespace LuaG //! @brief call a lua function bool callFunction(std::string funcName, int nbParams, int nbReturns); + + //! @brief setTable + void setTable(void); + + //! @brief push a number onto the lua stack + void push(float val); + + //! @brief push a string onto the lua stack + void push(std::string str); + + //! @brief Creates a new table at the top of the stack + void newTable(void); }; } \ No newline at end of file diff --git a/sources/System/IAControllable/IAControllableSystem.cpp b/sources/System/IAControllable/IAControllableSystem.cpp index 2b576360..cf88ef17 100644 --- a/sources/System/IAControllable/IAControllableSystem.cpp +++ b/sources/System/IAControllable/IAControllableSystem.cpp @@ -40,6 +40,54 @@ namespace BBM } + void IAControllableSystem::pushInfoPlayer(LuaG::State &state, MapInfo &player) + { + state.push("player"); + state.newTable(); + state.push("x"); + state.push(player.x); + state.setTable(); + state.push("y"); + state.push(player.y); + state.setTable(); + state.push("z"); + state.push(player.z); + state.setTable(); + state.setTable(); + } + + void IAControllableSystem::pushInfoRaw(LuaG::State &state) + { + state.push("raw"); + state.newTable(); + int index = 0; + for (auto &info : _map) { + state.push(index++); + state.newTable(); + state.push("x"); + state.push(info.x); + state.setTable(); + state.push("y"); + state.push(info.y); + state.setTable(); + state.push("z"); + state.push(info.z); + state.setTable(); + state.push("type"); + state.push(info.type); + state.setTable(); + state.setTable(); + } + state.setTable(); + } + + void IAControllableSystem::pushInfo(LuaG::State &state, MapInfo &player) + { + state.newTable(); + pushInfoPlayer(state, player); + pushInfoRaw(state); + } + void IAControllableSystem::onFixedUpdate(WAL::ViewEntity &entity) { auto &ia = entity.get(); @@ -48,11 +96,17 @@ namespace BBM MapInfo player(pos.position, MapGenerator::NOTHING); UpdateMapInfos(entity); - ia._state.callFunction("Update", 0, 4); + + lua_getglobal(ia._state.getState(), "Update"); + if (!lua_isfunction(ia._state.getState(), -1)) + return; + pushInfo(ia._state, player); + ia._state.callFunction("Update", 1, 4); controllable.bomb = ia._state.getReturnBool(); controllable.jump = ia._state.getReturnBool(); controllable.move.y = ia._state.getReturnNumber(); controllable.move.x = ia._state.getReturnNumber(); + lua_pop(state, -1); /* luabridge::LuaRef updateFunc = luabridge::getGlobal(ia.state, "Update"); if (!updateFunc.isFunction()) diff --git a/sources/System/IAControllable/IAControllableSystem.hpp b/sources/System/IAControllable/IAControllableSystem.hpp index 62f5ddf4..5bc1fa06 100644 --- a/sources/System/IAControllable/IAControllableSystem.hpp +++ b/sources/System/IAControllable/IAControllableSystem.hpp @@ -29,8 +29,17 @@ namespace BBM //! @brief All bombs on the map std::vector> _bombs; - //! @brief + //! @brief update the raw info of the map void UpdateMapInfos(WAL::ViewEntity &entity); + + //! @brief push player info + void pushInfoPlayer(LuaG::State &state, MapInfo &player); + + //! @brief push raw map info + void pushInfoRaw(LuaG::State &state); + + //! @brief push all the infos to the ai stack + void pushInfo(LuaG::State &state, MapInfo &player); public: //! @inherit From a712e42596a66c6e56aafc3089b7f79264d993a5 Mon Sep 17 00:00:00 2001 From: Bluub Date: Mon, 14 Jun 2021 18:29:41 +0200 Subject: [PATCH 21/78] clear players for each update --- .../System/IAControllable/IAControllableSystem.cpp | 12 ++++++------ todolua | 4 +++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/sources/System/IAControllable/IAControllableSystem.cpp b/sources/System/IAControllable/IAControllableSystem.cpp index cf88ef17..982234de 100644 --- a/sources/System/IAControllable/IAControllableSystem.cpp +++ b/sources/System/IAControllable/IAControllableSystem.cpp @@ -17,6 +17,12 @@ namespace BBM void IAControllableSystem::UpdateMapInfos(WAL::ViewEntity &entity) { + _players.clear(); + for (auto &[other, pos, _] : _wal.getScene()->view>()) { + if (static_cast(entity).getUid() == other.getUid()) + continue; + _players.push_back(MapInfo(pos.position, MapGenerator::NOTHING)); + } if (_cached) return; if (!_wal.getScene()) @@ -29,11 +35,6 @@ namespace BBM _map.push_back(MapInfo(pos.position, MapGenerator::BUMPER)); for (auto &[other, pos, _] : _wal.getScene()->view>()) _map.push_back(MapInfo(pos.position, MapGenerator::HOLE)); - for (auto &[other, pos, _] : _wal.getScene()->view>()) { - if (static_cast(entity).getUid() == other.getUid()) - continue; - _players.push_back(MapInfo(pos.position, MapGenerator::NOTHING)); - } for (auto &[other, pos, bomb] : _wal.getScene()->view()) _bombs.push_back(std::make_pair(pos.position, bomb.explosionRadius)); _cached = true; @@ -131,7 +132,6 @@ namespace BBM _cached = false; _map.clear(); _bombs.clear(); - _players.clear(); } bool IAControllableSystem::isInExplosionRange(float x, float y, float z) diff --git a/todolua b/todolua index ccf1ad93..11ae44bb 100644 --- a/todolua +++ b/todolua @@ -4,4 +4,6 @@ [ ] Closest Player [ ] GetPath to Point [ ] Closest Bonus - [ ] isInExplosionrRange \ No newline at end of file + [ ] isInExplosionrRange + +how do i do it ? \ No newline at end of file From 8dcc16b4c6f3cb03937c31426d450fa14bed0d59 Mon Sep 17 00:00:00 2001 From: Bluub Date: Tue, 15 Jun 2021 09:51:31 +0200 Subject: [PATCH 22/78] adding getglobal and pop to luagate --- ai_scripts/john.lua | 34 ++++++------- lib/LuaGate/sources/LuaGate.cpp | 12 ++++- lib/LuaGate/sources/LuaGate.hpp | 8 +++- lua_bind_info | 48 ------------------- .../IAControllableComponent.cpp | 17 +------ .../IAControllableComponent.hpp | 2 - .../IAControllable/IAControllableSystem.cpp | 25 ++-------- todolua | 9 ---- 8 files changed, 38 insertions(+), 117 deletions(-) delete mode 100644 lua_bind_info delete mode 100644 todolua diff --git a/ai_scripts/john.lua b/ai_scripts/john.lua index f9e51d88..63665371 100644 --- a/ai_scripts/john.lua +++ b/ai_scripts/john.lua @@ -9,7 +9,7 @@ mapinfo.dist { } ------------ -local debug = false +local debug = true if not debug then log = function() end @@ -45,25 +45,21 @@ function CreateMyMap(infos, maxX, maxZ) return map end -function isInExplosionRange() - return true -end - function Update(mapinfo) - print(mapinfo.raw[0].x) - print(mapinfo.raw[0].y) - print(mapinfo.raw[0].z) - --local maxX = 0 - --local maxZ = 0 - --for i, info in ipairs(infos) do - -- if info.x > maxX then - -- maxX = info.x - -- end - -- if info.z > maxZ then - -- maxZ = info.z - -- end - --end - --local myMap = CreateMyMap(infos, maxX, maxZ) + --print(mapinfo.raw[0].x) + --print(mapinfo.raw[0].y) + --print(mapinfo.raw[0].z) + local maxX = 0 + local maxZ = 0 + for i, info in ipairs(mapinfo.raw) do + if info.x > maxX then + maxX = info.x + end + if info.z > maxZ then + maxZ = info.z + end + end + local myMap = CreateMyMap(mapinfo.raw, maxX, maxZ) return 1, 1, false, false; --if (isInExplosionRange()) then -- return 0, , false, true diff --git a/lib/LuaGate/sources/LuaGate.cpp b/lib/LuaGate/sources/LuaGate.cpp index cbc5580d..bb381901 100644 --- a/lib/LuaGate/sources/LuaGate.cpp +++ b/lib/LuaGate/sources/LuaGate.cpp @@ -22,6 +22,11 @@ namespace LuaG return _state; } + void State::getGlobal(std::string str) + { + lua_getglobal(_state, str.c_str()); + } + void State::dofile(std::string filepath) { luaL_dofile(_state, filepath.c_str()); @@ -59,7 +64,7 @@ namespace LuaG return res; } - bool State::callFunction(std::string , int nbParams, int nbReturns) + bool State::callFunction(int nbParams, int nbReturns) { lua_pcall(_state, nbParams, nbReturns, 0); return true; @@ -84,4 +89,9 @@ namespace LuaG { lua_newtable(_state); } + + void State::popLast(void) + { + lua_pop(_state, -1); + } } diff --git a/lib/LuaGate/sources/LuaGate.hpp b/lib/LuaGate/sources/LuaGate.hpp index 1ee38c96..ed5bf73f 100644 --- a/lib/LuaGate/sources/LuaGate.hpp +++ b/lib/LuaGate/sources/LuaGate.hpp @@ -28,6 +28,9 @@ namespace LuaG //! @brief Get Lua state lua_State *getState(void); + //! @brief Get global value on top of the stack + void getGlobal(std::string str); + //! @brief Execute a file in this state void dofile(std::string filepath); @@ -41,7 +44,7 @@ namespace LuaG bool getReturnBool(void); //! @brief call a lua function - bool callFunction(std::string funcName, int nbParams, int nbReturns); + bool callFunction(int nbParams, int nbReturns); //! @brief setTable void setTable(void); @@ -54,5 +57,8 @@ namespace LuaG //! @brief Creates a new table at the top of the stack void newTable(void); + + //! @brief Pop last value on the stack + void popLast(void); }; } \ No newline at end of file diff --git a/lua_bind_info b/lua_bind_info deleted file mode 100644 index 72b27905..00000000 --- a/lua_bind_info +++ /dev/null @@ -1,48 +0,0 @@ -Create a "Object" metatable -map function to member function and get the instance using lua_userdata - -Constructor for Object instance -link to the Object metatable with __index - -Pass a Map object to the lua Update -function Update(Map) - -Or Map is global and set it before calling Update - -Map->infos = { - { x = 0, y = 0, z = 0, type = TYPE}, - , - -} - -Map->player = { - x, y, z -} - -Map->Ennemies = { - {x, y, z} -} - -Map->Bombs = { - { x, y, z, radius, timeLeft } -} - -Algos ? -Minimax, ExpectiMax, Alpha beta pruning - -Alpha beta, determine heuristic value of one node - --in bomb range -+closer to player -+ bomb breaks wall - - -6 moves by turn -[ -1, 0, false, false --1, 0, false, false -0, 1, false, false -0, -1, false, false -0, 0, false, true -0, 0, false, false -] diff --git a/sources/Component/IAControllable/IAControllableComponent.cpp b/sources/Component/IAControllable/IAControllableComponent.cpp index d07e688b..5bfa2643 100644 --- a/sources/Component/IAControllable/IAControllableComponent.cpp +++ b/sources/Component/IAControllable/IAControllableComponent.cpp @@ -12,24 +12,9 @@ namespace BBM { IAControllableComponent::IAControllableComponent(WAL::Entity &entity, std::string scriptPath) - : Component(entity), _scriptPath(scriptPath), state(luaL_newstate()), _state() + : Component(entity), _scriptPath(scriptPath), _state() { - luaL_openlibs(state); - _state.dofile(scriptPath); - /* - luabridge::getGlobalNamespace(state) - .beginNamespace ("luaBBM") - .beginClass("MapInfo") - .addProperty("x", &MapInfo::x) - .addProperty("y", &MapInfo::y) - .addProperty("z", &MapInfo::z) - .addProperty("type", &MapInfo::type) - .endClass() - .endNamespace(); - - luaL_dofile(state, scriptPath.c_str()); - */ } WAL::Component *IAControllableComponent::clone(WAL::Entity &entity) const diff --git a/sources/Component/IAControllable/IAControllableComponent.hpp b/sources/Component/IAControllable/IAControllableComponent.hpp index 16f075f6..99e6393e 100644 --- a/sources/Component/IAControllable/IAControllableComponent.hpp +++ b/sources/Component/IAControllable/IAControllableComponent.hpp @@ -22,8 +22,6 @@ namespace BBM //! @brief path to the lua script const std::string _scriptPath; public: - //! @brief Lua executing state - lua_State *state; //! @brief LuaGate state LuaG::State _state; diff --git a/sources/System/IAControllable/IAControllableSystem.cpp b/sources/System/IAControllable/IAControllableSystem.cpp index 982234de..1ef106c8 100644 --- a/sources/System/IAControllable/IAControllableSystem.cpp +++ b/sources/System/IAControllable/IAControllableSystem.cpp @@ -59,9 +59,9 @@ namespace BBM void IAControllableSystem::pushInfoRaw(LuaG::State &state) { + int index = 0; state.push("raw"); state.newTable(); - int index = 0; for (auto &info : _map) { state.push(index++); state.newTable(); @@ -98,33 +98,16 @@ namespace BBM UpdateMapInfos(entity); - lua_getglobal(ia._state.getState(), "Update"); + ia._state.getGlobal("Update"); if (!lua_isfunction(ia._state.getState(), -1)) return; pushInfo(ia._state, player); - ia._state.callFunction("Update", 1, 4); + ia._state.callFunction(1, 4); controllable.bomb = ia._state.getReturnBool(); controllable.jump = ia._state.getReturnBool(); controllable.move.y = ia._state.getReturnNumber(); controllable.move.x = ia._state.getReturnNumber(); - lua_pop(state, -1); - /* - luabridge::LuaRef updateFunc = luabridge::getGlobal(ia.state, "Update"); - if (!updateFunc.isFunction()) - return; - luabridge::LuaResult res = updateFunc(player, _map, _players); - - if (res.hasFailed() || res.size() != 4) - return; - if (res[0].isNumber()) - controllable.move.x = res[0]; - if (res[1].isNumber()) - controllable.move.y = res[1]; - if (res[2].isBool()) - controllable.jump = res[2]; - if (res[3].isBool()) - controllable.bomb = res[3]; - */ + ia._state.popLast(); } void IAControllableSystem::onSelfUpdate() diff --git a/todolua b/todolua deleted file mode 100644 index 11ae44bb..00000000 --- a/todolua +++ /dev/null @@ -1,9 +0,0 @@ -[ ] Metatable for MapInfo -[ ] Metatable for Vector of MapInfo -[ ] C++ helper function for ai - [ ] Closest Player - [ ] GetPath to Point - [ ] Closest Bonus - [ ] isInExplosionrRange - -how do i do it ? \ No newline at end of file From f922d563d79a42cd6d0d3ad0972f6af0c0372f1d Mon Sep 17 00:00:00 2001 From: Bluub Date: Tue, 15 Jun 2021 11:32:42 +0200 Subject: [PATCH 23/78] sending danger map to the script as raw data --- CMakeLists.txt | 3 +- ai_scripts/john.lua | 50 +- lib/LuaBridge/LuaBridge.hpp | 7789 ----------------- .../IAControllable/IAControllableSystem.cpp | 64 +- .../IAControllable/IAControllableSystem.hpp | 10 +- 5 files changed, 75 insertions(+), 7841 deletions(-) delete mode 100644 lib/LuaBridge/LuaBridge.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a99ac474..afefeb04 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,6 @@ include_directories(bomberman ${LUA_INCLUDE_DIR}) include_directories(bomberman lib/Ray/sources) include_directories(bomberman lib/wal/sources) include_directories(bomberman lib/LuaGate/sources) -include_directories(bomberman lib/LuaBridge) include_directories(bomberman sources) add_subdirectory(${PROJECT_SOURCE_DIR}/lib/wal) @@ -129,7 +128,7 @@ add_executable(bomberman ${SOURCES} ) -target_include_directories(bomberman PUBLIC sources ${LUA_INCLUDE_DIR} lib/LuaBridge) +target_include_directories(bomberman PUBLIC sources ${LUA_INCLUDE_DIR}) target_link_libraries(bomberman PUBLIC wal ray ${LUA_LIBRARIES} LuaGate) add_executable(unit_tests EXCLUDE_FROM_ALL diff --git a/ai_scripts/john.lua b/ai_scripts/john.lua index 63665371..0882c3d4 100644 --- a/ai_scripts/john.lua +++ b/ai_scripts/john.lua @@ -9,7 +9,7 @@ mapinfo.dist { } ------------ -local debug = true +local debug = false if not debug then log = function() end @@ -30,42 +30,52 @@ function PrintMap(map, maxX, maxZ) end end -function CreateMyMap(infos, maxX, maxZ) +function CreateMyMap(infos, maxX, maxY) local map = {} for i=0,maxX + 1 do map[i] = {} - for j=0,maxZ + 1 do + for j=0,maxY + 1 do map[i][j] = 0 end end for i, info in ipairs(infos) do - map[info.x][info.z] = info.type + map[info.x][info.y] = info.type end - PrintMap(map, maxX, maxZ) + PrintMap(map, maxX, maxY) return map end +function isInExplosionRange(mapinfo, x, y) + for i, danger in ipairs(mapinfo.danger) do + if danger.x == x and danger.y == y then + return true + end + end + return false +end + function Update(mapinfo) - --print(mapinfo.raw[0].x) - --print(mapinfo.raw[0].y) - --print(mapinfo.raw[0].z) local maxX = 0 - local maxZ = 0 + local maxY = 0 for i, info in ipairs(mapinfo.raw) do if info.x > maxX then maxX = info.x end - if info.z > maxZ then - maxZ = info.z + if info.y > maxY then + maxY = info.y end end - local myMap = CreateMyMap(mapinfo.raw, maxX, maxZ) - return 1, 1, false, false; - --if (isInExplosionRange()) then - -- return 0, , false, true - -- --play defensive RUN - --else - -- return 1, 1, false, false; - -- --play offensive - --end + local roundedPlayerPos = {x = math.floor(mapinfo.player.x+0.5), y = math.floor(mapinfo.player.y+0.5)} + local myMap = CreateMyMap(mapinfo.raw, maxX, maxY) + if (isInExplosionRange(mapinfo, roundedPlayerPos.x, roundedPlayerPos.y)) then + if (myMap[roundedPlayerPos.x + 1][roundedPlayerPos.y] ~= 0) then + return -1, 0, false, false + else + return 1, 0, false, false + end + --play defensive RUN + else + return 1, 0, true, true; + --play offensive + end end \ No newline at end of file diff --git a/lib/LuaBridge/LuaBridge.hpp b/lib/LuaBridge/LuaBridge.hpp deleted file mode 100644 index d8e84159..00000000 --- a/lib/LuaBridge/LuaBridge.hpp +++ /dev/null @@ -1,7789 +0,0 @@ -// https://github.com/kunitoki/LuaBridge3 -// Copyright 2021, Lucio Asnaghi -// SPDX-License-Identifier: MIT - -// clang-format off - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Begin File: Source/LuaBridge/detail/Config.h - -// https://github.com/kunitoki/LuaBridge3 -// Copyright 2020, Lucio Asnaghi -// Copyright 2020, Dmitry Tarakanov -// Copyright 2019, George Tokmaji -// SPDX-License-Identifier: MIT - -#if !(__cplusplus >= 201703L || (defined(_MSC_VER) && _HAS_CXX17)) -#error LuaBridge 3 requires a compliant C++17 compiler, or C++17 has not been enabled ! -#endif - -#if defined(_MSC_VER) -#if _CPPUNWIND || _HAS_EXCEPTIONS -#define LUABRIDGE_HAS_EXCEPTIONS 1 -#else -#define LUABRIDGE_HAS_EXCEPTIONS 0 -#endif -#elif defined(__clang__) -#if __EXCEPTIONS && __has_feature(cxx_exceptions) -#define LUABRIDGE_HAS_EXCEPTIONS 1 -#else -#define LUABRIDGE_HAS_EXCEPTIONS 0 -#endif -#elif defined(__GNUC__) -#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) -#define LUABRIDGE_HAS_EXCEPTIONS 1 -#else -#define LUABRIDGE_HAS_EXCEPTIONS 0 -#endif -#endif - -// End File: Source/LuaBridge/detail/Config.h - -// Begin File: Source/LuaBridge/detail/LuaHelpers.h - -// https://github.com/kunitoki/LuaBridge3 -// Copyright 2020, Lucio Asnaghi -// Copyright 2012, Vinnie Falco -// Copyright 2007, Nathan Reed -// SPDX-License-Identifier: MIT - -namespace luabridge { - -// These are for Lua versions prior to 5.2.0. -#if LUA_VERSION_NUM < 502 - -using lua_Unsigned = lua_Integer; - -inline int lua_absindex(lua_State* L, int idx) -{ - if (idx > LUA_REGISTRYINDEX && idx < 0) - return lua_gettop(L) + idx + 1; - else - return idx; -} - -inline void lua_rawgetp(lua_State* L, int idx, void const* p) -{ - idx = lua_absindex(L, idx); - lua_pushlightuserdata(L, const_cast(p)); - lua_rawget(L, idx); -} - -inline void lua_rawsetp(lua_State* L, int idx, void const* p) -{ - idx = lua_absindex(L, idx); - luaL_checkstack(L, 1, "not enough stack slots"); - lua_pushlightuserdata(L, const_cast(p)); - lua_insert(L, -2); - lua_rawset(L, idx); -} - -#define LUA_OPEQ 1 -#define LUA_OPLT 2 -#define LUA_OPLE 3 - -inline int lua_compare(lua_State* L, int idx1, int idx2, int op) -{ - switch (op) - { - case LUA_OPEQ: - return lua_equal(L, idx1, idx2); - break; - - case LUA_OPLT: - return lua_lessthan(L, idx1, idx2); - break; - - case LUA_OPLE: - return lua_equal(L, idx1, idx2) || lua_lessthan(L, idx1, idx2); - break; - - default: - return 0; - }; -} - -inline int get_length(lua_State* L, int idx) -{ - return int(lua_objlen(L, idx)); -} - -#else -inline int get_length(lua_State* L, int idx) -{ - lua_len(L, idx); - int len = int(luaL_checknumber(L, -1)); - lua_pop(L, 1); - return len; -} - -#endif - -#ifndef LUA_OK -#define LUABRIDGE_LUA_OK 0 -#else -#define LUABRIDGE_LUA_OK LUA_OK -#endif - -/** - * @brief Helper for unused vars. - */ -template -constexpr void unused(Args&&...) -{ -} - -/** - * @brief Helper to throw or return an error code. - */ -template -std::error_code throw_or_error_code(ErrorType error) -{ -#if LUABRIDGE_HAS_EXCEPTIONS - throw T(makeErrorCode(error).message().c_str()); -#else - return makeErrorCode(error); -#endif -} - -template -std::error_code throw_or_error_code(lua_State* L, ErrorType error) -{ -#if LUABRIDGE_HAS_EXCEPTIONS - throw T(L, makeErrorCode(error)); -#else - return (void)L, makeErrorCode(error); -#endif -} - -/** - * @brief Helper to throw or assert. - */ -template -void throw_or_assert(Args&&... args) -{ -#if LUABRIDGE_HAS_EXCEPTIONS - throw T(std::forward(args)...); -#else - unused(std::forward(args)...); - assert(false); -#endif -} - -/** - * @brief Helper to set unsigned. - */ -template -void pushunsigned(lua_State* L, T value) -{ -#if LUA_VERSION_NUM != 502 - lua_pushinteger(L, static_cast(value)); -#else - lua_pushunsigned(L, static_cast(value)); -#endif -} - -/** - * @brief Get a table value, bypassing metamethods. - */ -inline void rawgetfield(lua_State* L, int index, char const* key) -{ - assert(lua_istable(L, index)); - index = lua_absindex(L, index); - lua_pushstring(L, key); - lua_rawget(L, index); -} - -/** - * @brief Set a table value, bypassing metamethods. - */ -inline void rawsetfield(lua_State* L, int index, char const* key) -{ - assert(lua_istable(L, index)); - index = lua_absindex(L, index); - lua_pushstring(L, key); - lua_insert(L, -2); - lua_rawset(L, index); -} - -/** - * @brief Returns true if the value is a full userdata (not light). - */ -[[nodiscard]] inline bool isfulluserdata(lua_State* L, int index) -{ - return lua_isuserdata(L, index) && !lua_islightuserdata(L, index); -} - -/** - * @brief Test lua_State objects for global equality. - * - * This can determine if two different lua_State objects really point - * to the same global state, such as when using coroutines. - * - * @note This is used for assertions. - */ -[[nodiscard]] inline bool equalstates(lua_State* L1, lua_State* L2) -{ - return lua_topointer(L1, LUA_REGISTRYINDEX) == lua_topointer(L2, LUA_REGISTRYINDEX); -} - -/** - * @brief Return an aligned pointer of type T. - */ -template -[[nodiscard]] T* align(void* ptr) noexcept -{ - auto address = reinterpret_cast(ptr); - - auto offset = address % alignof(T); - auto aligned_address = (offset == 0) ? address : (address + alignof(T) - offset); - - return reinterpret_cast(aligned_address); -} - -/** - * @brief Return the space needed to align the type T on an unaligned address. - */ -template -[[nodiscard]] size_t maximum_space_needed_to_align() noexcept -{ - return sizeof(T) + alignof(T) - 1; -} - -/** - * @brief Allocate lua userdata taking into account alignment. - * - * Using this instead of lua_newuserdata directly prevents alignment warnings on 64bits platforms. - */ -template -void* lua_newuserdata_aligned(lua_State* L, Args&&... args) -{ - void* pointer = lua_newuserdata(L, maximum_space_needed_to_align()); - - T* aligned = align(pointer); - - new (aligned) T(std::forward(args)...); - - return pointer; -} - -/** - * @brief Deallocate lua userdata taking into account alignment. - */ -template -int lua_deleteuserdata_aligned(lua_State* L) -{ - assert(isfulluserdata(L, 1)); - - T* aligned = align(lua_touserdata(L, 1)); - aligned->~T(); - - return 0; -} - -/** - * @brief Helper to write a lua string error. - */ -inline void writestringerror(const char* fmt, const char* text) -{ - fprintf(stderr, fmt, text); - fflush(stderr); -} - -} // namespace luabridge - -// End File: Source/LuaBridge/detail/LuaHelpers.h - -// Begin File: Source/LuaBridge/detail/Errors.h - -// https://github.com/vinniefalco/LuaBridge -// Copyright 2021, Lucio Asnaghi -// SPDX-License-Identifier: MIT - -namespace luabridge { - -//================================================================================================= -/** - * @brief LuaBridge error codes. - */ -enum class ErrorCode -{ - ClassNotRegistered = 1, - - LuaFunctionCallFailed, -}; - -//================================================================================================= -namespace detail { -struct ErrorCategory : std::error_category -{ - const char* name() const noexcept override - { - return "luabridge"; - } - - std::string message(int ev) const override - { - switch (static_cast(ev)) - { - case ErrorCode::ClassNotRegistered: - return "The class is not registered in LuaBridge"; - - case ErrorCode::LuaFunctionCallFailed: - return "The lua function invocation raised an error"; - - default: - return "Unknown error"; - } - } - - static const ErrorCategory& getInstance() noexcept - { - static ErrorCategory category; - return category; - } -}; -} // namespace detail - -//================================================================================================= -/** - * @brief Construct an error code from the error enum. - */ -inline std::error_code makeErrorCode(ErrorCode e) -{ - return { static_cast(e), detail::ErrorCategory::getInstance() }; -} - -} // namespace luabridge - -namespace std { -template <> struct is_error_code_enum : true_type {}; -} // namespace std - -// End File: Source/LuaBridge/detail/Errors.h - -// Begin File: Source/LuaBridge/detail/LuaException.h - -// https://github.com/kunitoki/LuaBridge3 -// Copyright 2021, Lucio Asnaghi -// Copyright 2012, Vinnie Falco -// Copyright 2008, Nigel Atkinson -// SPDX-License-Identifier: MIT - -namespace luabridge { - -//================================================================================================ -class LuaException : public std::exception -{ -public: - //============================================================================================= - /** - * @brief Construct a LuaException after a lua_pcall(). - * - * Assumes the error string is on top of the stack, but provides a generic error message otherwise. - */ - LuaException(lua_State* L, std::error_code code) - : m_L(L) - , m_code(code) - { - } - - ~LuaException() noexcept override - { - } - - //============================================================================================= - /** - * @brief Return the error message. - */ - const char* what() const noexcept override - { - return m_what.c_str(); - } - - //============================================================================================= - /** - * @brief Throw an exception or raises a luaerror when exceptions are disabled. - * - * This centralizes all the exceptions thrown, so that we can set breakpoints before the stack is - * unwound, or otherwise customize the behavior. - */ - template - static void raise(const Exception& e) - { - assert(areExceptionsEnabled()); - -#if LUABRIDGE_HAS_EXCEPTIONS - throw e; -#else - unused(e); - - std::abort(); -#endif - } - - //============================================================================================= - /** - * @brief Check if exceptions are enabled. - */ - static bool areExceptionsEnabled() noexcept - { - return exceptionsEnabled(); - } - - /** - * @brief Initializes error handling. - * - * Subsequent Lua errors are translated to C++ exceptions, or logging and abort if exceptions are disabled. - */ - static void enableExceptions(lua_State* L) noexcept - { - exceptionsEnabled() = true; - - lua_atpanic(L, panicHandlerCallback); - } - -private: - struct FromLua {}; - - LuaException(lua_State* L, std::error_code code, FromLua) - : m_L(L) - , m_code(code) - { - whatFromStack(); - } - - void whatFromStack() - { - std::stringstream ss; - - const char* errorText = nullptr; - - if (lua_gettop(m_L) > 0) - { - errorText = lua_tostring(m_L, -1); - lua_pop(m_L, 1); - } - - ss << (errorText ? errorText : "Unknown error") << " (code=" << m_code.message() << ")"; - - m_what = std::move(ss).str(); - } - - static int panicHandlerCallback(lua_State* L) - { -#if LUABRIDGE_HAS_EXCEPTIONS - throw LuaException(L, makeErrorCode(ErrorCode::LuaFunctionCallFailed), FromLua{}); -#else - unused(L); - - std::abort(); -#endif - } - - static bool& exceptionsEnabled() - { - static bool areExceptionsEnabled = false; - return areExceptionsEnabled; - } - - lua_State* m_L = nullptr; - std::error_code m_code; - std::string m_what; -}; - -//================================================================================================= -/** - * @brief Initializes error handling using C++ exceptions. - * - * Subsequent Lua errors are translated to C++ exceptions. It aborts the application if called when no exceptions. - */ -inline void enableExceptions(lua_State* L) noexcept -{ -#if LUABRIDGE_HAS_EXCEPTIONS - LuaException::enableExceptions(L); -#else - unused(L); - - assert(false); // Never call this function when exceptions are not enabled. -#endif -} - -} // namespace luabridge - -// End File: Source/LuaBridge/detail/LuaException.h - -// Begin File: Source/LuaBridge/detail/ClassInfo.h - -// https://github.com/kunitoki/LuaBridge3 -// Copyright 2020, Lucio Asnaghi -// Copyright 2020, Dmitry Tarakanov -// Copyright 2012, Vinnie Falco -// SPDX-License-Identifier: MIT - -namespace luabridge { -namespace detail { - -//================================================================================================= -/** - * @brief A unique key for a type name in a metatable. - */ -inline const void* getTypeKey() noexcept -{ - return reinterpret_cast(0x71); -} - -//================================================================================================= -/** - * @brief The key of a const table in another metatable. - */ -inline const void* getConstKey() noexcept -{ - return reinterpret_cast(0xc07); -} - -//================================================================================================= -/** - * @brief The key of a class table in another metatable. - */ -inline const void* getClassKey() noexcept -{ - return reinterpret_cast(0xc1a); -} - -//================================================================================================= -/** - * @brief The key of a propget table in another metatable. - */ -inline const void* getPropgetKey() noexcept -{ - return reinterpret_cast(0x6e7); -} - -//================================================================================================= -/** - * @brief The key of a propset table in another metatable. - */ -inline const void* getPropsetKey() noexcept -{ - return reinterpret_cast(0x5e7); -} - -//================================================================================================= -/** - * @brief The key of a static table in another metatable. - */ -inline const void* getStaticKey() noexcept -{ - return reinterpret_cast(0x57a); -} - -//================================================================================================= -/** - * @brief The key of a parent table in another metatable. - */ -inline const void* getParentKey() noexcept -{ - return reinterpret_cast(0xdad); -} - -//================================================================================================= -/** - * @brief Get the key for the static table in the Lua registry. - * - * The static table holds the static data members, static properties, and static member functions for a class. - */ -template -const void* getStaticRegistryKey() noexcept -{ - static char value; - return std::addressof(value); -} - -//================================================================================================= -/** - * @brief Get the key for the class table in the Lua registry. - * - * The class table holds the data members, properties, and member functions of a class. Read-only data and properties, and const - * member functions are also placed here (to save a lookup in the const table). - */ -template -const void* getClassRegistryKey() noexcept -{ - static char value; - return std::addressof(value); -} - -//================================================================================================= -/** - * @brief Get the key for the const table in the Lua registry. - * - * The const table holds read-only data members and properties, and const member functions of a class. - */ -template -const void* getConstRegistryKey() noexcept -{ - static char value; - return std::addressof(value); -} - -} // namespace detail -} // namespace luabridge - -// End File: Source/LuaBridge/detail/ClassInfo.h - -// Begin File: Source/LuaBridge/detail/TypeTraits.h - -// https://github.com/kunitoki/LuaBridge3 -// Copyright 2020, Lucio Asnaghi -// Copyright 2019, Dmitry Tarakanov -// Copyright 2012, Vinnie Falco -// SPDX-License-Identifier: MIT - -namespace luabridge { - -//================================================================================================= -/** - * @brief Container traits. - * - * Unspecialized ContainerTraits has the isNotContainer typedef for SFINAE. All user defined containers must supply an appropriate - * specialization for ContinerTraits (without the alias isNotContainer). The containers that come with LuaBridge also come with the - * appropriate ContainerTraits specialization. - * - * @note See the corresponding declaration for details. - * - * A specialization of ContainerTraits for some generic type ContainerType looks like this: - * - * @code - * - * template - * struct ContainerTraits> - * { - * using Type = T; - * - * static ContainerType construct(T* c) - * { - * return c; // Implementation-dependent on ContainerType - * } - * - * static T* get(const ContainerType& c) - * { - * return c.get(); // Implementation-dependent on ContainerType - * } - * }; - * - * @endcode - */ -template -struct ContainerTraits -{ - using IsNotContainer = bool; - - using Type = T; -}; - -/** - * @brief Register shared_ptr support as container. - * - * @tparam T Class that is hold by the shared_ptr, must inherit from std::enable_shared_from_this. - */ -template -struct ContainerTraits> -{ - static_assert(std::is_base_of_v, T>); - - using Type = T; - - static std::shared_ptr construct(T* t) - { - return t->shared_from_this(); - } - - static T* get(const std::shared_ptr& c) - { - return c.get(); - } -}; - -namespace detail { - -//================================================================================================= -/** - * @brief Determine if type T is a container. - * - * To be considered a container, there must be a specialization of ContainerTraits with the required fields. - */ -template -class IsContainer -{ -private: - typedef char yes[1]; // sizeof (yes) == 1 - typedef char no[2]; // sizeof (no) == 2 - - template - static constexpr no& test(typename C::IsNotContainer*); - - template - static constexpr yes& test(...); - -public: - static constexpr bool value = sizeof(test>(0)) == sizeof(yes); -}; - -} // namespace detail -} // namespace luabridge - -// End File: Source/LuaBridge/detail/TypeTraits.h - -// Begin File: Source/LuaBridge/detail/Userdata.h - -// https://github.com/kunitoki/LuaBridge3 -// Copyright 2020, Lucio Asnaghi -// Copyright 2019, Dmitry Tarakanov -// Copyright 2012, Vinnie Falco -// SPDX-License-Identifier: MIT - -namespace luabridge { -namespace detail { - -//================================================================================================= -/** - * @brief Return the identity pointer for our lightuserdata tokens. - * - * Because of Lua's dynamic typing and our improvised system of imposing C++ class structure, there is the possibility that executing - * scripts may knowingly or unknowingly cause invalid data to get passed to the C functions created by LuaBridge. - * - * In particular, our security model addresses the following: - * - * 1. Scripts cannot create a userdata (ignoring the debug lib). - * - * 2. Scripts cannot create a lightuserdata (ignoring the debug lib). - * - * 3. Scripts cannot set the metatable on a userdata. - */ - -/** - * @brief Interface to a class pointer retrievable from a userdata. - */ -class Userdata -{ -private: - //============================================================================================= - /** - * @brief Validate and retrieve a Userdata on the stack. - * - * The Userdata must exactly match the corresponding class table or const table, or else a Lua error is raised. This is used for the - * __gc metamethod. - */ - static Userdata* getExactClass(lua_State* L, int index, const void* classKey) - { - return (void)classKey, static_cast(lua_touserdata(L, lua_absindex(L, index))); - } - - //============================================================================================= - /** - * @brief Validate and retrieve a Userdata on the stack. - * - * The Userdata must be derived from or the same as the given base class, identified by the key. If canBeConst is false, generates - * an error if the resulting Userdata represents to a const object. We do the type check first so that the error message is informative. - */ - static Userdata* getClass(lua_State* L, - int index, - const void* registryConstKey, - const void* registryClassKey, - bool canBeConst) - { - index = lua_absindex(L, index); - - lua_getmetatable(L, index); // Stack: object metatable (ot) | nil - if (!lua_istable(L, -1)) - { - lua_rawgetp(L, LUA_REGISTRYINDEX, registryClassKey); // Stack: registry metatable (rt) | nil - return throwBadArg(L, index); - } - - lua_rawgetp(L, -1, getConstKey()); // Stack: ot | nil, const table (co) | nil - assert(lua_istable(L, -1) || lua_isnil(L, -1)); - - // If const table is NOT present, object is const. Use non-const registry table - // if object cannot be const, so constness validation is done automatically. - // E.g. nonConstFn (constObj) - // -> canBeConst = false, isConst = true - // -> 'Class' registry table, 'const Class' object table - // -> 'expected Class, got const Class' - bool isConst = lua_isnil(L, -1); // Stack: ot | nil, nil, rt - if (isConst && canBeConst) - { - lua_rawgetp(L, LUA_REGISTRYINDEX, registryConstKey); // Stack: ot, nil, rt - } - else - { - lua_rawgetp(L, LUA_REGISTRYINDEX, registryClassKey); // Stack: ot, co, rt - } - - lua_insert(L, -3); // Stack: rt, ot, co | nil - lua_pop(L, 1); // Stack: rt, ot - - for (;;) - { - if (lua_rawequal(L, -1, -2)) // Stack: rt, ot - { - lua_pop(L, 2); // Stack: - - return static_cast(lua_touserdata(L, index)); - } - - // Replace current metatable with it's base class. - lua_rawgetp(L, -1, getParentKey()); // Stack: rt, ot, parent ot (pot) | nil - - if (lua_isnil(L, -1)) // Stack: rt, ot, nil - { - // Drop the object metatable because it may be some parent metatable - lua_pop(L, 2); // Stack: rt - return throwBadArg(L, index); - } - - lua_remove(L, -2); // Stack: rt, pot - } - - // no return - } - - static bool isInstance(lua_State* L, int index, const void* registryClassKey) - { - index = lua_absindex(L, index); - - int result = lua_getmetatable(L, index); // Stack: object metatable (ot) | nothing - if (result == 0) - return false; // Nothing was pushed on the stack - - if (!lua_istable(L, -1)) - { - lua_pop(L, 1); // Stack: - - return false; - } - - lua_rawgetp(L, LUA_REGISTRYINDEX, registryClassKey); // Stack: ot, rt - lua_insert(L, -2); // Stack: rt, ot - - for (;;) - { - if (lua_rawequal(L, -1, -2)) // Stack: rt, ot - { - lua_pop(L, 2); // Stack: - - return true; - } - - // Replace current metatable with it's base class. - lua_rawgetp(L, -1, getParentKey()); // Stack: rt, ot, parent ot (pot) | nil - - if (lua_isnil(L, -1)) // Stack: rt, ot, nil - { - lua_pop(L, 3); // Stack: - - return false; - } - - lua_remove(L, -2); // Stack: rt, pot - } - } - - static Userdata* throwBadArg(lua_State* L, int index) - { - assert(lua_istable(L, -1) || lua_isnil(L, -1)); // Stack: rt | nil - - const char* expected = 0; - if (lua_isnil(L, -1)) // Stack: nil - { - expected = "unregistered class"; - } - else - { - lua_rawgetp(L, -1, getTypeKey()); // Stack: rt, registry type - expected = lua_tostring(L, -1); - } - - const char* got = 0; - if (lua_isuserdata(L, index)) - { - lua_getmetatable(L, index); // Stack: ..., ot | nil - if (lua_istable(L, -1)) // Stack: ..., ot - { - lua_rawgetp(L, -1, getTypeKey()); // Stack: ..., ot, object type | nil - if (lua_isstring(L, -1)) - { - got = lua_tostring(L, -1); - } - } - } - - if (!got) - { - got = lua_typename(L, lua_type(L, index)); - } - - luaL_argerror(L, index, lua_pushfstring(L, "%s expected, got %s", expected, got)); - return 0; - } - -public: - virtual ~Userdata() {} - - //============================================================================================= - /** - * @brief Returns the Userdata* if the class on the Lua stack matches. - * - * If the class does not match, a Lua error is raised. - * - * @tparam T A registered user class. - * - * @param L A Lua state. - * @param index The index of an item on the Lua stack. - * - * @return A userdata pointer if the class matches. - */ - template - static Userdata* getExact(lua_State* L, int index) - { - return getExactClass(L, index, detail::getClassRegistryKey()); - } - - //============================================================================================= - /** - * @brief Get a pointer to the class from the Lua stack. - * - * If the object is not the class or a subclass, or it violates the const-ness, a Lua error is raised. - * - * @tparam T A registered user class. - * - * @param L A Lua state. - * @param index The index of an item on the Lua stack. - * @param canBeConst TBD - * - * @return A pointer if the class and constness match. - */ - template - static T* get(lua_State* L, int index, bool canBeConst) - { - if (lua_isnil(L, index)) - return nullptr; - - return static_cast(getClass(L, - index, - detail::getConstRegistryKey(), - detail::getClassRegistryKey(), - canBeConst) - ->getPointer()); - } - - template - static bool isInstance(lua_State* L, int index) - { - return isInstance(L, index, detail::getClassRegistryKey()); - } - -protected: - Userdata() = default; - - /** - * @brief Get an untyped pointer to the contained class. - */ - void* getPointer() const noexcept - { - return m_p; - } - - void* m_p = nullptr; // subclasses must set this -}; - -//================================================================================================= -/** - * @brief Wraps a class object stored in a Lua userdata. - * - * The lifetime of the object is managed by Lua. The object is constructed inside the userdata using placement new. - */ -template -class UserdataValue : public Userdata -{ -public: - /** - * @brief Push a T via placement new. - * - * The caller is responsible for calling placement new using the returned uninitialized storage. - * - * @param L A Lua state. - * - * @return An object referring to the newly created userdata value. - */ - static UserdataValue* place(lua_State* L, std::error_code& ec) - { - auto* ud = new (lua_newuserdata(L, sizeof(UserdataValue))) UserdataValue(); - - lua_rawgetp(L, LUA_REGISTRYINDEX, detail::getClassRegistryKey()); - - if (!lua_istable(L, -1)) - { - lua_pop(L, 1); // possibly: a nil - - ud->~UserdataValue(); - - ec = throw_or_error_code(L, ErrorCode::ClassNotRegistered); - - return nullptr; - } - - lua_setmetatable(L, -2); - - return ud; - } - - /** - * @brief Push T via copy construction from U. - * - * @tparam U A container type. - * - * @param L A Lua state. - * @param u A container object l-value reference. - * @param ec Error code that will be set in case of failure to push on the lua stack. - */ - template - static bool push(lua_State* L, const U& u, std::error_code& ec) - { - auto* ud = place(L, ec); - - if (!ud) - return false; - - new (ud->getObject()) U(u); - - ud->commit(); - - return true; - } - - /** - * @brief Push T via move construction from U. - * - * @tparam U A container type. - * - * @param L A Lua state. - * @param u A container object r-value reference. - * @param ec Error code that will be set in case of failure to push on the lua stack. - */ - template - static bool push(lua_State* L, U&& u, std::error_code& ec) - { - auto* ud = place(L, ec); - - if (!ud) - return false; - - new (ud->getObject()) U(std::move(u)); - - ud->commit(); - - return true; - } - - /** - * @brief Confirm object construction. - */ - void commit() noexcept - { - m_p = getObject(); - } - - T* getObject() noexcept - { - // If this fails to compile it means you forgot to provide - // a Container specialization for your container! - return reinterpret_cast(&m_storage); - } - -private: - /** - * @brief Used for placement construction. - */ - UserdataValue() noexcept - { - m_p = nullptr; - } - - ~UserdataValue() - { - if (getPointer() != nullptr) - { - getObject()->~T(); - } - } - - UserdataValue(const UserdataValue&); - UserdataValue operator=(const UserdataValue&); - - std::aligned_storage_t m_storage; -}; - -//================================================================================================= -/** - * @brief Wraps a pointer to a class object inside a Lua userdata. - * - * The lifetime of the object is managed by C++. - */ -class UserdataPtr : public Userdata -{ -public: - /** - * @brief Push non-const pointer to object. - * - * @tparam T A user registered class. - * - * @param L A Lua state. - * @param p A pointer to the user class instance. - * @param ec Error code that will be set in case of failure to push on the lua stack. - */ - template - static bool push(lua_State* L, T* p, std::error_code& ec) - { - if (p) - return push(L, p, getClassRegistryKey(), ec); - - lua_pushnil(L); - return true; - } - - /** - * @brief Push const pointer to object. - * - * @tparam T A user registered class. - * - * @param L A Lua state. - * @param p A pointer to the user class instance. - * @param ec Error code that will be set in case of failure to push on the lua stack. - */ - template - static bool push(lua_State* L, const T* p, std::error_code& ec) - { - if (p) - return push(L, p, getConstRegistryKey(), ec); - - lua_pushnil(L); - return true; - } - -private: - /** - * @brief Push a pointer to object using metatable key. - */ - static bool push(lua_State* L, const void* p, const void* key, std::error_code& ec) - { - auto* ptr = new (lua_newuserdata(L, sizeof(UserdataPtr))) UserdataPtr(const_cast(p)); - - lua_rawgetp(L, LUA_REGISTRYINDEX, key); - - if (!lua_istable(L, -1)) - { - lua_pop(L, 1); // possibly: a nil - - ptr->~UserdataPtr(); - - ec = throw_or_error_code(L, ErrorCode::ClassNotRegistered); - - return false; - } - - lua_setmetatable(L, -2); - - return true; - } - - explicit UserdataPtr(void* p) - { - // Can't construct with a null pointer! - assert(p != nullptr); - - m_p = p; - } - - UserdataPtr(const UserdataPtr&); - UserdataPtr operator=(const UserdataPtr&); -}; - -//============================================================================ -/** - * @brief Wraps a container that references a class object. - * - * The template argument C is the container type, ContainerTraits must be specialized on C or else a compile error will result. - */ -template -class UserdataShared : public Userdata -{ -public: - ~UserdataShared() = default; - - /** - * @brief Construct from a container to the class or a derived class. - * - * @tparam U A container type. - * - * @param u A container object reference. - */ - template - explicit UserdataShared(const U& u) : m_c(u) - { - m_p = const_cast(reinterpret_cast((ContainerTraits::get(m_c)))); - } - - /** - * @brief Construct from a pointer to the class or a derived class. - * - * @tparam U A container type. - * - * @param u A container object pointer. - */ - template - explicit UserdataShared(U* u) : m_c(u) - { - m_p = const_cast(reinterpret_cast((ContainerTraits::get(m_c)))); - } - -private: - UserdataShared(const UserdataShared&); - UserdataShared& operator=(const UserdataShared&); - - C m_c; -}; - -//================================================================================================= -/** - * @brief SFINAE helper for non-const objects. - */ -template -struct UserdataSharedHelper -{ - using T = std::remove_const_t::Type>; - - static bool push(lua_State* L, const C& c, std::error_code& ec) - { - if (ContainerTraits::get(c) != nullptr) - { - auto* us = new (lua_newuserdata(L, sizeof(UserdataShared))) UserdataShared(c); - - lua_rawgetp(L, LUA_REGISTRYINDEX, getClassRegistryKey()); - - if (!lua_istable(L, -1)) - { - lua_pop(L, 1); // possibly: a nil - - us->~UserdataShared(); - - ec = throw_or_error_code(L, ErrorCode::ClassNotRegistered); - - return false; - } - - lua_setmetatable(L, -2); - } - else - { - lua_pushnil(L); - } - - return true; - } - - static bool push(lua_State* L, T* t, std::error_code& ec) - { - if (t) - { - auto* us = new (lua_newuserdata(L, sizeof(UserdataShared))) UserdataShared(t); - - lua_rawgetp(L, LUA_REGISTRYINDEX, getClassRegistryKey()); - - if (!lua_istable(L, -1)) - { - lua_pop(L, 1); // possibly: a nil - - us->~UserdataShared(); - - ec = throw_or_error_code(L, ErrorCode::ClassNotRegistered); - - return false; - } - - lua_setmetatable(L, -2); - } - else - { - lua_pushnil(L); - } - - return true; - } -}; - -/** - * @brief SFINAE helper for const objects. - */ -template -struct UserdataSharedHelper -{ - using T = std::remove_const_t::Type>; - - static bool push(lua_State* L, const C& c, std::error_code& ec) - { - if (ContainerTraits::get(c) != nullptr) - { - auto* us = new (lua_newuserdata(L, sizeof(UserdataShared))) UserdataShared(c); - - lua_rawgetp(L, LUA_REGISTRYINDEX, getConstRegistryKey()); - - if (!lua_istable(L, -1)) - { - lua_pop(L, 1); // possibly: a nil - - us->~UserdataShared(); - - ec = throw_or_error_code(L, ErrorCode::ClassNotRegistered); - - return false; - } - - lua_setmetatable(L, -2); - } - else - { - lua_pushnil(L); - } - - return true; - } - - static bool push(lua_State* L, T* t, std::error_code& ec) - { - if (t) - { - auto* us = new (lua_newuserdata(L, sizeof(UserdataShared))) UserdataShared(t); - - lua_rawgetp(L, LUA_REGISTRYINDEX, getConstRegistryKey()); - - if (!lua_istable(L, -1)) - { - lua_pop(L, 1); // possibly: a nil - - us->~UserdataShared(); - - ec = throw_or_error_code(L, ErrorCode::ClassNotRegistered); - - return false; - } - - lua_setmetatable(L, -2); - } - else - { - lua_pushnil(L); - } - - return true; - } -}; - -//================================================================================================= -/** - * @brief Pass by container. - * - * The container controls the object lifetime. Typically this will be a lifetime shared by C++ and Lua using a reference count. Because of type - * erasure, containers like std::shared_ptr will not work, unless the type hold by them is derived from std::enable_shared_from_this. - */ -template -struct StackHelper -{ - using ReturnType = std::remove_const_t::Type>; - - static bool push(lua_State* L, const T& t, std::error_code& ec) - { - return UserdataSharedHelper::Type>>::push(L, t, ec); - } - - static T get(lua_State* L, int index) - { - return ContainerTraits::construct(Userdata::get(L, index, true)); - } -}; - -/** - * @brief Pass by value. - * - * Lifetime is managed by Lua. A C++ function which accesses a pointer or reference to an object outside the activation record in which it was - * retrieved may result in undefined behavior if Lua garbage collected it. - */ -template -struct StackHelper -{ - static bool push(lua_State* L, const T& t, std::error_code& ec) - { - return UserdataValue::push(L, t, ec); - } - - static bool push(lua_State* L, T&& t, std::error_code& ec) - { - return UserdataValue::push(L, std::move(t), ec); - } - - static T const& get(lua_State* L, int index) - { - return *Userdata::get(L, index, true); - } -}; - -//================================================================================================= -/** - * @brief Lua stack conversions for pointers and references to class objects. - * - * Lifetime is managed by C++. Lua code which remembers a reference to the value may result in undefined behavior if C++ destroys the object. - * The handling of the const and volatile qualifiers happens in UserdataPtr. - */ -template -struct RefStackHelper -{ - using ReturnType = C; - using T = std::remove_const_t::Type>; - - static inline bool push(lua_State* L, const C& t, std::error_code& ec) - { - return UserdataSharedHelper::Type>>::push(L, t, ec); - } - - static ReturnType get(lua_State* L, int index) - { - return ContainerTraits::construct(Userdata::get(L, index, true)); - } -}; - -template -struct RefStackHelper -{ - using ReturnType = T&; - - static bool push(lua_State* L, const T& t, std::error_code& ec) - { - return UserdataPtr::push(L, &t, ec); - } - - static ReturnType get(lua_State* L, int index) - { - T* t = Userdata::get(L, index, true); - - if (!t) - luaL_error(L, "nil passed to reference"); - - return *t; - } -}; - -//================================================================================================= -/** - * @brief Trait class that selects whether to return a user registered class object by value or by reference. - */ -template -struct UserdataGetter -{ - using ReturnType = T*; - - static ReturnType get(lua_State* L, int index) - { - return Userdata::get(L, index, false); - } -}; - -template -struct UserdataGetter> -{ - using ReturnType = T; - - static ReturnType get(lua_State* L, int index) - { - return StackHelper::value>::get(L, index); - } -}; - -} // namespace detail - -//================================================================================================= -/** - * @brief Lua stack conversions for class objects passed by value. - */ -template -struct Stack -{ - using IsUserdata = void; - - using Getter = detail::UserdataGetter; - using ReturnType = typename Getter::ReturnType; - - static bool push(lua_State* L, const T& value, std::error_code& ec) - { - return detail::StackHelper::value>::push(L, value, ec); - } - - static bool push(lua_State* L, T&& value, std::error_code& ec) - { - return detail::StackHelper::value>::push(L, std::move(value), ec); - } - - static ReturnType get(lua_State* L, int index) - { - return Getter::get(L, index); - } - - static bool isInstance(lua_State* L, int index) - { - return detail::Userdata::isInstance(L, index); - } -}; - -namespace detail { - -//================================================================================================= -/** - * @brief Trait class indicating whether the parameter type must be a user registered class. - * - * The trait checks the existence of member type Stack::IsUserdata specialization for detection. - */ -template -struct IsUserdata : std::false_type -{ -}; - -template -struct IsUserdata::IsUserdata>> : std::true_type -{ -}; - -//================================================================================================= -/** - * @brief Trait class that selects a specific push/get implemenation. - */ -template -struct StackOpSelector; - -// pointer -template -struct StackOpSelector -{ - using ReturnType = T*; - - static bool push(lua_State* L, T* value, std::error_code& ec) { return UserdataPtr::push(L, value, ec); } - - static T* get(lua_State* L, int index) { return Userdata::get(L, index, false); } - - static bool isInstance(lua_State* L, int index) { return Userdata::isInstance(L, index); } -}; - -// pointer to const -template -struct StackOpSelector -{ - using ReturnType = const T*; - - static bool push(lua_State* L, const T* value, std::error_code& ec) { return UserdataPtr::push(L, value, ec); } - - static const T* get(lua_State* L, int index) { return Userdata::get(L, index, true); } - - static bool isInstance(lua_State* L, int index) { return Userdata::isInstance(L, index); } -}; - -// l-value reference -template -struct StackOpSelector -{ - using Helper = RefStackHelper::value>; - using ReturnType = typename Helper::ReturnType; - - static bool push(lua_State* L, T& value, std::error_code& ec) { return UserdataPtr::push(L, &value, ec); } - - static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); } - - static bool isInstance(lua_State* L, int index) { return Userdata::isInstance(L, index); } -}; - -// l-value reference to const -template -struct StackOpSelector -{ - using Helper = RefStackHelper::value>; - using ReturnType = typename Helper::ReturnType; - - static bool push(lua_State* L, const T& value, std::error_code& ec) { return Helper::push(L, value, ec); } - - static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); } - - static bool isInstance(lua_State* L, int index) { return Userdata::isInstance(L, index); } -}; - -} // namespace detail -} // namespace luabridge - -// End File: Source/LuaBridge/detail/Userdata.h - -// Begin File: Source/LuaBridge/detail/Stack.h - -// https://github.com/kunitoki/LuaBridge3 -// Copyright 2020, Lucio Asnaghi -// Copyright 2019, Dmitry Tarakanov -// Copyright 2012, Vinnie Falco -// Copyright 2007, Nathan Reed -// SPDX-License-Identifier: MIT - -namespace luabridge { - -//================================================================================================= -/** - * @brief Lua stack traits for C++ types. - * - * @tparam T A C++ type. - */ -template -struct Stack; - -//================================================================================================= -/** - * @brief Specialization for void type. - */ -template <> -struct Stack -{ - static bool push(lua_State*, std::error_code&) - { - return true; - } -}; - -//================================================================================================= -/** - * @brief Specialization for nullptr_t. - */ -template <> -struct Stack -{ - static bool push(lua_State* L, std::nullptr_t, std::error_code&) - { - lua_pushnil(L); - return true; - } - - static std::nullptr_t get(lua_State*, int) - { - return nullptr; - } - - static bool isInstance(lua_State* L, int index) - { - return lua_isnil(L, index); - } -}; - -//================================================================================================= -/** - * @brief Receive the lua_State* as an argument. - */ -template <> -struct Stack -{ - static lua_State* get(lua_State* L, int) - { - return L; - } -}; - -//================================================================================================= -/** - * @brief Stack specialization for a lua_CFunction. - */ -template <> -struct Stack -{ - static bool push(lua_State* L, lua_CFunction f, std::error_code&) - { - lua_pushcfunction(L, f); - return true; - } - - static lua_CFunction get(lua_State* L, int index) - { - return lua_tocfunction(L, index); - } - - static bool isInstance(lua_State* L, int index) - { - return lua_iscfunction(L, index); - } -}; - -//================================================================================================= -/** - * @brief Stack specialization for `bool`. - */ -template <> -struct Stack -{ - static bool push(lua_State* L, bool value, std::error_code&) - { - lua_pushboolean(L, value ? 1 : 0); - return true; - } - - static bool get(lua_State* L, int index) - { - return lua_toboolean(L, index) ? true : false; - } - - static bool isInstance(lua_State* L, int index) - { - return lua_isboolean(L, index); - } -}; - -//================================================================================================= -/** - * @brief Stack specialization for `std::byte`. - */ -template <> -struct Stack -{ - static bool push(lua_State* L, std::byte value, std::error_code&) - { - pushunsigned(L, std::to_integer(value)); - return true; - } - - static std::byte get(lua_State* L, int index) - { - return static_cast(luaL_checkinteger(L, index)); - } - - static bool isInstance(lua_State* L, int index) - { - return lua_type(L, index) == LUA_TNUMBER; - } -}; - -//================================================================================================= -/** - * @brief Stack specialization for `char`. - */ -template <> -struct Stack -{ - static bool push(lua_State* L, char value, std::error_code&) - { - lua_pushlstring(L, &value, 1); - return true; - } - - static char get(lua_State* L, int index) - { - return luaL_checkstring(L, index)[0]; - } - - static bool isInstance(lua_State* L, int index) - { - return lua_type(L, index) == LUA_TSTRING; - } -}; - -//================================================================================================= -/** - * @brief Stack specialization for `unsigned char`. - */ -template <> -struct Stack -{ - static bool push(lua_State* L, unsigned char value, std::error_code&) - { - pushunsigned(L, value); - return true; - } - - static unsigned char get(lua_State* L, int index) - { - return static_cast(luaL_checkinteger(L, index)); - } - - static bool isInstance(lua_State* L, int index) - { - return lua_type(L, index) == LUA_TNUMBER; - } -}; - -//================================================================================================= -/** - Stack specialization for `short`. -*/ -template <> -struct Stack -{ - static bool push(lua_State* L, short value, std::error_code&) - { - lua_pushinteger(L, static_cast(value)); - return true; - } - - static short get(lua_State* L, int index) - { - return static_cast(luaL_checkinteger(L, index)); - } - - static bool isInstance(lua_State* L, int index) - { - return lua_type(L, index) == LUA_TNUMBER; - } -}; - -//================================================================================================= -/** - * @brief Stack specialization for `unsigned short`. - */ -template <> -struct Stack -{ - static bool push(lua_State* L, unsigned short value, std::error_code&) - { - pushunsigned(L, value); - return true; - } - - static unsigned short get(lua_State* L, int index) - { - return static_cast(luaL_checkinteger(L, index)); - } - - static bool isInstance(lua_State* L, int index) - { - return lua_type(L, index) == LUA_TNUMBER; - } -}; - -//================================================================================================= -/** - * @brief Stack specialization for `int`. - */ -template <> -struct Stack -{ - static bool push(lua_State* L, int value, std::error_code&) - { - lua_pushinteger(L, static_cast(value)); - return true; - } - - static int get(lua_State* L, int index) - { - return static_cast(luaL_checkinteger(L, index)); - } - - static bool isInstance(lua_State* L, int index) - { - return lua_type(L, index) == LUA_TNUMBER; - } -}; - -//================================================================================================= -/** - * @brief Stack specialization for `unsigned int`. - */ -template <> -struct Stack -{ - static bool push(lua_State* L, unsigned int value, std::error_code&) - { - pushunsigned(L, value); - return true; - } - - static unsigned int get(lua_State* L, int index) - { - return static_cast(luaL_checkinteger(L, index)); - } - - static bool isInstance(lua_State* L, int index) - { - return lua_type(L, index) == LUA_TNUMBER; - } -}; - -//================================================================================================= -/** - * @brief Stack specialization for `long`. - */ -template <> -struct Stack -{ - static bool push(lua_State* L, long value, std::error_code&) - { - lua_pushinteger(L, static_cast(value)); - return true; - } - - static long get(lua_State* L, int index) - { - return static_cast(luaL_checkinteger(L, index)); - } - - static bool isInstance(lua_State* L, int index) - { - return lua_type(L, index) == LUA_TNUMBER; - } -}; - -//================================================================================================= -/** - * @brief Stack specialization for `unsigned long`. - */ -template <> -struct Stack -{ - static bool push(lua_State* L, unsigned long value, std::error_code&) - { - pushunsigned(L, value); - return true; - } - - static unsigned long get(lua_State* L, int index) - { - return static_cast(luaL_checkinteger(L, index)); - } - - static bool isInstance(lua_State* L, int index) - { - return lua_type(L, index) == LUA_TNUMBER; - } -}; - -//================================================================================================= -/** - * @brief Stack specialization for `long long`. - */ -template <> -struct Stack -{ - static bool push(lua_State* L, long long value, std::error_code&) - { - lua_pushinteger(L, static_cast(value)); - return true; - } - - static long long get(lua_State* L, int index) - { - return static_cast(luaL_checkinteger(L, index)); - } - - static bool isInstance(lua_State* L, int index) - { - return lua_type(L, index) == LUA_TNUMBER; - } -}; - -//================================================================================================= -/** - * @brief Stack specialization for `unsigned long long`. - */ -template <> -struct Stack -{ - static bool push(lua_State* L, unsigned long long value, std::error_code&) - { - pushunsigned(L, value); - return true; - } - - static unsigned long long get(lua_State* L, int index) - { - return static_cast(luaL_checkinteger(L, index)); - } - - static bool isInstance(lua_State* L, int index) - { - return lua_type(L, index) == LUA_TNUMBER; - } -}; - -//================================================================================================= -/** - * @brief Stack specialization for `float`. - */ -template <> -struct Stack -{ - static bool push(lua_State* L, float value, std::error_code&) - { - lua_pushnumber(L, static_cast(value)); - return true; - } - - static float get(lua_State* L, int index) - { - return static_cast(luaL_checknumber(L, index)); - } - - static bool isInstance(lua_State* L, int index) - { - return lua_type(L, index) == LUA_TNUMBER; - } -}; - -//================================================================================================= -/** - * @brief Stack specialization for `double`. - */ -template <> -struct Stack -{ - static bool push(lua_State* L, double value, std::error_code&) - { - lua_pushnumber(L, static_cast(value)); - return true; - } - - static double get(lua_State* L, int index) - { - return static_cast(luaL_checknumber(L, index)); - } - - static bool isInstance(lua_State* L, int index) - { - return lua_type(L, index) == LUA_TNUMBER; - } -}; - -//================================================================================================= -/** - * @brief Stack specialization for `long double`. - */ -template <> -struct Stack -{ - static bool push(lua_State* L, long double value, std::error_code&) - { - lua_pushnumber(L, static_cast(value)); - return true; - } - - static long double get(lua_State* L, int index) - { - return static_cast(luaL_checknumber(L, index)); - } - - static bool isInstance(lua_State* L, int index) - { - return lua_type(L, index) == LUA_TNUMBER; - } -}; - -//================================================================================================= -/** - * @brief Stack specialization for `const char*`. - */ -template <> -struct Stack -{ - static bool push(lua_State* L, const char* str, std::error_code&) - { - if (str != nullptr) - lua_pushstring(L, str); - else - lua_pushnil(L); - - return true; - } - - static const char* get(lua_State* L, int index) - { - return lua_isnil(L, index) ? nullptr : luaL_checkstring(L, index); - } - - static bool isInstance(lua_State* L, int index) - { - return lua_isnil(L, index) || lua_type(L, index) == LUA_TSTRING; - } -}; - -//================================================================================================= -/** - * @brief Stack specialization for `const char[N]` literals. - */ -namespace detail { -template -struct IsStringLiteral : std::is_same>]>> -{ -}; -} // namespace detail - -template -struct Stack::value>> -{ - static bool push(lua_State* L, const char (&str)[std::extent_v>], std::error_code&) - { - lua_pushlstring(L, str, std::extent_v>); - return true; - } -}; - -//================================================================================================= -/** - * @brief Stack specialization for `std::string_view`. - */ -template <> -struct Stack -{ - static bool push(lua_State* L, std::string_view str, std::error_code&) - { - lua_pushlstring(L, str.data(), str.size()); - return true; - } - - static std::string_view get(lua_State* L, int index) - { - return lua_isnil(L, index) ? std::string_view() : luaL_checkstring(L, index); - } - - static bool isInstance(lua_State* L, int index) - { - return lua_isnil(L, index) || lua_type(L, index) == LUA_TSTRING; - } -}; - -//================================================================================================= -/** - * @brief Stack specialization for `std::string`. - */ -template <> -struct Stack -{ - static bool push(lua_State* L, const std::string& str, std::error_code&) - { - lua_pushlstring(L, str.data(), str.size()); - return true; - } - - static std::string get(lua_State* L, int index) - { - std::size_t len; - if (lua_type(L, index) == LUA_TSTRING) - { - const char* str = lua_tolstring(L, index, &len); - return std::string(str, len); - } - - // Lua reference manual: - // If the value is a number, then lua_tolstring also changes the actual value in the stack - // to a string. (This change confuses lua_next when lua_tolstring is applied to keys during - // a table traversal.) - lua_pushvalue(L, index); - const char* str = lua_tolstring(L, -1, &len); - std::string string(str, len); - lua_pop(L, 1); // Pop the temporary string - return string; - } - - static bool isInstance(lua_State* L, int index) - { - return lua_type(L, index) == LUA_TSTRING; - } -}; - -//================================================================================================= -/** - * @brief Stack specialization for `std::tuple`. - */ -template -struct Stack> -{ - static bool push(lua_State* L, const std::tuple& t, std::error_code& ec) - { - lua_createtable(L, static_cast(Size), 0); - - return push_element(L, t, ec); - } - - static std::tuple get(lua_State* L, int index) - { - if (!lua_istable(L, index)) - luaL_error(L, "#%d argment must be a table", index); - - if (get_length(L, index) != Size) - luaL_error(L, "table size should be %d but is %d", Size, get_length(L, index)); - - std::tuple value; - - int absIndex = lua_absindex(L, index); - lua_pushnil(L); - - pop_element(L, absIndex, value); - - return value; - } - - static bool isInstance(lua_State* L, int index) - { - return lua_type(L, index) == LUA_TTABLE; - } - -private: - static constexpr std::size_t Size = std::tuple_size_v>; - - template - static auto push_element(lua_State*, const std::tuple&, std::error_code&) - -> std::enable_if_t - { - return true; - } - - template - static auto push_element(lua_State* L, const std::tuple& t, std::error_code& ec) - -> std::enable_if_t - { - using T = std::tuple_element_t>; - - lua_pushinteger(L, static_cast(Index + 1)); - - std::error_code push_ec; - bool result = Stack::push(L, std::get(t), push_ec); - if (! result) - { - lua_pushnil(L); - lua_settable(L, -3); - ec = push_ec; - return false; - } - - lua_settable(L, -3); - - return push_element(L, t, ec); - } - - template - static auto pop_element(lua_State*, int, std::tuple&) - -> std::enable_if_t - { - } - - template - static auto pop_element(lua_State* L, int absIndex, std::tuple& t) - -> std::enable_if_t - { - using T = std::tuple_element_t>; - - if (lua_next(L, absIndex) == 0) - return; - - std::get(t) = Stack::get(L, -1); - lua_pop(L, 1); - - pop_element(L, absIndex, t); - } -}; - -namespace detail { - -template -struct StackOpSelector -{ - using ReturnType = T; - - static bool push(lua_State* L, T& value, std::error_code& ec) { return Stack::push(L, value, ec); } - - static ReturnType get(lua_State* L, int index) { return Stack::get(L, index); } - - static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } -}; - -template -struct StackOpSelector -{ - using ReturnType = T; - - static bool push(lua_State* L, const T& value, std::error_code& ec) { return Stack::push(L, value, ec); } - - static ReturnType get(lua_State* L, int index) { return Stack::get(L, index); } - - static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } -}; - -template -struct StackOpSelector -{ - using ReturnType = T; - - static bool push(lua_State* L, T* value, std::error_code& ec) { return Stack::push(L, *value, ec); } - - static ReturnType get(lua_State* L, int index) { return Stack::get(L, index); } - - static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } -}; - -template -struct StackOpSelector -{ - using ReturnType = T; - - static bool push(lua_State* L, const T* value, std::error_code& ec) { return Stack::push(L, *value, ec); } - - static ReturnType get(lua_State* L, int index) { return Stack::get(L, index); } - - static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } -}; - -} // namespace detail - -template -struct Stack::value>> -{ - using Helper = detail::StackOpSelector::value>; - using ReturnType = typename Helper::ReturnType; - - static bool push(lua_State* L, T& value, std::error_code& ec) { return Helper::push(L, value, ec); } - - static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); } - - static bool isInstance(lua_State* L, int index) { return Helper::template isInstance(L, index); } -}; - -template -struct Stack::value>> -{ - using Helper = detail::StackOpSelector::value>; - using ReturnType = typename Helper::ReturnType; - - static bool push(lua_State* L, const T& value, std::error_code& ec) { return Helper::push(L, value, ec); } - - static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); } - - static bool isInstance(lua_State* L, int index) { return Helper::template isInstance(L, index); } -}; - -template -struct Stack -{ - using Helper = detail::StackOpSelector::value>; - using ReturnType = typename Helper::ReturnType; - - static bool push(lua_State* L, T* value, std::error_code& ec) { return Helper::push(L, value, ec); } - - static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); } - - static bool isInstance(lua_State* L, int index) { return Helper::template isInstance(L, index); } -}; - -template -struct Stack -{ - using Helper = detail::StackOpSelector::value>; - using ReturnType = typename Helper::ReturnType; - - static bool push(lua_State* L, const T* value, std::error_code& ec) { return Helper::push(L, value, ec); } - - static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); } - - static bool isInstance(lua_State* L, int index) { return Helper::template isInstance(L, index); } -}; - -//------------------------------------------------------------------------------ -/** - * @brief Push an object onto the Lua stack. - */ -template -bool push(lua_State* L, T t, std::error_code& ec) -{ - return Stack::push(L, t, ec); -} - -//------------------------------------------------------------------------------ -/** - * @brief Check whether an object on the Lua stack is of type T. - */ -template -bool isInstance(lua_State* L, int index) -{ - return Stack::isInstance(L, index); -} - -} // namespace luabridge - -// End File: Source/LuaBridge/detail/Stack.h - -// Begin File: Source/LuaBridge/Map.h - -// https://github.com/kunitoki/LuaBridge3 -// Copyright 2020, Lucio Asnaghi -// Copyright 2018, Dmitry Tarakanov -// SPDX-License-Identifier: MIT - -namespace luabridge { - -//================================================================================================= -/** - * @brief Stack specialization for `std::map`. - */ -template -struct Stack> -{ - using Type = std::map; - - static bool push(lua_State* L, const Type& map, std::error_code& ec) - { - const int initialStackSize = lua_gettop(L); - - lua_createtable(L, 0, static_cast(map.size())); - - for (auto it = map.begin(); it != map.end(); ++it) - { - std::error_code errorCodeKey; - if (! Stack::push(L, it->first, errorCodeKey)) - { - ec = errorCodeKey; - lua_pop(L, lua_gettop(L) - initialStackSize); - return false; - } - - std::error_code errorCodeValue; - if (! Stack::push(L, it->second, errorCodeValue)) - { - ec = errorCodeValue; - lua_pop(L, lua_gettop(L) - initialStackSize); - return false; - } - - lua_settable(L, -3); - } - - return true; - } - - static Type get(lua_State* L, int index) - { - if (!lua_istable(L, index)) - luaL_error(L, "#%d argument must be a table", index); - - Type map; - - int absIndex = lua_absindex(L, index); - lua_pushnil(L); - - while (lua_next(L, absIndex) != 0) - { - map.emplace(Stack::get(L, -2), Stack::get(L, -1)); - lua_pop(L, 1); - } - - return map; - } - - static bool isInstance(lua_State* L, int index) - { - return lua_istable(L, index); - } -}; - -} // namespace luabridge - -// End File: Source/LuaBridge/Map.h - -// Begin File: Source/LuaBridge/UnorderedMap.h - -// https://github.com/kunitoki/LuaBridge3 -// Copyright 2020, Lucio Asnaghi -// Copyright 2019, Dmitry Tarakanov -// SPDX-License-Identifier: MIT - -namespace luabridge { - -//================================================================================================= -/** - * @brief Stack specialization for `std::unordered_map`. - */ -template -struct Stack> -{ - using Type = std::unordered_map; - - static bool push(lua_State* L, const Type& map, std::error_code& ec) - { - const int initialStackSize = lua_gettop(L); - - lua_createtable(L, 0, static_cast(map.size())); - - for (auto it = map.begin(); it != map.end(); ++it) - { - std::error_code errorCodeKey; - if (! Stack::push(L, it->first, errorCodeKey)) - { - ec = errorCodeKey; - lua_pop(L, lua_gettop(L) - initialStackSize); - return false; - } - - std::error_code errorCodeValue; - if (! Stack::push(L, it->second, errorCodeValue)) - { - ec = errorCodeValue; - lua_pop(L, lua_gettop(L) - initialStackSize); - return false; - } - - lua_settable(L, -3); - } - - return true; - } - - static Type get(lua_State* L, int index) - { - if (!lua_istable(L, index)) - luaL_error(L, "#%d argument must be a table", index); - - Type map; - - int absIndex = lua_absindex(L, index); - lua_pushnil(L); - - while (lua_next(L, absIndex) != 0) - { - map.emplace(Stack::get(L, -2), Stack::get(L, -1)); - lua_pop(L, 1); - } - - return map; - } - - static bool isInstance(lua_State* L, int index) - { - return lua_istable(L, index); - } -}; - -} // namespace luabridge - -// End File: Source/LuaBridge/UnorderedMap.h - -// Begin File: Source/LuaBridge/Optional.h - -// https://github.com/kunitoki/LuaBridge3 -// Copyright 2020, Lucio Asnaghi -// SPDX-License-Identifier: MIT - -namespace luabridge { - -//================================================================================================= -/** - * @brief Stack specialization for `std::optional`. - */ -template -struct Stack> -{ - using Type = std::optional; - - static bool push(lua_State* L, const Type& value, std::error_code& ec) - { - if (value) - return Stack::push(L, *value, ec); - - lua_pushnil(L); - return true; - } - - static Type get(lua_State* L, int index) - { - if (lua_type(L, index) == LUA_TNIL) - return std::nullopt; - - return Stack::get(L, index); - } - - static bool isInstance(lua_State* L, int index) - { - return lua_isnil(L, index) || Stack::isInstance(L, index); - } -}; - -} // namespace luabridge - -// End File: Source/LuaBridge/Optional.h - -// Begin File: Source/LuaBridge/detail/FuncTraits.h - -// https://github.com/kunitoki/LuaBridge3 -// Copyright 2020, Lucio Asnaghi -// Copyright 2020, Dmitry Tarakanov -// Copyright 2019, George Tokmaji -// Copyright 2012, Vinnie Falco -// SPDX-License-Identifier: MIT - -namespace luabridge { -namespace detail { - -//================================================================================================= -/** - * @brief Generic function traits. - * - * @tparam IsMember True if the function is a member function pointer. - * @tparam IsConst True if the function is const. - * @tparam R Return type of the function. - * @tparam Args Arguments types as variadic parameter pack. - */ -template -struct function_traits_base -{ - using result_type = R; - - using argument_types = std::tuple; - - static constexpr auto arity = sizeof...(Args); - - static constexpr auto is_member = IsMember; - - static constexpr auto is_const = IsConst; -}; - -template -struct function_traits_impl; - -template -struct function_traits_impl : function_traits_base -{ -}; - -template -struct function_traits_impl : function_traits_base -{ -}; - -template -struct function_traits_impl : function_traits_base -{ -}; - -template -struct function_traits_impl : function_traits_base -{ -}; - -template -struct function_traits_impl : function_traits_base -{ -}; - -template -struct function_traits_impl : function_traits_base -{ -}; - -template -struct function_traits_impl : function_traits_base -{ -}; - -template -struct function_traits_impl : function_traits_base -{ -}; - -#if _MSC_VER && _M_IX86 // Windows: WINAPI (a.k.a. __stdcall) function pointers (32bit only). -template -struct function_traits_impl : function_traits_base -{ -}; - -template -struct function_traits_impl : function_traits_base -{ -}; - -template -struct function_traits_impl : function_traits_base -{ -}; - -template -struct function_traits_impl : function_traits_base -{ -}; - -template -struct function_traits_impl : function_traits_base -{ -}; - -template -struct function_traits_impl : function_traits_base -{ -}; - -template -struct function_traits_impl : function_traits_base -{ -}; - -template -struct function_traits_impl : function_traits_base -{ -}; -#endif - -template -struct functor_traits_impl : function_traits_impl -{ -}; - -//================================================================================================= -/** - * @brief Traits class for callable objects (e.g. function pointers, lambdas) - * - * @tparam F Callable object. - */ -template -struct function_traits : std::conditional_t, - detail::functor_traits_impl, - detail::function_traits_impl> -{ -}; - -//================================================================================================= -/** - * @brief Deduces the return type of a callble object. - * - * @tparam F Callable object. - */ -template -using function_result_t = typename function_traits::result_type; - -/** - * @brief Deduces the argument type of a callble object. - * - * @tparam I Argument index. - * @tparam F Callable object. - */ -template -using function_argument_t = std::tuple_element_t::argument_types>; - -/** - * @brief Deduces the arguments type of a callble object. - * - * @tparam F Callable object. - */ -template -using function_arguments_t = typename function_traits::argument_types; - -/** - * @brief An integral constant expression that gives the number of arguments accepted by the callable object. - * - * @tparam F Callable object. - */ -template -static constexpr std::size_t function_arity_v = function_traits::arity; - -/** - * @brief An boolean constant expression that checks if the callable object is a member function. - * - * @tparam F Callable object. - */ -template -static constexpr bool function_is_member_v = function_traits::is_member; - -/** - * @brief An boolean constant expression that checks if the callable object is const. - * - * @tparam F Callable object. - */ -template -static constexpr bool function_is_const_v = function_traits::is_const; - -//================================================================================================= -/** - * @brief Detect if we are a `std::function`. - * - * @tparam F Callable object. - */ -template -struct is_std_function : std::false_type -{ -}; - -template -struct is_std_function> : std::true_type -{ -}; - -template -struct is_std_function> : std::true_type -{ -}; - -template -static constexpr bool is_std_function_v = is_std_function::value; - -//================================================================================================= -/** - * @brief Reconstruct a function signature from return type and args. - */ -template -struct to_std_function_type -{ -}; - -template -struct to_std_function_type> -{ - using type = std::function; -}; - -template -using to_std_function_type_t = typename to_std_function_type::type; - -//================================================================================================= -/** - * @brief Simple make_tuple alternative that doesn't decay the types. - * - * @tparam Types Argument types that will compose the tuple. - */ -template -constexpr auto tupleize(Types&&... types) -{ - return std::tuple(std::forward(types)...); -} - -//================================================================================================= -/** - * @brief Make argument lists extracting them from the lua state, starting at a stack index. - * - * @tparam ArgsPack Arguments pack to extract from the lua stack. - * @tparam Start Start index where stack variables are located in the lua stack. - */ -template -auto make_arguments_list_impl(lua_State* L, std::index_sequence) -{ - return tupleize(Stack>::get(L, Start + Indices)...); -} - -template -auto make_arguments_list(lua_State* L) -{ - return make_arguments_list_impl(L, std::make_index_sequence>()); -} - -//================================================================================================= -/** - * @brief Helpers for iterating through tuple arguments, pushing each argument to the lua stack. - */ -template -auto push_arguments(lua_State*, std::tuple, std::error_code&) - -> std::enable_if_t -{ - return Index + 1; -} - -template -auto push_arguments(lua_State* L, std::tuple t, std::error_code& ec) - -> std::enable_if_t -{ - using T = std::tuple_element_t>; - - std::error_code pec; - bool result = Stack::push(L, std::get(t), pec); - if (! result) - { - ec = pec; - return Index + 1; - } - - return push_arguments(L, std::move(t), ec); -} - -//================================================================================================= -/** - * @brief Helpers for iterating through tuple arguments, popping each argument from the lua stack. - */ -template -auto pop_arguments(lua_State*, std::tuple&) - -> std::enable_if_t -{ - return sizeof...(Types); -} - -template -auto pop_arguments(lua_State* L, std::tuple& t) - -> std::enable_if_t -{ - using T = std::tuple_element_t>; - - std::get(t) = Stack::get(L, Start - Index); - - return pop_arguments(L, t); -} - -//================================================================================================= -/** - * @brief Remove first type from tuple. - */ -template -struct remove_first_type -{ -}; - -template -struct remove_first_type> -{ - using type = std::tuple; -}; - -template -using remove_first_type_t = typename remove_first_type::type; - -//================================================================================================= -/** - * @brief Function generator. - */ -template -struct function -{ - template - static int call(lua_State* L, F func) - { -#if LUABRIDGE_HAS_EXCEPTIONS - try - { -#endif - std::error_code ec; - bool result = Stack::push(L, std::apply(func, make_arguments_list(L)), ec); - if (! result) - return luaL_error(L, ec.message().c_str()); - - return 1; - -#if LUABRIDGE_HAS_EXCEPTIONS - } - catch (const std::exception& e) - { - return luaL_error(L, e.what()); - } - catch (...) - { - return luaL_error(L, "Error while calling function"); - } -#endif - } - - template - static int call(lua_State* L, T* ptr, F func) - { -#if LUABRIDGE_HAS_EXCEPTIONS - try - { -#endif - auto f = [ptr, func](auto&&... args) -> ReturnType { return (ptr->*func)(std::forward(args)...); }; - - std::error_code ec; - bool result = Stack::push(L, std::apply(f, make_arguments_list(L)), ec); - if (! result) - return luaL_error(L, ec.message().c_str()); - - return 1; - -#if LUABRIDGE_HAS_EXCEPTIONS - } - catch (const std::exception& e) - { - return luaL_error(L, e.what()); - } - catch (...) - { - return luaL_error(L, "Error while calling method"); - } -#endif - } -}; - -template -struct function -{ - template - static int call(lua_State* L, F func) - { -#if LUABRIDGE_HAS_EXCEPTIONS - try - { -#endif - std::apply(func, make_arguments_list(L)); - - return 0; - -#if LUABRIDGE_HAS_EXCEPTIONS - } - catch (const std::exception& e) - { - return luaL_error(L, e.what()); - } - catch (...) - { - return luaL_error(L, "Error while calling function"); - } -#endif - } - - template - static int call(lua_State* L, T* ptr, F func) - { -#if LUABRIDGE_HAS_EXCEPTIONS - try - { -#endif - auto f = [ptr, func](auto&&... args) { (ptr->*func)(std::forward(args)...); }; - - std::apply(f, make_arguments_list(L)); - - return 0; - -#if LUABRIDGE_HAS_EXCEPTIONS - } - catch (const std::exception& e) - { - return luaL_error(L, e.what()); - } - catch (...) - { - return luaL_error(L, "Error while calling method"); - } -#endif - } -}; - -//================================================================================================= -/** - * @brief Constructor generators. - * - * These templates call operator new with the contents of a type/value list passed to the constructor. Two versions of call() are provided. - * One performs a regular new, the other performs a placement new. - */ -template -struct constructor; - -template -struct constructor -{ - using empty = std::tuple<>; - - static T* call(const empty&) - { - return new T; - } - - static T* call(void* ptr, const empty&) - { - return new (ptr) T; - } -}; - -template -struct constructor -{ - static T* call(const Args& args) - { - auto alloc = [](auto&&... args) { return new T{ std::forward(args)... }; }; - - return std::apply(alloc, args); - } - - static T* call(void* ptr, const Args& args) - { - auto alloc = [ptr](auto&&... args) { return new (ptr) T{ std::forward(args)... }; }; - - return std::apply(alloc, args); - } -}; - -//================================================================================================= -/** - * @brief Factory generators. - */ -template -struct factory -{ - template - static T* call(void* ptr, const F& func, const Args& args) - { - auto alloc = [ptr, &func](auto&&... args) { return func(ptr, std::forward(args)...); }; - - return std::apply(alloc, args); - } - - template - static T* call(void* ptr, const F& func) - { - return func(ptr); - } -}; - -} // namespace detail -} // namespace luabridge - -// End File: Source/LuaBridge/detail/FuncTraits.h - -// Begin File: Source/LuaBridge/detail/CFunctions.h - -// https://github.com/kunitoki/LuaBridge3 -// Copyright 2020, Lucio Asnaghi -// Copyright 2019, Dmitry Tarakanov -// Copyright 2012, Vinnie Falco -// SPDX-License-Identifier: MIT - -namespace luabridge { -namespace detail { - -//================================================================================================= -/** - * @brief __index metamethod for a namespace or class static and non-static members. - * - * Retrieves functions from metatables and properties from propget tables. Looks through the class hierarchy if inheritance is present. - */ -inline int index_metamethod(lua_State* L) -{ - assert(lua_istable(L, 1) || lua_isuserdata(L, 1)); // Stack (further not shown): table | userdata, name - - lua_getmetatable(L, 1); // Stack: class/const table (mt) - assert(lua_istable(L, -1)); - - for (;;) - { - lua_pushvalue(L, 2); // Stack: mt, field name - lua_rawget(L, -2); // Stack: mt, field | nil - - if (lua_iscfunction(L, -1)) // Stack: mt, field - { - lua_remove(L, -2); // Stack: field - return 1; - } - - assert(lua_isnil(L, -1)); // Stack: mt, nil - lua_pop(L, 1); // Stack: mt - - lua_rawgetp(L, -1, getPropgetKey()); // Stack: mt, propget table (pg) - assert(lua_istable(L, -1)); - - lua_pushvalue(L, 2); // Stack: mt, pg, field name - lua_rawget(L, -2); // Stack: mt, pg, getter | nil - lua_remove(L, -2); // Stack: mt, getter | nil - - if (lua_iscfunction(L, -1)) // Stack: mt, getter - { - lua_remove(L, -2); // Stack: getter - lua_pushvalue(L, 1); // Stack: getter, table | userdata - lua_call(L, 1, 1); // Stack: value - return 1; - } - - assert(lua_isnil(L, -1)); // Stack: mt, nil - lua_pop(L, 1); // Stack: mt - - // It may mean that the field may be in const table and it's constness violation. - // Don't check that, just return nil - - // Repeat the lookup in the parent metafield, - // or return nil if the field doesn't exist. - lua_rawgetp(L, -1, getParentKey()); // Stack: mt, parent mt | nil - - if (lua_isnil(L, -1)) // Stack: mt, nil - { - lua_remove(L, -2); // Stack: nil - return 1; - } - - // Removethe metatable and repeat the search in the parent one. - assert(lua_istable(L, -1)); // Stack: mt, parent mt - lua_remove(L, -2); // Stack: parent mt - } - - // no return -} - -//================================================================================================= -/** - * @brief __newindex metamethod for non-static members. - * - * Retrieves properties from propset tables. - */ -inline int newindex_metamethod(lua_State* L, bool pushSelf) -{ - assert(lua_istable(L, 1) || lua_isuserdata(L, 1)); // Stack (further not shown): table | userdata, name, new value - - lua_getmetatable(L, 1); // Stack: metatable (mt) - assert(lua_istable(L, -1)); - - for (;;) - { - lua_rawgetp(L, -1, getPropsetKey()); // Stack: mt, propset table (ps) | nil - - if (lua_isnil(L, -1)) // Stack: mt, nil - { - lua_pop(L, 2); // Stack: - - return luaL_error(L, "No member named '%s'", lua_tostring(L, 2)); - } - - assert(lua_istable(L, -1)); - - lua_pushvalue(L, 2); // Stack: mt, ps, field name - lua_rawget(L, -2); // Stack: mt, ps, setter | nil - lua_remove(L, -2); // Stack: mt, setter | nil - - if (lua_iscfunction(L, -1)) // Stack: mt, setter - { - lua_remove(L, -2); // Stack: setter - if (pushSelf) - lua_pushvalue(L, 1); // Stack: setter, table | userdata - lua_pushvalue(L, 3); // Stack: setter, table | userdata, new value - lua_call(L, pushSelf ? 2 : 1, 0); // Stack: - - return 0; - } - - assert(lua_isnil(L, -1)); // Stack: mt, nil - lua_pop(L, 1); // Stack: mt - - lua_rawgetp(L, -1, getParentKey()); // Stack: mt, parent mt | nil - - if (lua_isnil(L, -1)) // Stack: mt, nil - { - lua_pop(L, 1); // Stack: - - return luaL_error(L, "No writable member '%s'", lua_tostring(L, 2)); - } - - assert(lua_istable(L, -1)); // Stack: mt, parent mt - lua_remove(L, -2); // Stack: parent mt - // Repeat the search in the parent - } - - // no return -} - -//================================================================================================= -/** - * @brief __newindex metamethod for objects. - */ -inline int newindex_object_metamethod(lua_State* L) -{ - return newindex_metamethod(L, true); -} - -//================================================================================================= -/** - * @brief __newindex metamethod for namespace or class static members. - * - * Retrieves properties from propset tables. - */ -inline int newindex_static_metamethod(lua_State* L) -{ - return newindex_metamethod(L, false); -} - -//================================================================================================= -/** - * @brief lua_CFunction to report an error writing to a read-only value. - * - * The name of the variable is in the first upvalue. - */ -inline int read_only_error(lua_State* L) -{ - std::string s; - - s = s + "'" + lua_tostring(L, lua_upvalueindex(1)) + "' is read-only"; - - return luaL_error(L, s.c_str()); -} - -//================================================================================================= -/** - * @brief __gc metamethod for a class. - */ -template -static int gc_metamethod(lua_State* L) -{ - Userdata* ud = Userdata::getExact(L, 1); - assert(ud); - - ud->~Userdata(); - - return 0; -} - -//================================================================================================= - -template -struct property_getter; - -/** - * @brief lua_CFunction to get a variable. - * - * This is used for global variables or class static data members. The pointer to the data is in the first upvalue. - */ -template -struct property_getter -{ - static int call(lua_State* L) - { - assert(lua_islightuserdata(L, lua_upvalueindex(1))); - - T* ptr = static_cast(lua_touserdata(L, lua_upvalueindex(1))); - assert(ptr != nullptr); - - std::error_code ec; - if (! Stack::push(L, *ptr, ec)) - luaL_error(L, ec.message().c_str()); - - return 1; - } -}; - -#if 0 -template -struct property_getter, void> -{ - static int call(lua_State* L) - { - assert(lua_islightuserdata(L, lua_upvalueindex(1))); - - std::reference_wrapper* ptr = static_cast*>(lua_touserdata(L, lua_upvalueindex(1))); - assert(ptr != nullptr); - - std::error_code ec; - if (! Stack::push(L, ptr->get(), ec)) - luaL_error(L, ec.message().c_str()); - - return 1; - } -}; -#endif - -/** - * @brief lua_CFunction to get a class data member. - * - * The pointer-to-member is in the first upvalue. The class userdata object is at the top of the Lua stack. - */ -template -struct property_getter -{ - static int call(lua_State* L) - { - C* c = Userdata::get(L, 1, true); - - T C::** mp = static_cast(lua_touserdata(L, lua_upvalueindex(1))); - -#if LUABRIDGE_HAS_EXCEPTIONS - try - { -#endif - std::error_code ec; - if (! Stack::push(L, c->**mp, ec)) - luaL_error(L, ec.message().c_str()); - -#if LUABRIDGE_HAS_EXCEPTIONS - } - catch (const std::exception& e) - { - luaL_error(L, e.what()); - } - catch (...) - { - luaL_error(L, "Error while getting property"); - } -#endif - - return 1; - } -}; - -/** - * @brief Helper function to push a property getter on a table at a specific index. - */ -inline void add_property_getter(lua_State* L, const char* name, int tableIndex) -{ - assert(name != nullptr); - assert(lua_istable(L, tableIndex)); - assert(lua_iscfunction(L, -1)); // Stack: getter - - lua_rawgetp(L, tableIndex, getPropgetKey()); // Stack: getter, propget table (pg) - lua_pushvalue(L, -2); // Stack: getter, pg, getter - rawsetfield(L, -2, name); // Stack: getter, pg - lua_pop(L, 2); // Stack: - -} - -//================================================================================================= - -template -struct property_setter; - -/** - * @brief lua_CFunction to set a variable. - * - * This is used for global variables or class static data members. The pointer to the data is in the first upvalue. - */ -template -struct property_setter -{ - static int call(lua_State* L) - { - assert(lua_islightuserdata(L, lua_upvalueindex(1))); - - T* ptr = static_cast(lua_touserdata(L, lua_upvalueindex(1))); - assert(ptr != nullptr); - - *ptr = Stack::get(L, 1); - - return 0; - } -}; - -#if 0 -template -struct property_setter, void> -{ - static int call(lua_State* L) - { - assert(lua_islightuserdata(L, lua_upvalueindex(1))); - - std::reference_wrapper* ptr = static_cast*>(lua_touserdata(L, lua_upvalueindex(1))); - assert(ptr != nullptr); - - ptr->get() = Stack::get(L, 1); - - return 0; - } -}; -#endif - -/** - * @brief lua_CFunction to set a class data member. - * - * The pointer-to-member is in the first upvalue. The class userdata object is at the top of the Lua stack. - */ -template -struct property_setter -{ - static int call(lua_State* L) - { - C* c = Userdata::get(L, 1, false); - - T C::** mp = static_cast(lua_touserdata(L, lua_upvalueindex(1))); - -#if LUABRIDGE_HAS_EXCEPTIONS - try - { -#endif - c->** mp = Stack::get(L, 2); - -#if LUABRIDGE_HAS_EXCEPTIONS - } - catch (const std::exception& e) - { - luaL_error(L, e.what()); - } - catch (...) - { - luaL_error(L, "Error while setting property"); - } -#endif - - return 0; - } -}; - -/** - * @brief Helper function to push a property setter on a table at a specific index. - */ -inline void add_property_setter(lua_State* L, const char* name, int tableIndex) -{ - assert(name != nullptr); - assert(lua_istable(L, tableIndex)); - assert(lua_iscfunction(L, -1)); // Stack: setter - - lua_rawgetp(L, tableIndex, getPropsetKey()); // Stack: setter, propset table (ps) - lua_pushvalue(L, -2); // Stack: setter, ps, setter - rawsetfield(L, -2, name); // Stack: setter, ps - lua_pop(L, 2); // Stack: - -} - -//================================================================================================= -/** - * @brief lua_CFunction to call a class member function with a return value. - * - * The member function pointer is in the first upvalue. The class userdata object is at the top of the Lua stack. - */ -template -int invoke_member_function(lua_State* L) -{ - using FnTraits = detail::function_traits; - - assert(isfulluserdata(L, lua_upvalueindex(1))); - - T* ptr = Userdata::get(L, 1, false); - - const F& func = *static_cast(lua_touserdata(L, lua_upvalueindex(1))); - assert(func != nullptr); - - return function::call(L, ptr, func); -} - -template -int invoke_const_member_function(lua_State* L) -{ - using FnTraits = detail::function_traits; - - assert(isfulluserdata(L, lua_upvalueindex(1))); - - const T* ptr = Userdata::get(L, 1, true); - - const F& func = *static_cast(lua_touserdata(L, lua_upvalueindex(1))); - assert(func != nullptr); - - return function::call(L, ptr, func); -} - -//================================================================================================= -/** - * @brief lua_CFunction to call a class member lua_CFunction. - * - * The member function pointer is in the first upvalue. The object userdata ('this') value is at top ot the Lua stack. - */ -template -int invoke_member_cfunction(lua_State* L) -{ - using F = int (T::*)(lua_State * L); - - assert(isfulluserdata(L, lua_upvalueindex(1))); - - T* t = Userdata::get(L, 1, false); - - const F& func = *static_cast(lua_touserdata(L, lua_upvalueindex(1))); - assert(func != nullptr); - - return (t->*func)(L); -} - -template -int invoke_const_member_cfunction(lua_State* L) -{ - using F = int (T::*)(lua_State * L) const; - - assert(isfulluserdata(L, lua_upvalueindex(1))); - - const T* t = Userdata::get(L, 1, true); - - const F& func = *static_cast(lua_touserdata(L, lua_upvalueindex(1))); - assert(func != nullptr); - - return (t->*func)(L); -} - -//================================================================================================= -/** - * @brief lua_CFunction to call on a object via function pointer. - * - * The proxy function pointer (lightuserdata) is in the first upvalue. The class userdata object is at the top of the Lua stack. - */ -template -int invoke_proxy_function(lua_State* L) -{ - using FnTraits = detail::function_traits; - - assert(lua_islightuserdata(L, lua_upvalueindex(1))); - - auto func = reinterpret_cast(lua_touserdata(L, lua_upvalueindex(1))); - assert(func != nullptr); - - return function::call(L, func); -} - -//================================================================================================= -/** - * @brief lua_CFunction to call on a object via functor (lambda wrapped in a std::function). - * - * The proxy std::function (lightuserdata) is in the first upvalue. The class userdata object is at the top of the Lua stack. - */ -template -int invoke_proxy_functor(lua_State* L) -{ - using FnTraits = detail::function_traits; - - assert(isfulluserdata(L, lua_upvalueindex(1))); - - auto& func = *align(lua_touserdata(L, lua_upvalueindex(1))); - - return function::call(L, func); -} - -} // namespace detail -} // namespace luabridge - -// End File: Source/LuaBridge/detail/CFunctions.h - -// Begin File: Source/LuaBridge/detail/LuaRef.h - -// https://github.com/kunitoki/LuaBridge3 -// Copyright 2020, Lucio Asnaghi -// Copyright 2019, George Tokmaji -// Copyright 2018, Dmitry Tarakanov -// Copyright 2012, Vinnie Falco -// Copyright 2008, Nigel Atkinson -// SPDX-License-Identifier: MIT - -namespace luabridge { - -class LuaResult; - -//================================================================================================= -/** - * @brief Type tag for representing LUA_TNIL. - * - * Construct one of these using `LuaNil ()` to represent a Lua nil. This is faster than creating a reference in the registry to nil. - * Example: - * - * @code - * LuaRef t (LuaRef::createTable (L)); - * ... - * t ["k"] = LuaNil (); // assign nil - * @endcode - */ -struct LuaNil -{ -}; - -/** - * @brief Stack specialization for LuaNil. - */ -template <> -struct Stack -{ - static bool push(lua_State* L, const LuaNil&, std::error_code&) - { - lua_pushnil(L); - return true; - } - - static bool isInstance(lua_State* L, int index) - { - return lua_type(L, index) == LUA_TNIL; - } -}; - -//================================================================================================= -/** - * @brief Base class for Lua variables and table item reference classes. - */ -template -class LuaRefBase -{ -protected: - //============================================================================================= - /** - * @brief Pop the Lua stack. - * - * Pops the specified number of stack items on destruction. We use this when returning objects, to avoid an explicit temporary - * variable, since the destructor executes after the return statement. For example: - * - * @code - * template - * U cast (lua_State* L) - * { - * StackPop p (L, 1); - * ... - * return U (); // Destructor called after this line - * } - * @endcode - * - * @note The `StackPop` object must always be a named local variable. - */ - class StackPop - { - public: - /** - * @brief Create a StackPop object. - * - * @param L A Lua state. - * @param count The number of stack entries to pop on destruction. - */ - StackPop(lua_State* L, int count) - : m_L(L) - , m_count(count) { - } - - /** - * @brief Destroy a StackPop object. - * - * In case an exception is in flight before the destructor is called, stack is potentially cleared by lua. So we never pop more than - * the actual size of the stack. - */ - ~StackPop() - { - const int stackSize = lua_gettop(m_L); - - lua_pop(m_L, stackSize < m_count ? stackSize : m_count); - } - - /** - * @brief Set a new number to pop. - * - * @param newCount The new number of stack entries to pop on destruction. - */ - void popCount(int newCount) - { - m_count = newCount; - } - - private: - lua_State* m_L = nullptr; - int m_count = 0; - }; - - friend struct Stack; - - //============================================================================================= - /** - * @brief Type tag for stack construction. - */ - struct FromStack - { - }; - - LuaRefBase(lua_State* L) - : m_L(L) - { - } - - //============================================================================================= - /** - * @brief Create a reference to this reference. - * - * @returns An index in the Lua registry. - */ - int createRef() const - { - impl().push(); - - return luaL_ref(m_L, LUA_REGISTRYINDEX); - } - -public: - //============================================================================================= - /** - * @brief Convert to a string using lua_tostring function. - * - * @returns A string representation of the referred Lua value. - */ - std::string tostring() const - { - StackPop p(m_L, 1); - - lua_getglobal(m_L, "tostring"); - - impl().push(); - - lua_call(m_L, 1, 1); - - const char* str = lua_tostring(m_L, -1); - return str != nullptr ? str : ""; - } - - //============================================================================================= - /** - * @brief Print a text description of the value to a stream. - * - * This is used for diagnostics. - * - * @param os An output stream. - */ - void print(std::ostream& os) const - { - switch (type()) - { - case LUA_TNIL: - os << "nil"; - break; - - case LUA_TNUMBER: - os << cast(); - break; - - case LUA_TBOOLEAN: - os << (cast() ? "true" : "false"); - break; - - case LUA_TSTRING: - os << '"' << cast() << '"'; - break; - - case LUA_TTABLE: - os << "table: " << tostring(); - break; - - case LUA_TFUNCTION: - os << "function: " << tostring(); - break; - - case LUA_TUSERDATA: - os << "userdata: " << tostring(); - break; - - case LUA_TTHREAD: - os << "thread: " << tostring(); - break; - - case LUA_TLIGHTUSERDATA: - os << "lightuserdata: " << tostring(); - break; - - default: - os << "unknown"; - break; - } - } - - //============================================================================================= - /** - * @brief Insert a Lua value or table item reference to a stream. - * - * @param os An output stream. - * @param ref A Lua reference. - * - * @returns The output stream. - */ - friend std::ostream& operator<<(std::ostream& os, const LuaRefBase& ref) - { - ref.print(os); - return os; - } - - //============================================================================================= - /** - * @brief Retrieve the lua_State associated with the reference. - * - * @returns A Lua state. - */ - lua_State* state() const - { - return m_L; - } - - //============================================================================================= - /** - * @brief Place the object onto the Lua stack. - * - * @param L A Lua state. - */ - void push(lua_State* L) const - { - assert(equalstates(L, m_L)); - (void) L; - - impl().push(); - } - - //============================================================================================= - /** - * @brief Pop the top of Lua stack and assign it to the reference. - * - * @param L A Lua state. - */ - void pop(lua_State* L) - { - assert(equalstates(L, m_L)); - (void) L; - - impl().pop(); - } - - //============================================================================================= - /** - * @brief Return the Lua type of the referred value. - * - * This invokes lua_type(). - * - * @returns The type of the referred value. - * - * @see lua_type() - */ - int type() const - { - StackPop p(m_L, 1); - - impl().push(); - - const int refType = lua_type(m_L, -1); - - return refType; - } - - /** - * @brief Indicate whether it is a nil reference. - * - * @returns True if this is a nil reference, false otherwise. - */ - bool isNil() const { return type() == LUA_TNIL; } - - /** - * @brief Indicate whether it is a reference to a boolean. - * - * @returns True if it is a reference to a boolean, false otherwise. - */ - bool isBool() const { return type() == LUA_TBOOLEAN; } - - /** - * @brief Indicate whether it is a reference to a number. - * - * @returns True if it is a reference to a number, false otherwise. - */ - bool isNumber() const { return type() == LUA_TNUMBER; } - - /** - * @brief Indicate whether it is a reference to a string. - * - * @returns True if it is a reference to a string, false otherwise. - */ - bool isString() const { return type() == LUA_TSTRING; } - - /** - * @brief Indicate whether it is a reference to a table. - * - * @returns True if it is a reference to a table, false otherwise. - */ - bool isTable() const { return type() == LUA_TTABLE; } - - /** - * @brief Indicate whether it is a reference to a function. - * - * @returns True if it is a reference to a function, false otherwise. - */ - bool isFunction() const { return type() == LUA_TFUNCTION; } - - /** - * @brief Indicate whether it is a reference to a full userdata. - * - * @returns True if it is a reference to a full userdata, false otherwise. - */ - bool isUserdata() const { return type() == LUA_TUSERDATA; } - - /** - * @brief Indicate whether it is a reference to a lua thread (coroutine). - * - * @returns True if it is a reference to a lua thread, false otherwise. - */ - bool isThread() const { return type() == LUA_TTHREAD; } - - /** - * @brief Indicate whether it is a reference to a light userdata. - * - * @returns True if it is a reference to a light userdata, false otherwise. - */ - bool isLightUserdata() const { return type() == LUA_TLIGHTUSERDATA; } - - /** - * @brief Indicate whether it is a callable. - * - * @returns True if it is a callable, false otherwise. - */ - bool isCallable() const - { - if (isFunction()) - return true; - - auto metatable = getMetatable(); - return metatable.isTable() && metatable["__call"].isFunction(); - } - - //============================================================================================= - /** - * @brief Perform an explicit conversion to the type T. - * - * @returns A value of the type T converted from this reference. - */ - template - T cast() const - { - StackPop p(m_L, 1); - - impl().push(); - - return Stack::get(m_L, -1); - } - - //============================================================================================= - /** - * @brief Indicate if this reference is convertible to the type T. - * - * @returns True if the referred value is convertible to the type T, false otherwise. - */ - template - bool isInstance() const - { - StackPop p(m_L, 1); - - impl().push(); - - return Stack::isInstance(m_L, -1); - } - - //============================================================================================= - /** - * @brief Type cast operator. - * - * @returns A value of the type T converted from this reference. - */ - template - operator T() const - { - return cast(); - } - - //============================================================================================= - /** - * @brief Get the metatable for the LuaRef. - * - * @returns A LuaRef holding the metatable of the lua object. - */ - LuaRef getMetatable() const - { - if (isNil()) - return LuaRef(m_L); - - StackPop p(m_L, 2); - - impl().push(); - - if (! lua_getmetatable(m_L, -1)) - { - p.popCount(1); - return LuaRef(m_L); - } - - return LuaRef::fromStack(m_L); - } - - //============================================================================================= - /** - * @brief Compare this reference with a specified value using lua_compare(). - * - * This invokes metamethods. - * - * @param rhs A value to compare with. - * - * @returns True if the referred value is equal to the specified one. - */ - template - bool operator==(T rhs) const - { - StackPop p(m_L, 2); - - impl().push(); - - std::error_code ec; - if (! Stack::push(m_L, rhs, ec)) - { - p.popCount(1); - return false; - } - - return lua_compare(m_L, -2, -1, LUA_OPEQ) == 1; - } - - /** - * @brief Compare this reference with a specified value using lua_compare(). - * - * This invokes metamethods. - * - * @param rhs A value to compare with. - * - * @returns True if the referred value is not equal to the specified one. - */ - template - bool operator!=(T rhs) const - { - return !(*this == rhs); - } - - /** - * @brief Compare this reference with a specified value using lua_compare(). - * - * This invokes metamethods. - * - * @param rhs A value to compare with. - * - * @returns True if the referred value is less than the specified one. - */ - template - bool operator<(T rhs) const - { - StackPop p(m_L, 2); - - impl().push(); - - std::error_code ec; - if (! Stack::push(m_L, rhs, ec)) - { - p.popCount(1); - return false; - } - - const int lhsType = lua_type(m_L, -2); - const int rhsType = lua_type(m_L, -1); - if (lhsType != rhsType) - return lhsType < rhsType; - - return lua_compare(m_L, -2, -1, LUA_OPLT) == 1; - } - - /** - * @brief Compare this reference with a specified value using lua_compare(). - * - * This invokes metamethods. - * - * @param rhs A value to compare with. - * - * @returns True if the referred value is less than or equal to the specified one. - */ - template - bool operator<=(T rhs) const - { - StackPop p(m_L, 2); - - impl().push(); - - std::error_code ec; - if (! Stack::push(m_L, rhs, ec)) - { - p.popCount(1); - return false; - } - - const int lhsType = lua_type(m_L, -2); - const int rhsType = lua_type(m_L, -1); - if (lhsType != rhsType) - return lhsType <= rhsType; - - return lua_compare(m_L, -2, -1, LUA_OPLE) == 1; - } - - /** - * @brief Compare this reference with a specified value using lua_compare(). - * - * This invokes metamethods. - * - * @param rhs A value to compare with. - * - * @returns True if the referred value is greater than the specified one. - */ - template - bool operator>(T rhs) const - { - StackPop p(m_L, 2); - - impl().push(); - - std::error_code ec; - if (! Stack::push(m_L, rhs, ec)) - { - p.popCount(1); - return false; - } - - const int lhsType = lua_type(m_L, -2); - const int rhsType = lua_type(m_L, -1); - if (lhsType != rhsType) - return lhsType > rhsType; - - return lua_compare(m_L, -1, -2, LUA_OPLT) == 1; - } - - /** - * @brief Compare this reference with a specified value using lua_compare(). - * - * This invokes metamethods. - * - * @param rhs A value to compare with. - * - * @returns True if the referred value is greater than or equal to the specified one. - */ - template - bool operator>=(T rhs) const - { - StackPop p(m_L, 2); - - impl().push(); - - std::error_code ec; - if (! Stack::push(m_L, rhs, ec)) - { - p.popCount(1); - return false; - } - - const int lhsType = lua_type(m_L, -2); - const int rhsType = lua_type(m_L, -1); - if (lhsType != rhsType) - return lhsType >= rhsType; - - return lua_compare(m_L, -1, -2, LUA_OPLE) == 1; - } - - /** - * @brief Compare this reference with a specified value using lua_compare(). - * - * This does not invoke metamethods. - * - * @param rhs A value to compare with. - * - * @returns True if the referred value is equal to the specified one. - */ - template - bool rawequal(T v) const - { - StackPop p(m_L, 2); - - impl().push(); - - std::error_code ec; - if (! Stack::push(m_L, v, ec)) - { - p.popCount(1); - return false; - } - - return lua_rawequal(m_L, -1, -2) == 1; - } - - //============================================================================================= - /** - * @brief Append a value to a referred table. - * - * If the table is a sequence this will add another element to it. - * - * @param v A value to append to the table. - */ - template - void append(T v) const - { - StackPop p(m_L, 1); - - impl().push(); - - std::error_code ec; - if (! Stack::push(m_L, v, ec)) - return; - - luaL_ref(m_L, -2); - } - - //============================================================================================= - /** - * @brief Return the length of a referred array. - * - * This is identical to applying the Lua # operator. - * - * @returns The length of the referred array. - */ - int length() const - { - StackPop p(m_L, 1); - - impl().push(); - - return get_length(m_L, -1); - } - - //============================================================================================= - /** - * @brief Call Lua code. - * - * The return value is provided as a LuaRef (which may be LUA_REFNIL). - * - * If an error occurs, a LuaException is thrown (only if exceptions are enabled). - * - * @returns A result of the call. - */ - template - LuaResult operator()(Args&&... args) const; - -protected: - lua_State* m_L = nullptr; - -private: - const Impl& impl() const { return static_cast(*this); } - - Impl& impl() { return static_cast(*this); } -}; - -//================================================================================================= -/** - * @brief Lightweight reference to a Lua object. - * - * The reference is maintained for the lifetime of the C++ object. - */ -class LuaRef : public LuaRefBase -{ - //============================================================================================= - /** - * @brief A proxy for representing table values. - */ - class TableItem : public LuaRefBase - { - friend class LuaRef; - - public: - //========================================================================================= - /** - * @brief Construct a TableItem from a table value. - * - * The table is in the registry, and the key is at the top of the stack. - * The key is popped off the stack. - * - * @param L A lua state. - * @param tableRef The index of a table in the Lua registry. - */ - TableItem(lua_State* L, int tableRef) - : LuaRefBase(L) - , m_tableRef(LUA_NOREF) - , m_keyRef(luaL_ref(L, LUA_REGISTRYINDEX)) - { - lua_rawgeti(m_L, LUA_REGISTRYINDEX, tableRef); - m_tableRef = luaL_ref(L, LUA_REGISTRYINDEX); - } - - //========================================================================================= - /** - * @brief Create a TableItem via copy constructor. - * - * It is best to avoid code paths that invoke this, because it creates an extra temporary Lua reference. Typically this is done by - * passing the TableItem parameter as a `const` reference. - * - * @param other Another Lua table item reference. - */ - TableItem(const TableItem& other) - : LuaRefBase(other.m_L) - , m_tableRef(LUA_NOREF) - , m_keyRef(LUA_NOREF) - { - lua_rawgeti(m_L, LUA_REGISTRYINDEX, other.m_tableRef); - m_tableRef = luaL_ref(m_L, LUA_REGISTRYINDEX); - - lua_rawgeti(m_L, LUA_REGISTRYINDEX, other.m_keyRef); - m_keyRef = luaL_ref(m_L, LUA_REGISTRYINDEX); - } - - //========================================================================================= - /** - * @brief Destroy the proxy. - * - * This does not destroy the table value. - */ - ~TableItem() - { - if (m_keyRef != LUA_NOREF) - luaL_unref(m_L, LUA_REGISTRYINDEX, m_keyRef); - - if (m_tableRef != LUA_NOREF) - luaL_unref(m_L, LUA_REGISTRYINDEX, m_tableRef); - } - - //========================================================================================= - /** - * @brief Assign a new value to this table key. - * - * This may invoke metamethods. - * - * @tparam T The type of a value to assing. - * - * @param v A value to assign. - * - * @returns This reference. - */ - template - TableItem& operator=(T v) - { - StackPop p(m_L, 1); - lua_rawgeti(m_L, LUA_REGISTRYINDEX, m_tableRef); - lua_rawgeti(m_L, LUA_REGISTRYINDEX, m_keyRef); - - std::error_code ec; - if (! Stack::push(m_L, v, ec)) - return *this; - - lua_settable(m_L, -3); - return *this; - } - - //========================================================================================= - /** - * @brief Assign a new value to this table key. - * - * The assignment is raw, no metamethods are invoked. - * - * @tparam T The type of a value to assing. - * - * @param v A value to assign. - * - * @returns This reference. - */ - template - TableItem& rawset(T v) - { - StackPop p(m_L, 1); - lua_rawgeti(m_L, LUA_REGISTRYINDEX, m_tableRef); - lua_rawgeti(m_L, LUA_REGISTRYINDEX, m_keyRef); - - std::error_code ec; - if (! Stack::push(m_L, v, ec)) - return *this; - - lua_rawset(m_L, -3); - return *this; - } - - //========================================================================================= - /** - * @brief Push the value onto the Lua stack. - */ - using LuaRefBase::push; - - void push() const - { - lua_rawgeti(m_L, LUA_REGISTRYINDEX, m_tableRef); - lua_rawgeti(m_L, LUA_REGISTRYINDEX, m_keyRef); - lua_gettable(m_L, -2); - lua_remove(m_L, -2); // remove the table - } - - //========================================================================================= - /** - * @brief Access a table value using a key. - * - * This invokes metamethods. - * - * @tparam T The type of a key. - * - * @param key A key value. - * - * @returns A Lua table item reference. - */ - template - TableItem operator[](T key) const - { - return LuaRef(*this)[key]; - } - - //========================================================================================= - /** - * @brief Access a table value using a key. - * - * The operation is raw, metamethods are not invoked. The result is passed by value and may not be modified. - * - * @tparam T The type of a key. - * - * @param key A key value. - * - * @returns A Lua value reference. - */ - template - LuaRef rawget(T key) const - { - return LuaRef(*this).rawget(key); - } - - private: - int m_tableRef; - int m_keyRef; - }; - - friend struct Stack; - friend struct Stack; - - //========================================================================================= - /** - * @brief Create a reference to an object at the top of the Lua stack and pop it. - * - * This constructor is private and not invoked directly. Instead, use the `fromStack` function. - * - * @param L A Lua state. - * - * @note The object is popped. - */ - LuaRef(lua_State* L, FromStack) - : LuaRefBase(L) - , m_ref(luaL_ref(m_L, LUA_REGISTRYINDEX)) - { - } - - //========================================================================================= - /** - * @brief Create a reference to an object on the Lua stack. - * - * This constructor is private and not invoked directly. Instead, use the `fromStack` function. - * - * @param L A Lua state. - * - * @param index The index of the value on the Lua stack. - * - * @note The object is not popped. - */ - LuaRef(lua_State* L, int index, FromStack) - : LuaRefBase(L) - , m_ref(LUA_NOREF) - { - lua_pushvalue(m_L, index); - m_ref = luaL_ref(m_L, LUA_REGISTRYINDEX); - } - -public: - //============================================================================================= - /** - * @brief Create an invalid reference that will be treated as nil. - * - * The Lua reference may be assigned later. - * - * @param L A Lua state. - */ - LuaRef(lua_State* L) - : LuaRefBase(L) - , m_ref(LUA_NOREF) - { - } - - //============================================================================================= - /** - * @brief Push a value onto a Lua stack and return a reference to it. - * - * @param L A Lua state. - * @param v A value to push. - */ - template - LuaRef(lua_State* L, T v) - : LuaRefBase(L) - , m_ref(LUA_NOREF) - { - std::error_code ec; - if (! Stack::push(m_L, v, ec)) - return; - - m_ref = luaL_ref(m_L, LUA_REGISTRYINDEX); - } - - //============================================================================================= - /** - * @brief Create a reference to a table item. - * - * @param v A table item reference. - */ - LuaRef(const TableItem& v) - : LuaRefBase(v.state()) - , m_ref(v.createRef()) - { - } - - //============================================================================================= - /** - * @brief Create a new reference to an existing Lua value. - * - * @param other An existing reference. - */ - LuaRef(const LuaRef& other) - : LuaRefBase(other.m_L) - , m_ref(other.createRef()) - { - } - - //============================================================================================= - /** - * @brief Destroy a reference. - * - * The corresponding Lua registry reference will be released. - * - * @note If the state refers to a thread, it is the responsibility of the caller to ensure that the thread still exists when the LuaRef is destroyed. - */ - ~LuaRef() - { - if (m_ref != LUA_NOREF) - luaL_unref(m_L, LUA_REGISTRYINDEX, m_ref); - } - - //============================================================================================= - /** - * @brief Return a reference to a top Lua stack item. - * - * The stack item is not popped. - * - * @param L A Lua state. - * - * @returns A reference to a value on the top of a Lua stack. - */ - static LuaRef fromStack(lua_State* L) - { - return LuaRef(L, FromStack()); - } - - //============================================================================================= - /** - * @brief Return a reference to a Lua stack item with a specified index. - * - * The stack item is not removed. - * - * @param L A Lua state. - * @param index An index in the Lua stack. - * - * @returns A reference to a value in a Lua stack. - */ - static LuaRef fromStack(lua_State* L, int index) - { - lua_pushvalue(L, index); - return LuaRef(L, FromStack()); - } - - //============================================================================================= - /** - * @brief Create a new empty table on the top of a Lua stack and return a reference to it. - * - * @param L A Lua state. - * - * @returns A reference to the newly created table. - * - * @see luabridge::newTable() - */ - static LuaRef newTable(lua_State* L) - { - lua_newtable(L); - return LuaRef(L, FromStack()); - } - - //============================================================================================= - /** - * @brief Return a reference to a named global Lua variable. - * - * @param L A Lua state. - * @param name The name of a global variable. - * - * @returns A reference to the Lua variable. - * - * @see luabridge::getGlobal() - */ - static LuaRef getGlobal(lua_State* L, const char* name) - { - lua_getglobal(L, name); - return LuaRef(L, FromStack()); - } - - //============================================================================================= - /** - * @brief Indicate whether it is an invalid reference. - * - * @returns True if this is an invalid reference, false otherwise. - */ - bool isValid() const { return m_ref != LUA_NOREF; } - - //============================================================================================= - /** - * @brief Assign another LuaRef to this LuaRef. - * - * @param rhs A reference to assign from. - * - * @returns This reference. - */ - LuaRef& operator=(const LuaRef& rhs) - { - LuaRef ref(rhs); - swap(ref); - return *this; - } - - //============================================================================================= - /** - * @brief Assign a table item reference. - * - * @param rhs A table item reference. - * - * @returns This reference. - */ - LuaRef& operator=(const LuaRef::TableItem& rhs) - { - LuaRef ref(rhs); - swap(ref); - return *this; - } - - //============================================================================================= - /** - * @brief Assign nil to this reference. - * - * @returns This reference. - */ - LuaRef& operator=(const LuaNil&) - { - LuaRef ref(m_L); - swap(ref); - return *this; - } - - //============================================================================================= - /** - * @brief Assign a different value to this reference. - * - * @param rhs A value to assign. - * - * @returns This reference. - */ - template - LuaRef& operator=(T rhs) - { - LuaRef ref(m_L, rhs); - swap(ref); - return *this; - } - - //============================================================================================= - /** - * @brief Place the object onto the Lua stack. - */ - using LuaRefBase::push; - - void push() const - { - lua_rawgeti(m_L, LUA_REGISTRYINDEX, m_ref); - } - - //============================================================================================= - /** - * @brief Pop the top of Lua stack and assign the ref to m_ref - */ - void pop() - { - luaL_unref(m_L, LUA_REGISTRYINDEX, m_ref); - m_ref = luaL_ref(m_L, LUA_REGISTRYINDEX); - } - - //============================================================================================= - /** - * @brief Access a table value using a key. - * - * This invokes metamethods. - * - * @param key A key in the table. - * - * @returns A reference to the table item. - */ - template - TableItem operator[](T key) const - { - std::error_code ec; - if (! Stack::push(m_L, key, ec)) - return TableItem(m_L, m_ref); - - return TableItem(m_L, m_ref); - } - - //============================================================================================= - /** - * @brief Access a table value using a key. - * - * The operation is raw, metamethods are not invoked. The result is passed by value and may not be modified. - * - * @param key A key in the table. - * - * @returns A reference to the table item. - */ - template - LuaRef rawget(T key) const - { - StackPop(m_L, 1); - - push(m_L); - - std::error_code ec; - if (! Stack::push(m_L, key, ec)) - return LuaRef(m_L); - - lua_rawget(m_L, -2); - return LuaRef(m_L, FromStack()); - } - -private: - void swap(LuaRef& other) - { - using std::swap; - - swap(m_L, other.m_L); - swap(m_ref, other.m_ref); - } - - int m_ref = LUA_NOREF; -}; - -//================================================================================================= -/** - * @brief Stack specialization for `LuaRef`. - */ -template <> -struct Stack -{ - static bool push(lua_State* L, const LuaRef& v, std::error_code&) - { - return v.push(L), true; - } - - static LuaRef get(lua_State* L, int index) - { - return LuaRef::fromStack(L, index); - } -}; - -//================================================================================================= -/** - * @brief Stack specialization for `TableItem`. - */ -template <> -struct Stack -{ - static bool push(lua_State* L, const LuaRef::TableItem& v, std::error_code&) - { - return v.push(L), true; - } -}; - -//================================================================================================= -/** - * @brief Create a reference to a new, empty table. - * - * This is a syntactic abbreviation for LuaRef::newTable (). - */ -inline LuaRef newTable(lua_State* L) -{ - return LuaRef::newTable(L); -} - -//================================================================================================= -/** - * @brief Create a reference to a value in the global table. - * - * This is a syntactic abbreviation for LuaRef::getGlobal (). - */ -inline LuaRef getGlobal(lua_State* L, const char* name) -{ - return LuaRef::getGlobal(L, name); -} - -//================================================================================================= -/** - * @brief C++ like cast syntax. - */ -template -T cast(const LuaRef& ref) -{ - return ref.cast(); -} - -} // namespace luabridge - -// End File: Source/LuaBridge/detail/LuaRef.h - -// Begin File: Source/LuaBridge/detail/Invoke.h - -// https://github.com/kunitoki/LuaBridge3 -// Copyright 2021, Lucio Asnaghi -// SPDX-License-Identifier: MIT - -namespace luabridge { - -//================================================================================================= -/** - * @brief Result of a lua invocation. - */ -class LuaResult -{ -public: - /** - * @brief Get if the result was ok and didn't raise a lua error. - */ - explicit operator bool() const noexcept - { - return !m_ec; - } - - /** - * @brief Return if the invocation was ok and didn't raise a lua error. - */ - bool wasOk() const noexcept - { - return !m_ec; - } - - /** - * @brief Return if the invocation did raise a lua error. - */ - bool hasFailed() const noexcept - { - return !!m_ec; - } - - /** - * @brief Return the error code, if any. - * - * In case the invcation didn't raise any lua error, the value returned equals to a - * default constructed std::error_code. - */ - std::error_code errorCode() const noexcept - { - return m_ec; - } - - /** - * @brief Return the error message, if any. - */ - std::string errorMessage() const noexcept - { - if (std::holds_alternative(m_data)) - { - const auto& message = std::get(m_data); - return message.empty() ? m_ec.message() : message; - } - - return {}; - } - - /** - * @brief Return the number of return values. - */ - std::size_t size() const noexcept - { - if (std::holds_alternative>(m_data)) - return std::get>(m_data).size(); - - return 0; - } - - /** - * @brief Get a return value at a specific index. - */ - LuaRef operator[](std::size_t index) const - { - assert(m_ec == std::error_code()); - - if (std::holds_alternative>(m_data)) - { - const auto& values = std::get>(m_data); - - assert(index < values.size()); - return values[index]; - } - - return LuaRef(m_L); - } - -private: - template - friend LuaResult call(const LuaRef&, Args&&...); - - static LuaResult errorFromStack(lua_State* L, std::error_code ec) - { - auto errorString = lua_tostring(L, -1); - lua_pop(L, 1); - - return LuaResult(L, ec, errorString ? errorString : ec.message()); - } - - static LuaResult valuesFromStack(lua_State* L, int stackTop) - { - std::vector values; - - const int numReturnedValues = lua_gettop(L) - stackTop; - if (numReturnedValues > 0) - { - values.reserve(numReturnedValues); - - for (int index = numReturnedValues; index > 0; --index) - values.emplace_back(LuaRef::fromStack(L, -index)); - - lua_pop(L, numReturnedValues); - } - - return LuaResult(L, std::move(values)); - } - - LuaResult(lua_State* L, std::error_code ec, std::string_view errorString) - : m_L(L) - , m_ec(ec) - , m_data(std::string(errorString)) - { - } - - explicit LuaResult(lua_State* L, std::vector values) noexcept - : m_L(L) - , m_data(std::move(values)) - { - } - - lua_State* m_L = nullptr; - std::error_code m_ec; - std::variant, std::string> m_data; -}; - -//================================================================================================= -/** - * @brief Safely call Lua code. - * - * These overloads allow Lua code to be called throught lua_pcall. The return value is provided as - * a LuaResult which will hold the return values or an error if the call failed. - * - * If an error occurs, a LuaException is thrown or if exceptions are disabled the FunctionResult will - * contain a error code and evaluate false. - * - * @note The function might throw a LuaException if the application is compiled with exceptions on - * and they are enabled globally by calling `enableExceptions` in two cases: - * - one of the arguments passed cannot be pushed in the stack, for example a unregistered C++ class - * - the lua invaction calls the panic handler, which is converted to a C++ exception - * - * @return A result object. -*/ -template -LuaResult call(const LuaRef& object, Args&&... args) -{ - lua_State* L = object.state(); - const int stackTop = lua_gettop(L); - - object.push(); - - { - std::error_code ec; - auto pushedArgs = detail::push_arguments(L, std::forward_as_tuple(args...), ec); - if (ec) - { - lua_pop(L, static_cast(pushedArgs) + 1); - return LuaResult(L, ec, ec.message()); - } - } - - int code = lua_pcall(L, sizeof...(Args), LUA_MULTRET, 0); - if (code != LUABRIDGE_LUA_OK) - { - auto ec = makeErrorCode(ErrorCode::LuaFunctionCallFailed); - -#if LUABRIDGE_HAS_EXCEPTIONS - if (LuaException::areExceptionsEnabled()) - LuaException::raise(LuaException(L, ec)); -#else - return LuaResult::errorFromStack(L, ec); -#endif - } - - return LuaResult::valuesFromStack(L, stackTop); -} - -//============================================================================================= -/** - * @brief Wrapper for lua_pcall that throws if exceptions are enabled. - */ -inline int pcall(lua_State* L, int nargs = 0, int nresults = 0, int msgh = 0) -{ - const int code = lua_pcall(L, nargs, nresults, msgh); - -#if LUABRIDGE_HAS_EXCEPTIONS - if (code != LUABRIDGE_LUA_OK && LuaException::areExceptionsEnabled()) - LuaException::raise(LuaException(L, makeErrorCode(ErrorCode::LuaFunctionCallFailed))); -#endif - - return code; -} - -//============================================================================================= -template -template -LuaResult LuaRefBase::operator()(Args&&... args) const -{ - return call(*this, std::forward(args)...); -} - -} // namespace luabridge - -// End File: Source/LuaBridge/detail/Invoke.h - -// Begin File: Source/LuaBridge/detail/Iterator.h - -// https://github.com/kunitoki/LuaBridge3 -// Copyright 2020, Lucio Asnaghi -// Copyright 2018, Dmitry Tarakanov -// Copyright 2012, Vinnie Falco -// SPDX-License-Identifier: MIT - -namespace luabridge { - -//================================================================================================= -/** - * @brief Iterator class to allow table iteration. - * - * @see Range class. - */ -class Iterator -{ -public: - explicit Iterator(const LuaRef& table, bool isEnd = false) - : m_L(table.state()) - , m_table(table) - , m_key(table.state()) // m_key is nil - , m_value(table.state()) // m_value is nil - { - if (! isEnd) - { - next(); // get the first (key, value) pair from table - } - } - - /** - * @brief Return an associated Lua state. - * - * @return A Lua state. - */ - lua_State* state() const noexcept - { - return m_L; - } - - /** - * @brief Dereference the iterator. - * - * @return A key-value pair for a current table entry. - */ - std::pair operator*() const - { - return std::make_pair(m_key, m_value); - } - - /** - * @brief Return the value referred by the iterator. - * - * @return A value for the current table entry. - */ - LuaRef operator->() const - { - return m_value; - } - - /** - * @brief Compare two iterators. - * - * @param rhs Another iterator. - * - * @return True if iterators point to the same entry of the same table, false otherwise. - */ - bool operator!=(const Iterator& rhs) const - { - assert(m_L == rhs.m_L); - - return ! m_table.rawequal(rhs.m_table) || ! m_key.rawequal(rhs.m_key); - } - - /** - * @brief Move the iterator to the next table entry. - * - * @return This iterator. - */ - Iterator& operator++() - { - if (isNil()) - { - // if the iterator reaches the end, do nothing - return *this; - } - else - { - next(); - return *this; - } - } - - /** - * @brief Check if the iterator points after the last table entry. - * - * @return True if there are no more table entries to iterate, false otherwise. - */ - bool isNil() const noexcept - { - return m_key.isNil(); - } - - /** - * @brief Return the key for the current table entry. - * - * @return A reference to the entry key. - */ - LuaRef key() const - { - return m_key; - } - - /** - * @brief Return the key for the current table entry. - * - * @return A reference to the entry value. - */ - LuaRef value() const - { - return m_value; - } - -private: - // Don't use postfix increment, it is less efficient - Iterator operator++(int); - - void next() - { - m_table.push(); - m_key.push(); - - if (lua_next(m_L, -2)) - { - m_value.pop(); - m_key.pop(); - } - else - { - m_key = LuaNil(); - m_value = LuaNil(); - } - - lua_pop(m_L, 1); - } - - lua_State* m_L = nullptr; - LuaRef m_table; - LuaRef m_key; - LuaRef m_value; -}; - -//================================================================================================= -/** - * @brief Range class taking two table iterators. - */ -class Range -{ -public: - Range(const Iterator& begin, const Iterator& end) - : m_begin(begin) - , m_end(end) - { - } - - const Iterator& begin() const noexcept - { - return m_begin; - } - - const Iterator& end() const noexcept - { - return m_end; - } - -private: - Iterator m_begin; - Iterator m_end; -}; - -//================================================================================================= -/** - * @brief Return a range for the Lua table reference. - * - * @return A range suitable for range-based for statement. - */ -inline Range pairs(const LuaRef& table) -{ - return Range{ Iterator(table, false), Iterator(table, true) }; -} - -} // namespace luabridge - -// End File: Source/LuaBridge/detail/Iterator.h - -// Begin File: Source/LuaBridge/detail/Security.h - -// https://github.com/vinniefalco/LuaBridge -// Copyright 2021, Lucio Asnaghi -// Copyright 2012, Vinnie Falco -// SPDX-License-Identifier: MIT - -namespace luabridge { - -//================================================================================================= -/** - * @brief Security options. - */ -class Security -{ -public: - static bool hideMetatables() noexcept - { - return getSettings().hideMetatables; - } - - static void setHideMetatables(bool shouldHide) noexcept - { - getSettings().hideMetatables = shouldHide; - } - -private: - struct Settings - { - Settings() noexcept - : hideMetatables(true) - { - } - - bool hideMetatables; - }; - - static Settings& getSettings() noexcept - { - static Settings settings; - return settings; - } -}; - -//================================================================================================= -/** - * @brief Get a global value from the lua_State. - * - * @note This works on any type specialized by `Stack`, including `LuaRef` and its table proxies. -*/ -template -T getGlobal(lua_State* L, const char* name) -{ - lua_getglobal(L, name); - - auto result = luabridge::Stack::get(L, -1); - - lua_pop(L, 1); - - return result; -} - -//================================================================================================= -/** - * @brief Set a global value in the lua_State. - * - * @note This works on any type specialized by `Stack`, including `LuaRef` and its table proxies. -*/ -template -bool setGlobal(lua_State* L, T&& t, const char* name) -{ - std::error_code ec; - if (push(L, std::forward(t), ec)) - { - lua_setglobal(L, name); - return true; - } - - return false; -} - -//================================================================================================= -/** - * @brief Change whether or not metatables are hidden (on by default). - */ -inline void setHideMetatables(bool shouldHide) noexcept -{ - Security::setHideMetatables(shouldHide); -} - -} // namespace luabridge - -// End File: Source/LuaBridge/detail/Security.h - -// Begin File: Source/LuaBridge/detail/Namespace.h - -// https://github.com/kunitoki/LuaBridge3 -// Copyright 2020, Lucio Asnaghi -// Copyright 2019, Dmitry Tarakanov -// Copyright 2012, Vinnie Falco -// Copyright 2007, Nathan Reed -// SPDX-License-Identifier: MIT - -namespace luabridge { -namespace detail { - -//================================================================================================= -/** - * @brief Base for class and namespace registration. - * - * Maintains Lua stack in the proper state. Once beginNamespace, beginClass or deriveClass is called the parent object upon its destruction - * may no longer clear the Lua stack. - * - * Then endNamespace or endClass is called, a new parent is created and the child transfers the responsibility for clearing stack to it. - * - * So there can be maximum one "active" registrar object. - */ -class Registrar -{ -protected: - Registrar(lua_State* L) - : L(L) - , m_stackSize(0) - { - } - - Registrar(lua_State* L, int skipStackPops) - : L(L) - , m_stackSize(0) - , m_skipStackPops(skipStackPops) - { - } - - Registrar(const Registrar& rhs) - : L(rhs.L) - , m_stackSize(std::exchange(rhs.m_stackSize, 0)) - , m_skipStackPops(std::exchange(rhs.m_skipStackPops, 0)) - { - } - - Registrar& operator=(const Registrar& rhs) - { - using std::swap; - - Registrar tmp(rhs); - - swap(m_stackSize, tmp.m_stackSize); - - return *this; - } - - ~Registrar() - { - const int popsCount = m_stackSize - m_skipStackPops; - if (popsCount > 0) - { - assert(popsCount <= lua_gettop(L)); - - lua_pop(L, popsCount); - } - } - - void assertIsActive() const - { - if (m_stackSize == 0) - { - throw_or_assert("Unable to continue registration"); - } - } - - lua_State* const L = nullptr; - int mutable m_stackSize = 0; - int mutable m_skipStackPops = 0; -}; - -} // namespace detail - -//================================================================================================= -/** - * @brief Provides C++ to Lua registration capabilities. - * - * This class is not instantiated directly, call `getGlobalNamespace` to start the registration process. - */ -class Namespace : public detail::Registrar -{ - //============================================================================================= -#if 0 - /** - Error reporting. - - VF: This function looks handy, why aren't we using it? - */ - static int luaError (lua_State* L, std::string message) - { - assert (lua_isstring (L, lua_upvalueindex (1))); - std::string s; - - // Get information on the caller's caller to format the message, - // so the error appears to originate from the Lua source. - lua_Debug ar; - int result = lua_getstack (L, 2, &ar); - if (result != 0) - { - lua_getinfo (L, "Sl", &ar); - s = ar.short_src; - if (ar.currentline != -1) - { - // poor mans int to string to avoid . - lua_pushnumber (L, ar.currentline); - s = s + ":" + lua_tostring (L, -1) + ": "; - lua_pop (L, 1); - } - } - - s = s + message; - - return luaL_error (L, s.c_str ()); - } -#endif - - //============================================================================================= - /** - * @brief Factored base to reduce template instantiations. - */ - class ClassBase : public detail::Registrar - { - public: - explicit ClassBase(Namespace& parent) - : Registrar(parent) - { - } - - using Registrar::operator=; - - protected: - //========================================================================================= - /** - * @brief Create the const table. - */ - void createConstTable(const char* name, bool trueConst = true) - { - assert(name != nullptr); - - std::string type_name = std::string(trueConst ? "const " : "") + name; - - // Stack: namespace table (ns) - lua_newtable(L); // Stack: ns, const table (co) - lua_pushvalue(L, -1); // Stack: ns, co, co - lua_setmetatable(L, -2); // co.__metatable = co. Stack: ns, co - - lua_pushstring(L, type_name.c_str()); - lua_rawsetp(L, -2, detail::getTypeKey()); // co [typeKey] = name. Stack: ns, co - - lua_pushcfunction(L, &detail::index_metamethod); - rawsetfield(L, -2, "__index"); - - lua_pushcfunction(L, &detail::newindex_object_metamethod); - rawsetfield(L, -2, "__newindex"); - - lua_newtable(L); - lua_rawsetp(L, -2, detail::getPropgetKey()); - - if (Security::hideMetatables()) - { - lua_pushnil(L); - rawsetfield(L, -2, "__metatable"); - } - } - - //========================================================================================= - /** - * @brief Create the class table. - * - * The Lua stack should have the const table on top. - */ - void createClassTable(const char* name) - { - assert(name != nullptr); - - // Stack: namespace table (ns), const table (co) - - // Class table is the same as const table except the propset table - createConstTable(name, false); // Stack: ns, co, cl - - lua_newtable(L); // Stack: ns, co, cl, propset table (ps) - lua_rawsetp(L, -2, detail::getPropsetKey()); // cl [propsetKey] = ps. Stack: ns, co, cl - - lua_pushvalue(L, -2); // Stack: ns, co, cl, co - lua_rawsetp(L, -2, detail::getConstKey()); // cl [constKey] = co. Stack: ns, co, cl - - lua_pushvalue(L, -1); // Stack: ns, co, cl, cl - lua_rawsetp(L, -3, detail::getClassKey()); // co [classKey] = cl. Stack: ns, co, cl - } - - //========================================================================================= - /** - * @brief Create the static table. - */ - void createStaticTable(const char* name) - { - assert(name != nullptr); - - // Stack: namespace table (ns), const table (co), class table (cl) - lua_newtable(L); // Stack: ns, co, cl, visible static table (vst) - lua_newtable(L); // Stack: ns, co, cl, st, static metatable (st) - lua_pushvalue(L, -1); // Stack: ns, co, cl, vst, st, st - lua_setmetatable(L, -3); // st.__metatable = mt. Stack: ns, co, cl, vst, st - lua_insert(L, -2); // Stack: ns, co, cl, st, vst - rawsetfield(L, -5, name); // ns [name] = vst. Stack: ns, co, cl, st - -#if 0 - lua_pushlightuserdata (L, this); - lua_pushcclosure (L, &tostringMetaMethod, 1); - rawsetfield (L, -2, "__tostring"); -#endif - - lua_pushcfunction(L, &detail::index_metamethod); - rawsetfield(L, -2, "__index"); - - lua_pushcfunction(L, &detail::newindex_static_metamethod); - rawsetfield(L, -2, "__newindex"); - - lua_newtable(L); // Stack: ns, co, cl, st, proget table (pg) - lua_rawsetp(L, -2, detail::getPropgetKey()); // st [propgetKey] = pg. Stack: ns, co, cl, st - - lua_newtable(L); // Stack: ns, co, cl, st, propset table (ps) - lua_rawsetp(L, -2, detail::getPropsetKey()); // st [propsetKey] = pg. Stack: ns, co, cl, st - - lua_pushvalue(L, -2); // Stack: ns, co, cl, st, cl - lua_rawsetp(L, -2, detail::getClassKey()); // st [classKey] = cl. Stack: ns, co, cl, st - - if (Security::hideMetatables()) - { - lua_pushnil(L); - rawsetfield(L, -2, "__metatable"); - } - } - - //========================================================================================= - /** - * @brief lua_CFunction to construct a class object wrapped in a container. - */ - template - static int ctorContainerProxy(lua_State* L) - { - using T = typename ContainerTraits::Type; - - T* object = detail::constructor::call(detail::make_arguments_list(L)); - - std::error_code ec; - if (! detail::UserdataSharedHelper::push(L, object, ec)) - luaL_error(L, ec.message().c_str()); - - return 1; - } - - //========================================================================================= - /** - * @brief lua_CFunction to construct a class object in-place in the userdata. - */ - template - static int ctorPlacementProxy(lua_State* L) - { - std::error_code ec; - detail::UserdataValue* value = detail::UserdataValue::place(L, ec); - if (! value) - luaL_error(L, ec.message().c_str()); - - detail::constructor::call(value->getObject(), detail::make_arguments_list(L)); - - value->commit(); - - return 1; - } - - //========================================================================================= - /** - * @brief Asserts on stack state. - */ - void assertStackState() const - { - // Stack: const table (co), class table (cl), static table (st) - assert(lua_istable(L, -3)); - assert(lua_istable(L, -2)); - assert(lua_istable(L, -1)); - } - }; - - //============================================================================================= - /** - * @brief Provides a class registration in a lua_State. - * - * After construction the Lua stack holds these objects: - * -1 static table - * -2 class table - * -3 const table - * -4 enclosing namespace table - */ - template - class Class : public ClassBase - { - public: - //========================================================================================= - - /** - * @brief Register a new class or add to an existing class registration. - * - * @param name The new class name. - * @param parent A parent namespace object. - */ - Class(const char* name, Namespace& parent) - : ClassBase(parent) - { - assert(name != nullptr); - assert(lua_istable(L, -1)); // Stack: namespace table (ns) - - rawgetfield(L, -1, name); // Stack: ns, static table (st) | nil - - if (lua_isnil(L, -1)) // Stack: ns, nil - { - lua_pop(L, 1); // Stack: ns - - createConstTable(name); // Stack: ns, const table (co) - lua_pushcfunction(L, &detail::gc_metamethod); // Stack: ns, co, function - rawsetfield(L, -2, "__gc"); // co ["__gc"] = function. Stack: ns, co - ++m_stackSize; - - createClassTable(name); // Stack: ns, co, class table (cl) - lua_pushcfunction(L, &detail::gc_metamethod); // Stack: ns, co, cl, function - rawsetfield(L, -2, "__gc"); // cl ["__gc"] = function. Stack: ns, co, cl - ++m_stackSize; - - createStaticTable(name); // Stack: ns, co, cl, st - ++m_stackSize; - - // Map T back to its tables. - lua_pushvalue(L, -1); // Stack: ns, co, cl, st, st - lua_rawsetp(L, LUA_REGISTRYINDEX, detail::getStaticRegistryKey()); // Stack: ns, co, cl, st - lua_pushvalue(L, -2); // Stack: ns, co, cl, st, cl - lua_rawsetp(L, LUA_REGISTRYINDEX, detail::getClassRegistryKey()); // Stack: ns, co, cl, st - lua_pushvalue(L, -3); // Stack: ns, co, cl, st, co - lua_rawsetp(L, LUA_REGISTRYINDEX, detail::getConstRegistryKey()); // Stack: ns, co, cl, st - } - else - { - assert(lua_istable(L, -1)); // Stack: ns, st - ++m_stackSize; - - // Map T back from its stored tables - - lua_rawgetp(L, LUA_REGISTRYINDEX, detail::getConstRegistryKey()); // Stack: ns, st, co - lua_insert(L, -2); // Stack: ns, co, st - ++m_stackSize; - - lua_rawgetp(L, LUA_REGISTRYINDEX, detail::getClassRegistryKey()); // Stack: ns, co, st, cl - lua_insert(L, -2); // Stack: ns, co, cl, st - ++m_stackSize; - } - } - - //========================================================================================= - /** - * @brief Derive a new class. - * - * @param name The class name. - * @param parent A parent namespace object. - * @param staticKey Key where the class is stored. - */ - Class(const char* name, Namespace& parent, void const* const staticKey) - : ClassBase(parent) - { - assert(name != nullptr); - assert(lua_istable(L, -1)); // Stack: namespace table (ns) - - createConstTable(name); // Stack: ns, const table (co) - lua_pushcfunction(L, &detail::gc_metamethod); // Stack: ns, co, function - rawsetfield(L, -2, "__gc"); // co ["__gc"] = function. Stack: ns, co - ++m_stackSize; - - createClassTable(name); // Stack: ns, co, class table (cl) - lua_pushcfunction(L, &detail::gc_metamethod); // Stack: ns, co, cl, function - rawsetfield(L, -2, "__gc"); // cl ["__gc"] = function. Stack: ns, co, cl - ++m_stackSize; - - createStaticTable(name); // Stack: ns, co, cl, st - ++m_stackSize; - - lua_rawgetp( L, LUA_REGISTRYINDEX, staticKey); // Stack: ns, co, cl, st, parent st (pst) | nil - if (lua_isnil(L, -1)) // Stack: ns, co, cl, st, nil - { - ++m_stackSize; - - throw_or_assert("Base class is not registered"); - return; - } - - assert(lua_istable(L, -1)); // Stack: ns, co, cl, st, pst - - lua_rawgetp(L, -1, detail::getClassKey()); // Stack: ns, co, cl, st, pst, parent cl (pcl) - assert(lua_istable(L, -1)); - - lua_rawgetp(L, -1, detail::getConstKey()); // Stack: ns, co, cl, st, pst, pcl, parent co (pco) - assert(lua_istable(L, -1)); - - lua_rawsetp(L, -6, detail::getParentKey()); // co [parentKey] = pco. Stack: ns, co, cl, st, pst, pcl - lua_rawsetp(L, -4, detail::getParentKey()); // cl [parentKey] = pcl. Stack: ns, co, cl, st, pst - lua_rawsetp(L, -2, detail::getParentKey()); // st [parentKey] = pst. Stack: ns, co, cl, st - - lua_pushvalue(L, -1); // Stack: ns, co, cl, st, st - lua_rawsetp(L, LUA_REGISTRYINDEX, detail::getStaticRegistryKey()); // Stack: ns, co, cl, st - lua_pushvalue(L, -2); // Stack: ns, co, cl, st, cl - lua_rawsetp(L, LUA_REGISTRYINDEX, detail::getClassRegistryKey()); // Stack: ns, co, cl, st - lua_pushvalue(L, -3); // Stack: ns, co, cl, st, co - lua_rawsetp(L, LUA_REGISTRYINDEX, detail::getConstRegistryKey()); // Stack: ns, co, cl, st - } - - //========================================================================================= - /** - * @brief Continue registration in the enclosing namespace. - * - * @returns A parent registration object. - */ - Namespace endClass() - { - assert(m_stackSize > 3); - - m_stackSize -= 3; - lua_pop(L, 3); - return Namespace(*this); - } - - //========================================================================================= - /** - * @brief Add or replace a static property. - * - * @tparam U The type of the property. - * - * @param name The property name. - * @param value A property value pointer. - * @param isWritable True for a read-write, false for read-only property. - * - * @returns This class registration object. - */ - template - Class& addStaticProperty(const char* name, U* value, bool isWritable = true) - { - assert(name != nullptr); - assertStackState(); // Stack: const table (co), class table (cl), static table (st) - - lua_pushlightuserdata(L, value); // Stack: co, cl, st, pointer - lua_pushcclosure(L, &detail::property_getter::call, 1); // Stack: co, cl, st, getter - detail::add_property_getter(L, name, -2); // Stack: co, cl, st - - if (isWritable) - { - lua_pushlightuserdata(L, value); // Stack: co, cl, st, ps, pointer - lua_pushcclosure(L, &detail::property_setter::call, 1); // Stack: co, cl, st, ps, setter - } - else - { - lua_pushstring(L, name); // Stack: co, cl, st, name - lua_pushcclosure(L, &detail::read_only_error, 1); // Stack: co, cl, st, function - } - - detail::add_property_setter(L, name, -2); // Stack: co, cl, st - - return *this; - } - - //========================================================================================= - /** - * @brief Add or replace a static property member. - * - * @tparam U The type of the property. - * - * @param name The property name. - * @param get A property getter function pointer. - * @param set A property setter function pointer, optional, nullable. Omit or pass nullptr for a read-only property. - * - * @returns This class registration object. - */ - template - Class& addStaticProperty(const char* name, U (*get)(), void (*set)(U) = nullptr) - { - assert(name != nullptr); - assertStackState(); // Stack: const table (co), class table (cl), static table (st) - - lua_pushlightuserdata(L, reinterpret_cast(get)); // Stack: co, cl, st, function ptr - lua_pushcclosure(L, &detail::invoke_proxy_function, 1); // Stack: co, cl, st, getter - detail::add_property_getter(L, name, -2); // Stack: co, cl, st - - if (set != nullptr) - { - lua_pushlightuserdata(L, reinterpret_cast(set)); // Stack: co, cl, st, function ptr - lua_pushcclosure(L, &detail::invoke_proxy_function, 1); // Stack: co, cl, st, setter - } - else - { - lua_pushstring(L, name); // Stack: co, cl, st, ps, name - lua_pushcclosure(L, &detail::read_only_error, 1); // Stack: co, cl, st, function - } - - detail::add_property_setter(L, name, -2); // Stack: co, cl, st - - return *this; - } - - //========================================================================================= - /** - * @brief Add or replace a static member function. - */ - template >> - Class& addStaticFunction(const char* name, Function fp) - { - assert(name != nullptr); - assertStackState(); // Stack: const table (co), class table (cl), static table (st) - - lua_pushlightuserdata(L, reinterpret_cast(fp)); // Stack: co, cl, st, function ptr - lua_pushcclosure(L, &detail::invoke_proxy_function, 1); // co, cl, st, function - rawsetfield(L, -2, name); // co, cl, st - - return *this; - } - - //========================================================================================= - /** - * @brief Add or replace a static member function for constructible by std::function. - */ - template >> - Class addStaticFunction(const char* name, Function function) - { - using FnType = decltype(function); - - assert(name != nullptr); - assertStackState(); // Stack: const table (co), class table (cl), static table (st) - - lua_newuserdata_aligned(L, std::move(function)); // Stack: co, cl, st, function userdata (ud) - lua_newtable(L); // Stack: co, cl, st, ud, ud metatable (mt) - lua_pushcfunction(L, &lua_deleteuserdata_aligned); // Stack: co, cl, st, ud, mt, gc function - rawsetfield(L, -2, "__gc"); // Stack: co, cl, st, ud, mt - lua_setmetatable(L, -2); // Stack: co, cl, st, ud - lua_pushcclosure(L, &detail::invoke_proxy_functor, 1); // Stack: co, cl, st, function - rawsetfield(L, -2, name); // Stack: co, cl, st - - return *this; - } - - //========================================================================================= - /** - * @brief Add or replace a lua_CFunction. - * - * @param name The name of the function. - * @param fp A C-function pointer. - * - * @returns This class registration object. - */ - Class& addStaticFunction(const char* name, lua_CFunction fp) - { - assert(name != nullptr); - assertStackState(); // Stack: const table (co), class table (cl), static table (st) - - lua_pushcfunction(L, fp); // co, cl, st, function - rawsetfield(L, -2, name); // co, cl, st - - return *this; - } - - //========================================================================================= - /** - * @brief Add or replace a property member. - */ - template - Class& addProperty(const char* name, U V::*mp, bool isWritable = true) - { - static_assert(std::is_base_of_v); - - using MemberPtrType = decltype(mp); - - assert(name != nullptr); - assertStackState(); // Stack: const table (co), class table (cl), static table (st) - - new (lua_newuserdata(L, sizeof(MemberPtrType))) MemberPtrType(mp); // Stack: co, cl, st, field ptr - lua_pushcclosure(L, &detail::property_getter::call, 1); // Stack: co, cl, st, getter - lua_pushvalue(L, -1); // Stack: co, cl, st, getter, getter - detail::add_property_getter(L, name, -5); // Stack: co, cl, st, getter - detail::add_property_getter(L, name, -3); // Stack: co, cl, st - - if (isWritable) - { - new (lua_newuserdata(L, sizeof(MemberPtrType))) MemberPtrType(mp); // Stack: co, cl, st, field ptr - lua_pushcclosure(L, &detail::property_setter::call, 1); // Stack: co, cl, st, setter - detail::add_property_setter(L, name, -3); // Stack: co, cl, st - } - - return *this; - } - - //========================================================================================= - /** - * @brief Add or replace a property member. - */ - template - Class& addProperty(const char* name, TG (T::*get)() const, void (T::*set)(TS) = nullptr) - { - using GetType = TG (T::*)() const; - using SetType = void (T::*)(TS); - - assert(name != nullptr); - assertStackState(); // Stack: const table (co), class table (cl), static table (st) - - new (lua_newuserdata(L, sizeof(GetType))) GetType(get); // Stack: co, cl, st, funcion ptr - lua_pushcclosure(L, &detail::invoke_const_member_function, 1); // Stack: co, cl, st, getter - lua_pushvalue(L, -1); // Stack: co, cl, st, getter, getter - detail::add_property_getter(L, name, -5); // Stack: co, cl, st, getter - detail::add_property_getter(L, name, -3); // Stack: co, cl, st - - if (set != nullptr) - { - new (lua_newuserdata(L, sizeof(SetType))) SetType(set); // Stack: co, cl, st, function ptr - lua_pushcclosure(L, &detail::invoke_member_function, 1); // Stack: co, cl, st, setter - detail::add_property_setter(L, name, -3); // Stack: co, cl, st - } - - return *this; - } - - //========================================================================================= - /** - * @brief Add or replace a property member. - */ - template - Class& addProperty(const char* name, TG (T::*get)(lua_State*) const, void (T::*set)(TS, lua_State*) = nullptr) - { - using GetType = TG (T::*)(lua_State*) const; - using SetType = void (T::*)(TS, lua_State*); - - assert(name != nullptr); - assertStackState(); // Stack: const table (co), class table (cl), static table (st) - - new (lua_newuserdata(L, sizeof(GetType))) GetType(get); // Stack: co, cl, st, funcion ptr - lua_pushcclosure(L, &detail::invoke_const_member_function, 1); // Stack: co, cl, st, getter - lua_pushvalue(L, -1); // Stack: co, cl, st, getter, getter - detail::add_property_getter(L, name, -5); // Stack: co, cl, st, getter - detail::add_property_getter(L, name, -3); // Stack: co, cl, st - - if (set != nullptr) - { - new (lua_newuserdata(L, sizeof(SetType))) SetType(set); // Stack: co, cl, st, function ptr - lua_pushcclosure(L, &detail::invoke_member_function, 1); // Stack: co, cl, st, setter - detail::add_property_setter(L, name, -3); // Stack: co, cl, st - } - - return *this; - } - - //========================================================================================= - /** - * @brief Add or replace a property member, by proxy. - * - * When a class is closed for modification and does not provide (or cannot provide) the function signatures necessary to implement - * get or set for a property, this will allow non-member functions act as proxies. - * - * Both the get and the set functions require a T const* and T* in the first argument respectively. - */ - template - Class& addProperty(const char* name, TG (*get)(T const*), void (*set)(T*, TS) = nullptr) - { - assert(name != nullptr); - assertStackState(); // Stack: const table (co), class table (cl), static table (st) - - lua_pushlightuserdata(L, reinterpret_cast(get)); // Stack: co, cl, st, function ptr - lua_pushcclosure(L, &detail::invoke_proxy_function, 1); // Stack: co, cl, st, getter - lua_pushvalue(L, -1); // Stack: co, cl, st,, getter, getter - detail::add_property_getter(L, name, -5); // Stack: co, cl, st, getter - detail::add_property_getter(L, name, -3); // Stack: co, cl, st - - if (set != nullptr) - { - lua_pushlightuserdata( L, reinterpret_cast(set)); // Stack: co, cl, st, function ptr - lua_pushcclosure(L, &detail::invoke_proxy_function, 1); // Stack: co, cl, st, setter - detail::add_property_setter(L, name, -3); // Stack: co, cl, st - } - - return *this; - } - - //========================================================================================= - /** - * @brief Add or replace a property member, by proxy C-function. - * - * When a class is closed for modification and does not provide (or cannot provide) the function signatures necessary to implement - * get or set for a property, this will allow non-member functions act as proxies. - * - * The object userdata ('this') value is at the index 1. - * The new value for set function is at the index 2. - */ - Class& addProperty(const char* name, lua_CFunction get, lua_CFunction set = nullptr) - { - assert(name != nullptr); - assertStackState(); // Stack: const table (co), class table (cl), static table (st) - - lua_pushcfunction(L, get); - lua_pushvalue(L, -1); // Stack: co, cl, st,, getter, getter - detail::add_property_getter(L, name, -5); // Stack: co, cl, st,, getter - detail::add_property_getter(L, name, -3); // Stack: co, cl, st, - - if (set != nullptr) - { - lua_pushcfunction(L, set); - detail::add_property_setter(L, name, -3); // Stack: co, cl, st, - } - - return *this; - } - - //========================================================================================= - /** - * @brief Add or replace a property member, by constructible by std::function. - */ - template >> - Class& addProperty(const char* name, Getter get) - { - using FirstArg = detail::function_argument_t<0, Getter>; - static_assert(std::is_same_v>, T>); - - assert(name != nullptr); - assertStackState(); // Stack: const table (co), class table (cl), static table (st) - - using GetType = decltype(get); - - lua_newuserdata_aligned(L, std::move(get)); // Stack: co, cl, st, function userdata (ud) - lua_newtable(L); // Stack: co, cl, st, ud, ud metatable (mt) - lua_pushcfunction(L, &lua_deleteuserdata_aligned); // Stack: co, cl, st, ud, mt, gc function - rawsetfield(L, -2, "__gc"); // Stack: co, cl, st, ud, mt - lua_setmetatable(L, -2); // Stack: co, cl, st, ud - lua_pushcclosure(L, &detail::invoke_proxy_functor, 1); // Stack: co, cl, st, getter - lua_pushvalue(L, -1); // Stack: co, cl, st, getter, getter - detail::add_property_getter(L, name, -4); // Stack: co, cl, st, getter - detail::add_property_getter(L, name, -4); // Stack: co, cl, st - - return *this; - } - - template && !std::is_pointer_v>> - Class& addProperty(const char* name, Getter get, Setter set) - { - addProperty(name, std::move(get)); - - using FirstArg = detail::function_argument_t<0, Setter>; - static_assert(std::is_same_v>, T>); - - assert(name != nullptr); - assertStackState(); // Stack: const table (co), class table (cl), static table (st) - - using SetType = decltype(set); - - lua_newuserdata_aligned(L, std::move(set)); // Stack: co, cl, st, function userdata (ud) - lua_newtable(L); // Stack: co, cl, st, ud, ud metatable (mt) - lua_pushcfunction(L, &lua_deleteuserdata_aligned); // Stack: co, cl, st, ud, mt, gc function - rawsetfield(L, -2, "__gc"); // Stack: co, cl, st, ud, mt - lua_setmetatable(L, -2); // Stack: co, cl, st, ud - lua_pushcclosure(L, &detail::invoke_proxy_functor, 1); // Stack: co, cl, st, setter - detail::add_property_setter(L, name, -3); // Stack: co, cl, st - - return *this; - } - - //========================================================================================= - /** - * @brief Add or replace a namespace function by convertible to std::function (capturing lambdas). - */ - template != 0>> - Class addFunction(const char* name, Function function) - { - using FnType = decltype(function); - - using FirstArg = detail::function_argument_t<0, Function>; - static_assert(std::is_same_v>, T>); - - assert(name != nullptr); - assertStackState(); // Stack: const table (co), class table (cl), static table (st) - - if (name == std::string_view("__gc")) - { - throw_or_assert("__gc metamethod registration is forbidden"); - return *this; - } - - lua_newuserdata_aligned(L, std::move(function)); // Stack: co, cl, st, function userdata (ud) - lua_newtable(L); // Stack: co, cl, st, ud, ud metatable (mt) - lua_pushcfunction(L, &lua_deleteuserdata_aligned); // Stack: co, cl, st, ud, mt, gc function - rawsetfield(L, -2, "__gc"); // Stack: co, cl, st, ud, mt - lua_setmetatable(L, -2); // Stack: co, cl, st, ud - - lua_pushcclosure(L, &detail::invoke_proxy_functor, 1); // Stack: co, cl, st, function - - if constexpr (! std::is_const_v>>) - { - rawsetfield(L, -3, name); // Stack: co, cl, st - } - else - { - lua_pushvalue(L, -1); // Stack: co, cl, st, function, function - rawsetfield(L, -4, name); // Stack: co, cl, st, function - rawsetfield(L, -4, name); // Stack: co, cl, st - } - - return *this; - } - - //========================================================================================= - /** - * @brief Add or replace a member function. - */ - template - Class& addFunction(const char* name, ReturnType (U::*mf)(Params...)) - { - static_assert(std::is_base_of_v); - - using MemFn = decltype(mf); - - assert(name != nullptr); - assertStackState(); // Stack: const table (co), class table (cl), static table (st) - - if (name == std::string_view("__gc")) - { - throw_or_assert("__gc metamethod registration is forbidden"); - return *this; - } - - new (lua_newuserdata(L, sizeof(MemFn))) MemFn(mf); - lua_pushcclosure(L, &detail::invoke_member_function, 1); - rawsetfield(L, -3, name); // class table - - return *this; - } - - template - Class& addFunction(const char* name, ReturnType (U::*mf)(Params...) const) - { - static_assert(std::is_base_of_v); - - using MemFn = decltype(mf); - - assert(name != nullptr); - assertStackState(); // Stack: const table (co), class table (cl), static table (st) - - if (name == std::string_view("__gc")) - { - throw_or_assert("__gc metamethod registration is forbidden"); - return *this; - } - - new (lua_newuserdata(L, sizeof(MemFn))) MemFn(mf); - lua_pushcclosure(L, &detail::invoke_const_member_function, 1); - lua_pushvalue(L, -1); - rawsetfield(L, -5, name); // const table - rawsetfield(L, -3, name); // class table - - return *this; - } - - //========================================================================================= - /** - * @brief Add or replace a proxy function. - */ - template - Class& addFunction(const char* name, ReturnType (*proxyFn)(T* object, Params...)) - { - using FnType = decltype(proxyFn); - - assert(name != nullptr); - assertStackState(); // Stack: const table (co), class table (cl), static table (st) - - if (name == std::string_view("__gc")) - { - throw_or_assert("__gc metamethod registration is forbidden"); - return *this; - } - - lua_pushlightuserdata(L, reinterpret_cast(proxyFn)); // Stack: co, cl, st, function ptr - lua_pushcclosure(L, &detail::invoke_proxy_function, 1); // Stack: co, cl, st, function - rawsetfield(L, -3, name); // Stack: co, cl, st - - return *this; - } - - template - Class& addFunction(const char* name, ReturnType (*proxyFn)(const T* object, Params...)) - { - using FnType = decltype(proxyFn); - - assert(name != nullptr); - assertStackState(); // Stack: const table (co), class table (cl), static table (st) - - if (name == std::string_view("__gc")) - { - throw_or_assert("__gc metamethod registration is forbidden"); - return *this; - } - - lua_pushlightuserdata(L, reinterpret_cast(proxyFn)); // Stack: co, cl, st, function ptr - lua_pushcclosure(L, &detail::invoke_proxy_function, 1); // Stack: co, cl, st, function - lua_pushvalue(L, -1); // Stack: co, cl, st, function, function - rawsetfield(L, -4, name); // Stack: co, cl, st, function - rawsetfield(L, -4, name); // Stack: co, cl, st - - return *this; - } - - //========================================================================================= - /** - * @brief Add or replace a member lua_CFunction. - */ - template - Class& addFunction(const char* name, int (U::*mfp)(lua_State*)) - { - static_assert(std::is_base_of_v); - - using F = decltype(mfp); - - assert(name != nullptr); - assertStackState(); // Stack: const table (co), class table (cl), static table (st) - - if (name == std::string_view("__gc")) - { - throw_or_assert("__gc metamethod registration is forbidden"); - return *this; - } - - new (lua_newuserdata(L, sizeof(mfp))) F(mfp); // Stack: co, cl, st, function ptr - lua_pushcclosure(L, &detail::invoke_member_cfunction, 1); // Stack: co, cl, st, function - rawsetfield(L, -3, name); // Stack: co, cl, st - - return *this; - } - - //========================================================================================= - /** - * @brief Add or replace a const member lua_CFunction. - */ - template - Class& addFunction(const char* name, int (U::*mfp)(lua_State*) const) - { - static_assert(std::is_base_of_v); - - using F = decltype(mfp); - - assert(name != nullptr); - assertStackState(); // Stack: const table (co), class table (cl), static table (st) - - if (name == std::string_view("__gc")) - { - throw_or_assert("__gc metamethod registration is forbidden"); - return *this; - } - - new (lua_newuserdata(L, sizeof(mfp))) F(mfp); - lua_pushcclosure(L, &detail::invoke_const_member_cfunction, 1); - lua_pushvalue(L, -1); // Stack: co, cl, st, function, function - rawsetfield(L, -4, name); // Stack: co, cl, st, function - rawsetfield(L, -4, name); // Stack: co, cl, st - - return *this; - } - - //========================================================================================= - /** - * @brief Add or replace a free lua_CFunction that works as a member. - * - * This object is at top of the stack, then all other arguments. - */ - Class& addFunction(const char* name, lua_CFunction fp) - { - assert(name != nullptr); - assertStackState(); // Stack: const table (co), class table (cl), static table (st) - - if (name == std::string_view("__gc")) - { - throw_or_assert("__gc metamethod registration is forbidden"); - return *this; - } - - lua_pushcfunction(L, fp); // Stack: co, cl, st, function - rawsetfield(L, -3, name); // Stack: co, cl, st - - return *this; - } - - //========================================================================================= - /** - * @brief Add or replace a primary Constructor. - * - * The primary Constructor is invoked when calling the class type table like a function. - * - * The template parameter should be a function pointer type that matches the desired Constructor (since you can't take the - * address of a Constructor and pass it as an argument). - */ - template - Class& addConstructor() - { - assertStackState(); // Stack: const table (co), class table (cl), static table (st) - - lua_pushcclosure(L, &ctorContainerProxy, C>, 0); - rawsetfield(L, -2, "__call"); - - return *this; - } - - template - Class& addConstructor() - { - assertStackState(); // Stack: const table (co), class table (cl), static table (st) - - lua_pushcclosure(L, &ctorPlacementProxy, T>, 0); - rawsetfield(L, -2, "__call"); - - return *this; - } - - //========================================================================================= - /** - * @brief Add or replace a factory. - * - * The primary Constructor is invoked when calling the class type table like a function. - * - * The template parameter should be a function pointer type that matches the desired Constructor (since you can't take the - * address of a Constructor and pass it as an argument). - */ - template - Class addConstructor(Function function) - { - assertStackState(); // Stack: const table (co), class table (cl), static table (st) - - auto factory = [function = std::move(function)](lua_State* L) -> T* - { - std::error_code ec; - detail::UserdataValue* value = detail::UserdataValue::place(L, ec); - if (! value) - luaL_error(L, ec.message().c_str()); - - using FnTraits = detail::function_traits; - using FnArgs = detail::remove_first_type_t; - - T* obj = detail::factory::call(value->getObject(), function, detail::make_arguments_list(L)); - - value->commit(); - - return obj; - }; - - using FactoryFnType = decltype(factory); - - lua_newuserdata_aligned(L, std::move(factory)); // Stack: co, cl, st, function userdata (ud) - lua_newtable(L); // Stack: co, cl, st, ud, ud metatable (mt) - lua_pushcfunction(L, &lua_deleteuserdata_aligned); // Stack: co, cl, st, ud, mt, gc function - rawsetfield(L, -2, "__gc"); // Stack: co, cl, st, ud, mt - lua_setmetatable(L, -2); // Stack: co, cl, st, ud - - lua_pushcclosure(L, &detail::invoke_proxy_functor, 1); // Stack: co, cl, st, function - rawsetfield(L, -2, "__call"); // Stack: co, cl, st - - return *this; - } - }; - -private: - struct FromStack {}; - - //============================================================================================= - /** - * @brief Open the global namespace for registrations. - * - * @param L A Lua state. - */ - explicit Namespace(lua_State* L) - : Registrar(L) - { - lua_getglobal(L, "_G"); - - ++m_stackSize; - } - - //============================================================================================= - /** - * @brief Open the a namespace for registrations from a table on top of the stack. - * - * @param L A Lua state. - */ - Namespace(lua_State* L, FromStack) - : Registrar(L, 1) - { - assert(lua_istable(L, -1)); - - { - lua_pushvalue(L, -1); // Stack: ns, mt - - // ns.__metatable = ns - lua_setmetatable(L, -2); // Stack: ns, mt - - // ns.__index = index_metamethod - lua_pushcfunction(L, &detail::index_metamethod); - rawsetfield(L, -2, "__index"); // Stack: ns - - lua_newtable(L); // Stack: ns, mt, propget table (pg) - lua_rawsetp(L, -2, detail::getPropgetKey()); // ns [propgetKey] = pg. Stack: ns - - lua_newtable(L); // Stack: ns, mt, propset table (ps) - lua_rawsetp(L, -2, detail::getPropsetKey()); // ns [propsetKey] = ps. Stack: ns - } - - ++m_stackSize; - } - - //============================================================================================= - /** - * @brief Open a namespace for registrations. - * - * The namespace is created if it doesn't already exist. - * - * @param name The namespace name. - * @param parent The parent namespace object. - * - * @pre The parent namespace is at the top of the Lua stack. - */ - Namespace(const char* name, Namespace& parent) - : Registrar(parent) - { - assert(name != nullptr); - assert(lua_istable(L, -1)); // Stack: parent namespace (pns) - - rawgetfield(L, -1, name); // Stack: pns, namespace (ns) | nil - - if (lua_isnil(L, -1)) // Stack: pns, nil - { - lua_pop(L, 1); // Stack: pns - - lua_newtable(L); // Stack: pns, ns - lua_pushvalue(L, -1); // Stack: pns, ns, mt - - // ns.__metatable = ns - lua_setmetatable(L, -2); // Stack: pns, ns - - // ns.__index = index_metamethod - lua_pushcfunction(L, &detail::index_metamethod); - rawsetfield(L, -2, "__index"); // Stack: pns, ns - - // ns.__newindex = newindex_static_metamethod - lua_pushcfunction(L, &detail::newindex_static_metamethod); - rawsetfield(L, -2, "__newindex"); // Stack: pns, ns - - lua_newtable(L); // Stack: pns, ns, propget table (pg) - lua_rawsetp(L, -2, detail::getPropgetKey()); // ns [propgetKey] = pg. Stack: pns, ns - - lua_newtable(L); // Stack: pns, ns, propset table (ps) - lua_rawsetp(L, -2, detail::getPropsetKey()); // ns [propsetKey] = ps. Stack: pns, ns - - // pns [name] = ns - lua_pushvalue(L, -1); // Stack: pns, ns, ns - rawsetfield(L, -3, name); // Stack: pns, ns - } - - ++m_stackSize; - } - - //============================================================================================= - /** - * @brief Close the class and continue the namespace registrations. - * - * @param child A child class registration object. - */ - explicit Namespace(ClassBase& child) - : Registrar(child) - { - } - - using Registrar::operator=; - -public: - //============================================================================================= - /** - * @brief Retrieve the global namespace. - * - * It is recommended to put your namespace inside the global namespace, and then add your classes and functions to it, rather than - * adding many classes and functions directly to the global namespace. - * - * @param L A Lua state. - * - * @returns A namespace registration object. - */ - static Namespace getGlobalNamespace(lua_State* L) - { - return Namespace(L); - } - - /** - * @brief Retrieve the namespace on top of the stack. - * - * You should have a table on top of the stack before calling this function. It will then use the table there as destination for registrations. - * - * @param L A Lua state. - * - * @returns A namespace registration object. - */ - static Namespace getNamespaceFromStack(lua_State* L) - { - return Namespace(L, FromStack{}); - } - - //============================================================================================= - /** - * @brief Open a new or existing namespace for registrations. - * - * @param name The namespace name. - * - * @returns A namespace registration object. - */ - Namespace beginNamespace(const char* name) - { - assertIsActive(); - return Namespace(name, *this); - } - - //============================================================================================= - /** - * @brief Continue namespace registration in the parent. - * - * Do not use this on the global namespace. - * - * @returns A parent namespace registration object. - */ - Namespace endNamespace() - { - if (m_stackSize == 1) - { - throw_or_assert("endNamespace() called on global namespace"); - - return Namespace(*this); - } - - assert(m_stackSize > 1); - --m_stackSize; - lua_pop(L, 1); - return Namespace(*this); - } - - //============================================================================================= - /** - * @brief Add or replace a property. - * - * @param name The property name. - * @param value A value pointer. - * @param isWritable True for a read-write, false for read-only property. - * - * @returns This namespace registration object. - */ - template - Namespace& addProperty(const char* name, T* value, bool isWritable = true) - { - if (m_stackSize == 1) - { - throw_or_assert("addProperty() called on global namespace"); - - return *this; - } - - assert(name != nullptr); - assert(lua_istable(L, -1)); // Stack: namespace table (ns) - - lua_pushlightuserdata(L, value); // Stack: ns, pointer - lua_pushcclosure(L, &detail::property_getter::call, 1); // Stack: ns, getter - detail::add_property_getter(L, name, -2); // Stack: ns - - if (isWritable) - { - lua_pushlightuserdata(L, value); // Stack: ns, pointer - lua_pushcclosure(L, &detail::property_setter::call, 1); // Stack: ns, setter - } - else - { - lua_pushstring(L, name); // Stack: ns, ps, name - lua_pushcclosure(L, &detail::read_only_error, 1); // Stack: ns, function - } - - detail::add_property_setter(L, name, -2); // Stack: ns - - return *this; - } - - //============================================================================================= - /** - * @brief Add or replace a property. - * - * If the set function is omitted or null, the property is read-only. - * - * @param name The property name. - * @param get A pointer to a property getter function. - * @param set A pointer to a property setter function, optional. - * - * @returns This namespace registration object. - */ - template - Namespace& addProperty(const char* name, TG (*get)(), void (*set)(TS) = nullptr) - { - if (m_stackSize == 1) - { - throw_or_assert("addProperty() called on global namespace"); - - return *this; - } - - assert(name != nullptr); - assert(lua_istable(L, -1)); // Stack: namespace table (ns) - - lua_pushlightuserdata(L, reinterpret_cast(get)); // Stack: ns, function ptr - lua_pushcclosure(L, &detail::invoke_proxy_function, 1); // Stack: ns, getter - detail::add_property_getter(L, name, -2); - - if (set != nullptr) - { - lua_pushlightuserdata(L, reinterpret_cast(set)); // Stack: ns, function ptr - lua_pushcclosure(L, &detail::invoke_proxy_function, 1); - } - else - { - lua_pushstring(L, name); - lua_pushcclosure(L, &detail::read_only_error, 1); - } - - detail::add_property_setter(L, name, -2); - - return *this; - } - - //============================================================================================= - /** - * @brief Add or replace a readonly property. - * - * @param name The property name. - * @param get A pointer to a property getter function. - * - * @returns This namespace registration object. - */ - template - Namespace& addProperty(const char* name, Getter get) - { - using GetType = decltype(get); - - assert(name != nullptr); - assert(lua_istable(L, -1)); // Stack: namespace table (ns) - - lua_newuserdata_aligned(L, std::move(get)); // Stack: ns, function userdata (ud) - lua_newtable(L); // Stack: ns, ud, ud metatable (mt) - lua_pushcfunction(L, &lua_deleteuserdata_aligned); // Stack: ns, ud, mt, gc function - rawsetfield(L, -2, "__gc"); // Stack: ns, ud, mt - lua_setmetatable(L, -2); // Stack: ns, ud - lua_pushcclosure(L, &detail::invoke_proxy_functor, 1); // Stack: ns, ud, getter - detail::add_property_getter(L, name, -2); // Stack: ns, ud, getter - - lua_pushstring(L, name); // Stack: ns, name - lua_pushcclosure(L, &detail::read_only_error, 1); // Stack: ns, name, function - detail::add_property_setter(L, name, -2); // Stack: ns - - return *this; - } - - /** - * @brief Add or replace a mutable property. - * - * @param name The property name. - * @param get A pointer to a property getter function. - * @param set A pointer to a property setter function. - * - * @returns This namespace registration object. - */ - template - Namespace& addProperty(const char* name, Getter get, Setter set) - { - assert(name != nullptr); - assert(lua_istable(L, -1)); // Stack: namespace table (ns) - - addProperty(name, std::move(get)); - - using SetType = decltype(set); - - lua_newuserdata_aligned(L, std::move(set)); // Stack: ns, function userdata (ud) - lua_newtable(L); // Stack: ns, ud, ud metatable (mt) - lua_pushcfunction(L, &lua_deleteuserdata_aligned); // Stack: ns, ud, mt, gc function - rawsetfield(L, -2, "__gc"); // Stack: ns, ud, mt - lua_setmetatable(L, -2); // Stack: ns, ud - lua_pushcclosure(L, &detail::invoke_proxy_functor, 1); // Stack: ns, ud, getter - detail::add_property_setter(L, name, -2); // Stack: ns, ud, getter - - return *this; - } - - //============================================================================================= - /** - * @brief Add or replace a property. - * - * If the set function is omitted or null, the property is read-only. - * - * @param name The property name. - * @param get A pointer to a property getter function. - * @param set A pointer to a property setter function, optional. - * - * @returns This namespace registration object. - */ - Namespace& addProperty(const char* name, lua_CFunction get, lua_CFunction set = nullptr) - { - assert(name != nullptr); - assert(lua_istable(L, -1)); // Stack: namespace table (ns) - - lua_pushcfunction(L, get); // Stack: ns, getter - detail::add_property_getter(L, name, -2); // Stack: ns - - if (set != nullptr) - { - lua_pushcfunction(L, set); // Stack: ns, setter - detail::add_property_setter(L, name, -2); // Stack: ns - } - else - { - lua_pushstring(L, name); // Stack: ns, name - lua_pushcclosure(L, &detail::read_only_error, 1); // Stack: ns, name, function - detail::add_property_setter(L, name, -2); // Stack: ns - } - - return *this; - } - - //============================================================================================= - /** - * @brief Add or replace a namespace function by convertible to std::function. - */ - template - Namespace& addFunction(const char* name, Function function) - { - using FnType = decltype(function); - - assert(name != nullptr); - assert(lua_istable(L, -1)); // Stack: namespace table (ns) - - lua_newuserdata_aligned(L, std::move(function)); // Stack: ns, function userdata (ud) - lua_newtable(L); // Stack: ns, ud, ud metatable (mt) - lua_pushcfunction(L, &lua_deleteuserdata_aligned); // Stack: ns, ud, mt, gc function - rawsetfield(L, -2, "__gc"); // Stack: ns, ud, mt - lua_setmetatable(L, -2); // Stack: ns, ud - lua_pushcclosure(L, &detail::invoke_proxy_functor, 1); // Stack: ns, function - rawsetfield(L, -2, name); // Stack: ns - - return *this; - } - - //============================================================================================= - /** - * @brief Add or replace a free function. - */ - template - Namespace& addFunction(const char* name, ReturnType (*fp)(Params...)) - { - using FnType = decltype(fp); - - assert(name != nullptr); - assert(lua_istable(L, -1)); // Stack: namespace table (ns) - - lua_pushlightuserdata(L, reinterpret_cast(fp)); // Stack: ns, function ptr - lua_pushcclosure(L, &detail::invoke_proxy_function, 1); // Stack: ns, function - rawsetfield(L, -2, name); // Stack: ns - - return *this; - } - - //============================================================================================= - /** - * @brief Add or replace a lua_CFunction. - * - * @param name The function name. - * @param fp A C-function pointer. - * - * @returns This namespace registration object. - */ - Namespace& addFunction(const char* name, lua_CFunction fp) - { - assert(name != nullptr); - assert(lua_istable(L, -1)); // Stack: namespace table (ns) - - lua_pushcfunction(L, fp); // Stack: ns, function - rawsetfield(L, -2, name); // Stack: ns - - return *this; - } - - //============================================================================================= - /** - * @brief Open a new or existing class for registrations. - * - * @param name The class name. - * - * @returns A class registration object. - */ - template - Class beginClass(const char* name) - { - assertIsActive(); - return Class(name, *this); - } - - //============================================================================================= - /** - * @brief Derive a new class for registrations. - * - * Call deriveClass() only once. To continue registrations for the class later, use beginClass(). - * - * @param name The class name. - * - * @returns A class registration object. - */ - template - Class deriveClass(const char* name) - { - assertIsActive(); - return Class(name, *this, detail::getStaticRegistryKey()); - } -}; - -//================================================================================================= -/** - * @brief Retrieve the global namespace. - * - * It is recommended to put your namespace inside the global namespace, and then add your classes and functions to it, rather than adding - * many classes and functions directly to the global namespace. - * - * @param L A Lua state. - * - * @returns A namespace registration object. - */ -inline Namespace getGlobalNamespace(lua_State* L) -{ - return Namespace::getGlobalNamespace(L); -} - -//================================================================================================= -/** - * @brief Retrieve the namespace on top of the stack. - * - * You should have a table on top of the stack before calling this function. It will then use the table there as destination for registrations. - * - * @param L A Lua state. - * - * @returns A namespace registration object. - */ -inline Namespace getNamespaceFromStack(lua_State* L) -{ - return Namespace::getNamespaceFromStack(L); -} - -} // namespace luabridge - -// End File: Source/LuaBridge/detail/Namespace.h - -// Begin File: Source/LuaBridge/LuaBridge.h - -// https://github.com/kunitoki/LuaBridge3 -// Copyright 2020, Lucio Asnaghi -// Copyright 2020, Dmitry Tarakanov -// Copyright 2012, Vinnie Falco -// Copyright 2007, Nathan Reed -// SPDX-License-Identifier: MIT - -// All #include dependencies are listed here -// instead of in the individual header files. - -#define LUABRIDGE_MAJOR_VERSION 3 -#define LUABRIDGE_MINOR_VERSION 1 -#define LUABRIDGE_VERSION 301 - -#ifndef LUA_VERSION_NUM -#error "Lua headers must be included prior to LuaBridge ones" -#endif - - -// End File: Source/LuaBridge/LuaBridge.h - -// Begin File: Source/LuaBridge/List.h - -// https://github.com/kunitoki/LuaBridge3 -// Copyright 2020, Lucio Asnaghi -// Copyright 2020, Dmitry Tarakanov -// SPDX-License-Identifier: MIT - -namespace luabridge { - -//================================================================================================= -/** - * @brief Stack specialization for `std::array`. - */ -template -struct Stack> -{ - using Type = std::list; - - static bool push(lua_State* L, const Type& list, std::error_code& ec) - { - const int initialStackSize = lua_gettop(L); - - lua_createtable(L, static_cast(list.size()), 0); - - auto it = list.cbegin(); - for (lua_Integer tableIndex = 1; it != list.cend(); ++tableIndex, ++it) - { - lua_pushinteger(L, tableIndex); - - std::error_code errorCode; - if (! Stack::push(L, *it, errorCode)) - { - ec = errorCode; - lua_pop(L, lua_gettop(L) - initialStackSize); - return false; - } - - lua_settable(L, -3); - } - - return true; - } - - static Type get(lua_State* L, int index) - { - if (!lua_istable(L, index)) - luaL_error(L, "#%d argument must be a table", index); - - Type list; - - int absIndex = lua_absindex(L, index); - lua_pushnil(L); - - while (lua_next(L, absIndex) != 0) - { - list.emplace_back(Stack::get(L, -1)); - lua_pop(L, 1); - } - - return list; - } - - static bool isInstance(lua_State* L, int index) - { - return lua_istable(L, index); - } -}; - -} // namespace luabridge - -// End File: Source/LuaBridge/List.h - -// Begin File: Source/LuaBridge/Array.h - -// https://github.com/kunitoki/LuaBridge3 -// Copyright 2020, Lucio Asnaghi -// Copyright 2020, Dmitry Tarakanov -// SPDX-License-Identifier: MIT - -namespace luabridge { - -//================================================================================================= -/** - * @brief Stack specialization for `std::array`. - */ -template -struct Stack> -{ - using Type = std::array; - - static bool push(lua_State* L, const Type& array, std::error_code& ec) - { - const int initialStackSize = lua_gettop(L); - - lua_createtable(L, static_cast(Size), 0); - - for (std::size_t i = 0; i < Size; ++i) - { - lua_pushinteger(L, static_cast(i + 1)); - - std::error_code errorCode; - bool result = Stack::push(L, array[i], errorCode); - if (!result) - { - ec = errorCode; - lua_pop(L, lua_gettop(L) - initialStackSize); - return false; - } - - lua_settable(L, -3); - } - - return true; - } - - static Type get(lua_State* L, int index) - { - if (!lua_istable(L, index)) - luaL_error(L, "#%d argment must be a table", index); - - if (get_length(L, index) != Size) - luaL_error(L, "table size should be %d but is %d", Size, get_length(L, index)); - - Type array; - - int absIndex = lua_absindex(L, index); - lua_pushnil(L); - - int arrayIndex = 0; - while (lua_next(L, absIndex) != 0) - { - array[arrayIndex++] = Stack::get(L, -1); - lua_pop(L, 1); - } - - return array; - } -}; - -} // namespace luabridge - -// End File: Source/LuaBridge/Array.h - -// Begin File: Source/LuaBridge/Vector.h - -// https://github.com/kunitoki/LuaBridge3 -// Copyright 2020, Lucio Asnaghi -// Copyright 2018, Dmitry Tarakanov -// SPDX-License-Identifier: MIT - -namespace luabridge { - -//================================================================================================= -/** - * @brief Stack specialization for `std::vector`. - */ -template -struct Stack> -{ - using Type = std::vector; - - static bool push(lua_State* L, const Type& vector, std::error_code& ec) - { - const int initialStackSize = lua_gettop(L); - - lua_createtable(L, static_cast(vector.size()), 0); - - for (std::size_t i = 0; i < vector.size(); ++i) - { - lua_pushinteger(L, static_cast(i + 1)); - - std::error_code errorCode; - if (! Stack::push(L, vector[i], errorCode)) - { - ec = errorCode; - lua_pop(L, lua_gettop(L) - initialStackSize); - return false; - } - - lua_settable(L, -3); - } - - return true; - } - - static Type get(lua_State* L, int index) - { - if (!lua_istable(L, index)) - luaL_error(L, "#%d argument must be a table", index); - - Type vector; - vector.reserve(static_cast(get_length(L, index))); - - int absIndex = lua_absindex(L, index); - lua_pushnil(L); - - while (lua_next(L, absIndex) != 0) - { - vector.emplace_back(Stack::get(L, -1)); - lua_pop(L, 1); - } - - return vector; - } - - static bool isInstance(lua_State* L, int index) - { - return lua_istable(L, index); - } -}; - -} // namespace luabridge - -// End File: Source/LuaBridge/Vector.h - -// Begin File: Source/LuaBridge/Set.h - -// https://github.com/kunitoki/LuaBridge3 -// Copyright 2020, Lucio Asnaghi -// SPDX-License-Identifier: MIT - -namespace luabridge { - -//================================================================================================= -/** - * @brief Stack specialization for `std::set`. - */ -template -struct Stack> -{ - using Type = std::set; - - static bool push(lua_State* L, const Type& set, std::error_code& ec) - { - const int initialStackSize = lua_gettop(L); - - lua_createtable(L, 0, static_cast(set.size())); - - for (auto it = set.begin(); it != set.end(); ++it) - { - std::error_code errorCodeKey; - if (! Stack::push(L, it->first, errorCodeKey)) - { - ec = errorCodeKey; - lua_pop(L, lua_gettop(L) - initialStackSize); - return false; - } - - std::error_code errorCodeValue; - if (! Stack::push(L, it->second, errorCodeValue)) - { - ec = errorCodeValue; - lua_pop(L, lua_gettop(L) - initialStackSize); - return false; - } - - lua_settable(L, -3); - } - - return true; - } - - static Type get(lua_State* L, int index) - { - if (!lua_istable(L, index)) - luaL_error(L, "#%d argument must be a table", index); - - Type set; - - int absIndex = lua_absindex(L, index); - lua_pushnil(L); - - while (lua_next(L, absIndex) != 0) - { - set.emplace(Stack::get(L, -2), Stack::get(L, -1)); - lua_pop(L, 1); - } - - return set; - } - - static bool isInstance(lua_State* L, int index) - { - return lua_istable(L, index); - } -}; - -} // namespace luabridge - -// End File: Source/LuaBridge/Set.h - -// Begin File: Source/LuaBridge/RefCountedObject.h - -// https://github.com/kunitoki/LuaBridge3 -// Copyright 2020, Lucio Asnaghi -// Copyright 2012, Vinnie Falco -// Copyright 2004-11 by Raw Material Software Ltd. -// SPDX-License-Identifier: MIT - -//============================================================================== -/* - This is a derivative work used by permission from part of - JUCE, available at http://www.rawaterialsoftware.com - - License: The MIT License (http://www.opensource.org/licenses/mit-license.php) - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - This file incorporates work covered by the following copyright and - permission notice: - - This file is part of the JUCE library - "Jules' Utility Class Extensions" - Copyright 2004-11 by Raw Material Software Ltd. -*/ -//============================================================================== - -namespace luabridge { - -//============================================================================== -/** - Adds reference-counting to an object. - - To add reference-counting to a class, derive it from this class, and - use the RefCountedObjectPtr class to point to it. - - e.g. @code - class MyClass : public RefCountedObjectType - { - void foo(); - - // This is a neat way of declaring a typedef for a pointer class, - // rather than typing out the full templated name each time.. - typedef RefCountedObjectPtr Ptr; - }; - - MyClass::Ptr p = new MyClass(); - MyClass::Ptr p2 = p; - p = 0; - p2->foo(); - @endcode - - Once a new RefCountedObjectType has been assigned to a pointer, be - careful not to delete the object manually. -*/ -template -class RefCountedObjectType -{ -public: - //============================================================================== - /** Increments the object's reference count. - - This is done automatically by the smart pointer, but is public just - in case it's needed for nefarious purposes. - */ - inline void incReferenceCount() const { ++refCount; } - - /** Decreases the object's reference count. - - If the count gets to zero, the object will be deleted. - */ - inline void decReferenceCount() const - { - assert(getReferenceCount() > 0); - - if (--refCount == 0) - delete this; - } - - /** Returns the object's current reference count. - * @returns The reference count. - */ - inline int getReferenceCount() const { return static_cast(refCount); } - -protected: - //============================================================================== - /** Creates the reference-counted object (with an initial ref count of zero). */ - RefCountedObjectType() : refCount() {} - - /** Destructor. */ - virtual ~RefCountedObjectType() - { - // it's dangerous to delete an object that's still referenced by something else! - assert(getReferenceCount() == 0); - } - -private: - //============================================================================== - CounterType mutable refCount; -}; - -//============================================================================== - -/** Non thread-safe reference counted object. - - This creates a RefCountedObjectType that uses a non-atomic integer - as the counter. -*/ -typedef RefCountedObjectType RefCountedObject; - -//============================================================================== -/** - A smart-pointer class which points to a reference-counted object. - - The template parameter specifies the class of the object you want to point - to - the easiest way to make a class reference-countable is to simply make - it inherit from RefCountedObjectType, but if you need to, you could roll - your own reference-countable class by implementing a pair of methods called - incReferenceCount() and decReferenceCount(). - - When using this class, you'll probably want to create a typedef to - abbreviate the full templated name - e.g. - - @code - - typedef RefCountedObjectPtr MyClassPtr; - - @endcode -*/ -template -class RefCountedObjectPtr -{ -public: - /** The class being referenced by this pointer. */ - typedef ReferenceCountedObjectClass ReferencedType; - - //============================================================================== - /** Creates a pointer to a null object. */ - inline RefCountedObjectPtr() : referencedObject(0) {} - - /** Creates a pointer to an object. - This will increment the object's reference-count if it is non-null. - - @param refCountedObject A reference counted object to own. - */ - inline RefCountedObjectPtr(ReferenceCountedObjectClass* const refCountedObject) - : referencedObject(refCountedObject) - { - if (refCountedObject != 0) - refCountedObject->incReferenceCount(); - } - - /** Copies another pointer. - This will increment the object's reference-count (if it is non-null). - - @param other Another pointer. - */ - inline RefCountedObjectPtr(const RefCountedObjectPtr& other) - : referencedObject(other.referencedObject) - { - if (referencedObject != 0) - referencedObject->incReferenceCount(); - } - - /** - Takes-over the object from another pointer. - - @param other Another pointer. - */ - inline RefCountedObjectPtr(RefCountedObjectPtr&& other) - : referencedObject(other.referencedObject) - { - other.referencedObject = 0; - } - - /** Copies another pointer. - This will increment the object's reference-count (if it is non-null). - - @param other Another pointer. - */ - template - inline RefCountedObjectPtr(const RefCountedObjectPtr& other) - : referencedObject(static_cast(other.getObject())) - { - if (referencedObject != 0) - referencedObject->incReferenceCount(); - } - - /** Changes this pointer to point at a different object. - - The reference count of the old object is decremented, and it might be - deleted if it hits zero. The new object's count is incremented. - - @param other A pointer to assign from. - @returns This pointer. - */ - RefCountedObjectPtr& operator=(const RefCountedObjectPtr& other) - { - return operator=(other.referencedObject); - } - - /** Changes this pointer to point at a different object. - The reference count of the old object is decremented, and it might be - deleted if it hits zero. The new object's count is incremented. - - @param other A pointer to assign from. - @returns This pointer. - */ - template - RefCountedObjectPtr& operator=(const RefCountedObjectPtr& other) - { - return operator=(static_cast(other.getObject())); - } - - /** - Takes-over the object from another pointer. - - @param other A pointer to assign from. - @returns This pointer. - */ - RefCountedObjectPtr& operator=(RefCountedObjectPtr&& other) - { - std::swap(referencedObject, other.referencedObject); - return *this; - } - - /** Changes this pointer to point at a different object. - The reference count of the old object is decremented, and it might be - deleted if it hits zero. The new object's count is incremented. - - @param newObject A reference counted object to own. - @returns This pointer. - */ - RefCountedObjectPtr& operator=(ReferenceCountedObjectClass* const newObject) - { - if (referencedObject != newObject) - { - if (newObject != 0) - newObject->incReferenceCount(); - - ReferenceCountedObjectClass* const oldObject = referencedObject; - referencedObject = newObject; - - if (oldObject != 0) - oldObject->decReferenceCount(); - } - - return *this; - } - - /** Destructor. - This will decrement the object's reference-count, and may delete it if it - gets to zero. - */ - ~RefCountedObjectPtr() - { - if (referencedObject != 0) - referencedObject->decReferenceCount(); - } - - /** Returns the object that this pointer references. - The returned pointer may be null. - - @returns The pointee. - */ - operator ReferenceCountedObjectClass*() const { return referencedObject; } - - /** Returns the object that this pointer references. - The returned pointer may be null. - - @returns The pointee. - */ - ReferenceCountedObjectClass* operator->() const { return referencedObject; } - - /** Returns the object that this pointer references. - The returned pointer may be null. - - @returns The pointee. - */ - ReferenceCountedObjectClass* getObject() const { return referencedObject; } - -private: - //============================================================================== - ReferenceCountedObjectClass* referencedObject; -}; - -/** Compares two ReferenceCountedObjectPointers. */ -template -bool operator==(const RefCountedObjectPtr& object1, - ReferenceCountedObjectClass* const object2) -{ - return object1.getObject() == object2; -} - -/** Compares two ReferenceCountedObjectPointers. */ -template -bool operator==(const RefCountedObjectPtr& object1, - const RefCountedObjectPtr& object2) -{ - return object1.getObject() == object2.getObject(); -} - -/** Compares two ReferenceCountedObjectPointers. */ -template -bool operator==(ReferenceCountedObjectClass* object1, - RefCountedObjectPtr& object2) -{ - return object1 == object2.getObject(); -} - -/** Compares two ReferenceCountedObjectPointers. */ -template -bool operator!=(const RefCountedObjectPtr& object1, - const ReferenceCountedObjectClass* object2) -{ - return object1.getObject() != object2; -} - -/** Compares two ReferenceCountedObjectPointers. */ -template -bool operator!=(const RefCountedObjectPtr& object1, - RefCountedObjectPtr& object2) -{ - return object1.getObject() != object2.getObject(); -} - -/** Compares two ReferenceCountedObjectPointers. */ -template -bool operator!=(ReferenceCountedObjectClass* object1, - RefCountedObjectPtr& object2) -{ - return object1 != object2.getObject(); -} - -//============================================================================== - -template -struct ContainerTraits> -{ - using Type = T; - - static RefCountedObjectPtr construct(T* c) { return c; } - - static T* get(RefCountedObjectPtr const& c) { return c.getObject(); } -}; - -//============================================================================== - -} // namespace luabridge - -// End File: Source/LuaBridge/RefCountedObject.h - -// Begin File: Source/LuaBridge/detail/Dump.h - -// https://github.com/kunitoki/LuaBridge3 -// Copyright 2020, Lucio Asnaghi -// Copyright 2019, Dmitry Tarakanov -// Copyright 2012, Vinnie Falco -// Copyright 2007, Nathan Reed -// SPDX-License-Identifier: MIT - -namespace luabridge { -namespace debug { - -inline void putIndent(std::ostream& stream, unsigned level) -{ - for (unsigned i = 0; i < level; ++i) - { - stream << " "; - } -} - -inline void dumpTable(lua_State* L, int index, std::ostream& stream, unsigned level); - -inline void dumpValue(lua_State* L, int index, std::ostream& stream, unsigned level = 0) -{ - const int type = lua_type(L, index); - switch (type) - { - case LUA_TNIL: - stream << "nil"; - break; - - case LUA_TBOOLEAN: - stream << (lua_toboolean(L, index) ? "true" : "false"); - break; - - case LUA_TNUMBER: - stream << lua_tonumber(L, index); - break; - - case LUA_TSTRING: - stream << '"' << lua_tostring(L, index) << '"'; - break; - - case LUA_TFUNCTION: - if (lua_iscfunction(L, index)) - { - stream << "cfunction@" << lua_topointer(L, index); - } - else - { - stream << "function@" << lua_topointer(L, index); - } - break; - - case LUA_TTHREAD: - stream << "thread@" << lua_tothread(L, index); - break; - - case LUA_TLIGHTUSERDATA: - stream << "lightuserdata@" << lua_touserdata(L, index); - break; - - case LUA_TTABLE: - dumpTable(L, index, stream, level); - break; - - case LUA_TUSERDATA: - stream << "userdata@" << lua_touserdata(L, index); - break; - - default: - stream << lua_typename(L, type); - ; - break; - } -} - -inline void dumpTable(lua_State* L, int index, std::ostream& stream, unsigned level) -{ - stream << "table@" << lua_topointer(L, index); - - if (level > 0) - { - return; - } - - index = lua_absindex(L, index); - stream << " {"; - lua_pushnil(L); // Initial key - while (lua_next(L, index)) - { - stream << "\n"; - putIndent(stream, level + 1); - dumpValue(L, -2, stream, level + 1); // Key - stream << ": "; - dumpValue(L, -1, stream, level + 1); // Value - lua_pop(L, 1); // Value - } - putIndent(stream, level); - stream << "\n}"; -} - -inline void dumpState(lua_State* L, std::ostream& stream = std::cerr) -{ - int top = lua_gettop(L); - for (int i = 1; i <= top; ++i) - { - stream << "stack #" << i << ": "; - dumpValue(L, i, stream, 0); - stream << "\n"; - } -} - -} // namespace debug -} // namespace luabridge - -// End File: Source/LuaBridge/detail/Dump.h - -// clang-format on \ No newline at end of file diff --git a/sources/System/IAControllable/IAControllableSystem.cpp b/sources/System/IAControllable/IAControllableSystem.cpp index 1ef106c8..44dca2ca 100644 --- a/sources/System/IAControllable/IAControllableSystem.cpp +++ b/sources/System/IAControllable/IAControllableSystem.cpp @@ -49,9 +49,6 @@ namespace BBM state.push(player.x); state.setTable(); state.push("y"); - state.push(player.y); - state.setTable(); - state.push("z"); state.push(player.z); state.setTable(); state.setTable(); @@ -69,9 +66,6 @@ namespace BBM state.push(info.x); state.setTable(); state.push("y"); - state.push(info.y); - state.setTable(); - state.push("z"); state.push(info.z); state.setTable(); state.push("type"); @@ -82,11 +76,48 @@ namespace BBM state.setTable(); } + void IAControllableSystem::pushInfoDangerPos(LuaG::State &state, int &index, float xpos, float ypos) + { + state.push(index++); + state.newTable(); + state.push("x"); + state.push(xpos); + state.setTable(); + state.push("y"); + state.push(ypos); + state.setTable(); + state.setTable(); + } + + void IAControllableSystem::pushInfoDanger(LuaG::State &state) + { + int index = 0; + state.push("danger"); + state.newTable(); + for (auto &bomb : _bombs) { + Vector3f bombPos = std::get<0>(bomb); + int bombRadius = std::get<1>(bomb); + pushInfoDangerPos(state, index, bombPos.x, bombPos.z); + for (int i = 1; i < bombRadius; i++) { + Vector3f pos = bombPos - Vector3f(i, 0, 0); + pushInfoDangerPos(state, index, pos.x, pos.z); + pos = bombPos - Vector3f(-i, 0, 0); + pushInfoDangerPos(state, index, pos.x, pos.z); + pos = bombPos - Vector3f(0, 0, i); + pushInfoDangerPos(state, index, pos.x, pos.z); + pos = bombPos - Vector3f(0, 0, -i); + pushInfoDangerPos(state, index, pos.x, pos.z); + } + } + state.setTable(); + } + void IAControllableSystem::pushInfo(LuaG::State &state, MapInfo &player) { state.newTable(); pushInfoPlayer(state, player); pushInfoRaw(state); + pushInfoDanger(state); } void IAControllableSystem::onFixedUpdate(WAL::ViewEntity &entity) @@ -116,25 +147,4 @@ namespace BBM _map.clear(); _bombs.clear(); } - - bool IAControllableSystem::isInExplosionRange(float x, float y, float z) - { - Vector3f pos(x, y, z); - //pos = pos.round(); - //for (auto &bomb : _bombs) { - // Vector3f bombPos = std::get<0>(bomb); - // int bombRadius = std::get<1>(bomb); - // for (int i = 1; i < bombRadius; i++) { - // if (pos == bombPos - Vector3f(i, 0, 0)) - // return true; - // if (pos == bombPos - Vector3f(-i, 0, 0)) - // return true; - // if (pos == bombPos - Vector3f(0, 0, i)) - // return true; - // if (pos == bombPos - Vector3f(0, 0, -i)) - // return true; - // } - //} - return true; - } } \ No newline at end of file diff --git a/sources/System/IAControllable/IAControllableSystem.hpp b/sources/System/IAControllable/IAControllableSystem.hpp index 5bc1fa06..d2347512 100644 --- a/sources/System/IAControllable/IAControllableSystem.hpp +++ b/sources/System/IAControllable/IAControllableSystem.hpp @@ -31,13 +31,19 @@ namespace BBM //! @brief update the raw info of the map void UpdateMapInfos(WAL::ViewEntity &entity); - + + //! @brief push danger info position + void pushInfoDangerPos(LuaG::State &state, int &index, float xpos, float ypos); + //! @brief push player info void pushInfoPlayer(LuaG::State &state, MapInfo &player); //! @brief push raw map info void pushInfoRaw(LuaG::State &state); + //! @brief push danger map info + void pushInfoDanger(LuaG::State &state); + //! @brief push all the infos to the ai stack void pushInfo(LuaG::State &state, MapInfo &player); public: @@ -56,7 +62,5 @@ namespace BBM ~IAControllableSystem() override = default; //! @brief A keyboard system is assignable. IAControllableSystem &operator=(const IAControllableSystem &) = default; - - static bool isInExplosionRange(float x, float y, float z); }; } From 35d07117a708342618dd80fc8554ea664d2fad7d Mon Sep 17 00:00:00 2001 From: Bluub Date: Tue, 15 Jun 2021 16:28:29 +0200 Subject: [PATCH 24/78] merge lobby --- ai_scripts/john.lua | 82 +++++++++++++++---- .../IAControllable/IAControllableSystem.cpp | 45 ++++++---- .../IAControllable/IAControllableSystem.hpp | 17 ++-- sources/System/Lobby/LobbySystem.cpp | 3 +- 4 files changed, 105 insertions(+), 42 deletions(-) diff --git a/ai_scripts/john.lua b/ai_scripts/john.lua index 0882c3d4..cfe5e235 100644 --- a/ai_scripts/john.lua +++ b/ai_scripts/john.lua @@ -8,7 +8,7 @@ mapinfo.dist { } ]] ------------ - +------ Debug variables local debug = false if not debug then @@ -18,9 +18,15 @@ else print(a) end end +----- Global variables +Dirs = {{x = 1, y = 0}, {x = -1, y = 0}, {x = 0, y = -1}, {x = 0, y = 1}} +MaxX = 0 +MaxY = 0 +Map = {} -function PrintMap(map, maxX, maxZ) - for i=0,maxX + 1 do +----- Map functions +function PrintMap(map, MaxX, maxZ) + for i=0,MaxX + 1 do local s = "| " for j=0,maxZ + 1 do s = s .. tostring(map[i][j]) .. " | "; @@ -30,18 +36,18 @@ function PrintMap(map, maxX, maxZ) end end -function CreateMyMap(infos, maxX, maxY) +function CreateMyMap(infos, MaxX, MaxY) local map = {} - for i=0,maxX + 1 do + for i=0,MaxX + 1 do map[i] = {} - for j=0,maxY + 1 do + for j=0,MaxY + 1 do map[i][j] = 0 end end for i, info in ipairs(infos) do map[info.x][info.y] = info.type end - PrintMap(map, maxX, maxY) + PrintMap(map, MaxX, MaxY) return map end @@ -54,21 +60,61 @@ function isInExplosionRange(mapinfo, x, y) return false end -function Update(mapinfo) - local maxX = 0 - local maxY = 0 - for i, info in ipairs(mapinfo.raw) do - if info.x > maxX then - maxX = info.x - end - if info.y > maxY then - maxY = info.y + +---- Pathfinding +function pathfind(root, target) + local closed = {} + local open = {} + local came_from = {} +end + +function dist(nodeA, nodeB) + return math.sqrt(math.pow(nodeB.x - nodeA.x, 2) + math.pow(nodeB.y - nodeA.y, 2)) +end + +function getPathToSafeSpace(player, danger) + local minXesc = (player.x - 3 < 0) and 0 or (player.x - 3); + local MaxXesc = (player.x + 3 > MaxX) and MaxX or (player.x + 3); + local minYesc = (player.y - 3 < 0) and 0 or (player.y - 3); + local MaxYesc = (player.y + 3 > MaxY) and MaxY or (player.y + 3); + + local maybeSafeSpace = {} + for i=minXesc,MaxXesc do + for j=minYesc, MaxYesc do + if myMap[i][j] == 0 or danger[i][j] == 0 then + table.insert(maybeSafeSpace, {x = i, y = j}) + end end end + local minDist = 100000 + local res = {} + for safe in pairs(maybeSafeSpace) do + local currDist = dist(player, safe) + if currDist < minDist then + minDist, res = currDist, safe + end + end + local path = pathfind(player, res) +end + + +------ Update +function Update(mapinfo) + MaxX = 0 + MaxY = 0 + for i, info in ipairs(mapinfo.raw) do + if info.x > MaxX then + MaxX = info.x + end + if info.y > MaxY then + MaxY = info.y + end + end + Map = CreateMyMap(mapinfo.raw, MaxX, MaxY) local roundedPlayerPos = {x = math.floor(mapinfo.player.x+0.5), y = math.floor(mapinfo.player.y+0.5)} - local myMap = CreateMyMap(mapinfo.raw, maxX, maxY) if (isInExplosionRange(mapinfo, roundedPlayerPos.x, roundedPlayerPos.y)) then - if (myMap[roundedPlayerPos.x + 1][roundedPlayerPos.y] ~= 0) then + --local pathToSafeSpace = getPathToSafeSpace(roundedPlayerPos) + if (Map[roundedPlayerPos.x + 1][roundedPlayerPos.y] ~= 0) then return -1, 0, false, false else return 1, 0, false, false diff --git a/sources/System/IAControllable/IAControllableSystem.cpp b/sources/System/IAControllable/IAControllableSystem.cpp index 44dca2ca..f4baa9b5 100644 --- a/sources/System/IAControllable/IAControllableSystem.cpp +++ b/sources/System/IAControllable/IAControllableSystem.cpp @@ -4,6 +4,7 @@ #include "Component/Bomb/BasicBombComponent.hpp" #include "Component/Tag/TagComponent.hpp" +#include "Component/Timer/TimerComponent.hpp" #include "Component/Controllable/ControllableComponent.hpp" #include "Component/IAControllable/IAControllableComponent.hpp" #include "System/IAControllable/IAControllableSystem.hpp" @@ -15,7 +16,7 @@ namespace BBM : System(wal), _wal(wal), _cached(false) { } - void IAControllableSystem::UpdateMapInfos(WAL::ViewEntity &entity) + void IAControllableSystem::UpdateMapInfos(WAL::ViewEntity &entity) { _players.clear(); for (auto &[other, pos, _] : _wal.getScene()->view>()) { @@ -35,13 +36,13 @@ namespace BBM _map.push_back(MapInfo(pos.position, MapGenerator::BUMPER)); for (auto &[other, pos, _] : _wal.getScene()->view>()) _map.push_back(MapInfo(pos.position, MapGenerator::HOLE)); - for (auto &[other, pos, bomb] : _wal.getScene()->view()) - _bombs.push_back(std::make_pair(pos.position, bomb.explosionRadius)); + for (auto &[other, pos, bomb, timer] : _wal.getScene()->view()) + _bombs.push_back(std::make_tuple(pos.position, bomb.explosionRadius, timer.ringIn)); _cached = true; } - void IAControllableSystem::pushInfoPlayer(LuaG::State &state, MapInfo &player) + void IAControllableSystem::pushInfoPlayer(LuaG::State &state, MapInfo &player, BombHolderComponent &bombHolder) { state.push("player"); state.newTable(); @@ -51,6 +52,12 @@ namespace BBM state.push("y"); state.push(player.z); state.setTable(); + state.push("bombCount"); + state.push(bombHolder.bombCount); + state.setTable(); + state.push("radius"); + state.push(bombHolder.explosionRadius); + state.setTable(); state.setTable(); } @@ -76,7 +83,7 @@ namespace BBM state.setTable(); } - void IAControllableSystem::pushInfoDangerPos(LuaG::State &state, int &index, float xpos, float ypos) + void IAControllableSystem::pushInfoDangerPos(LuaG::State &state, int &index, float xpos, float ypos, int dangerLevel) { state.push(index++); state.newTable(); @@ -86,6 +93,9 @@ namespace BBM state.push("y"); state.push(ypos); state.setTable(); + state.push("level"); + state.push(dangerLevel); + state.setTable(); state.setTable(); } @@ -97,34 +107,39 @@ namespace BBM for (auto &bomb : _bombs) { Vector3f bombPos = std::get<0>(bomb); int bombRadius = std::get<1>(bomb); - pushInfoDangerPos(state, index, bombPos.x, bombPos.z); + std::chrono::nanoseconds timeleft = std::get<2>(bomb); + int dangerLevel = timeleft.count() / 1000000000; + if (dangerLevel == 0) + dangerLevel = 1; + pushInfoDangerPos(state, index, bombPos.x, bombPos.z, dangerLevel); for (int i = 1; i < bombRadius; i++) { Vector3f pos = bombPos - Vector3f(i, 0, 0); - pushInfoDangerPos(state, index, pos.x, pos.z); + pushInfoDangerPos(state, index, pos.x, pos.z, dangerLevel); pos = bombPos - Vector3f(-i, 0, 0); - pushInfoDangerPos(state, index, pos.x, pos.z); + pushInfoDangerPos(state, index, pos.x, pos.z, dangerLevel); pos = bombPos - Vector3f(0, 0, i); - pushInfoDangerPos(state, index, pos.x, pos.z); + pushInfoDangerPos(state, index, pos.x, pos.z, dangerLevel); pos = bombPos - Vector3f(0, 0, -i); - pushInfoDangerPos(state, index, pos.x, pos.z); + pushInfoDangerPos(state, index, pos.x, pos.z, dangerLevel); } } state.setTable(); } - void IAControllableSystem::pushInfo(LuaG::State &state, MapInfo &player) + void IAControllableSystem::pushInfo(LuaG::State &state, MapInfo &player, BombHolderComponent &bombHolder) { state.newTable(); - pushInfoPlayer(state, player); + pushInfoPlayer(state, player, bombHolder); pushInfoRaw(state); pushInfoDanger(state); } - void IAControllableSystem::onFixedUpdate(WAL::ViewEntity &entity) + void IAControllableSystem::onFixedUpdate(WAL::ViewEntity &entity) { auto &ia = entity.get(); auto &controllable = entity.get(); auto &pos = entity.get(); + auto &bombHolder = entity.get(); MapInfo player(pos.position, MapGenerator::NOTHING); UpdateMapInfos(entity); @@ -132,10 +147,10 @@ namespace BBM ia._state.getGlobal("Update"); if (!lua_isfunction(ia._state.getState(), -1)) return; - pushInfo(ia._state, player); + pushInfo(ia._state, player, bombHolder); ia._state.callFunction(1, 4); controllable.bomb = ia._state.getReturnBool(); - controllable.jump = ia._state.getReturnBool(); + controllable.select = ia._state.getReturnBool(); controllable.move.y = ia._state.getReturnNumber(); controllable.move.x = ia._state.getReturnNumber(); ia._state.popLast(); diff --git a/sources/System/IAControllable/IAControllableSystem.hpp b/sources/System/IAControllable/IAControllableSystem.hpp index d2347512..6c895a25 100644 --- a/sources/System/IAControllable/IAControllableSystem.hpp +++ b/sources/System/IAControllable/IAControllableSystem.hpp @@ -5,13 +5,14 @@ #pragma once #include +#include "Component/BombHolder/BombHolderComponent.hpp" #include "Map/MapInfo.hpp" #include "System/System.hpp" namespace BBM { //! @brief A system to handle keyboard entities. - class IAControllableSystem : public WAL::System + class IAControllableSystem : public WAL::System { private: //! @brief Reference to wal to get Views @@ -27,16 +28,16 @@ namespace BBM std::vector _players; //! @brief All bombs on the map - std::vector> _bombs; + std::vector> _bombs; //! @brief update the raw info of the map - void UpdateMapInfos(WAL::ViewEntity &entity); + void UpdateMapInfos(WAL::ViewEntity &entity); //! @brief push danger info position - void pushInfoDangerPos(LuaG::State &state, int &index, float xpos, float ypos); + void pushInfoDangerPos(LuaG::State &state, int &index, float xpos, float ypos, int dangerLevel); //! @brief push player info - void pushInfoPlayer(LuaG::State &state, MapInfo &player); + void pushInfoPlayer(LuaG::State &state, MapInfo &player, BombHolderComponent &bombHolder); //! @brief push raw map info void pushInfoRaw(LuaG::State &state); @@ -44,12 +45,12 @@ namespace BBM //! @brief push danger map info void pushInfoDanger(LuaG::State &state); - //! @brief push all the infos to the ai stack - void pushInfo(LuaG::State &state, MapInfo &player); + //! @brief push all the infos to the lua stack + void pushInfo(LuaG::State &state, MapInfo &player, BombHolderComponent &bombHolder); public: //! @inherit - void onFixedUpdate(WAL::ViewEntity &entity) override; + void onFixedUpdate(WAL::ViewEntity &entity) override; //! @inherit void onSelfUpdate() override; diff --git a/sources/System/Lobby/LobbySystem.cpp b/sources/System/Lobby/LobbySystem.cpp index 4ff24b97..abb49d9a 100644 --- a/sources/System/Lobby/LobbySystem.cpp +++ b/sources/System/Lobby/LobbySystem.cpp @@ -12,6 +12,7 @@ #include #include #include +#include "Component/IAControllable/IAControllableComponent.hpp" #include #include @@ -185,7 +186,7 @@ namespace BBM player.addComponent(3); break; case ControllableComponent::AI: - throw std::runtime_error("Not implemented error"); + player.addComponent("./ai_scripts/john.lua"); break; default: throw std::runtime_error("Invalid controller for a player."); From 79dcf36b318ff494e7f67fdbbe075ba02ecaa1f5 Mon Sep 17 00:00:00 2001 From: Bluub Date: Tue, 15 Jun 2021 17:14:23 +0200 Subject: [PATCH 25/78] fix typo --- lib/LuaGate/sources/LuaGate.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/LuaGate/sources/LuaGate.hpp b/lib/LuaGate/sources/LuaGate.hpp index ed5bf73f..dfaa2965 100644 --- a/lib/LuaGate/sources/LuaGate.hpp +++ b/lib/LuaGate/sources/LuaGate.hpp @@ -10,7 +10,7 @@ namespace LuaG class State { private: - //! @”rief Lua state + //! @brief Lua state lua_State *_state; public: //! @brief ctor From 83850f0f1ae2d1bb7ddf7b2059df9e6346c70b89 Mon Sep 17 00:00:00 2001 From: Bluub Date: Tue, 15 Jun 2021 17:16:39 +0200 Subject: [PATCH 26/78] fix typo --- sources/Models/GameState.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/Models/GameState.hpp b/sources/Models/GameState.hpp index bafc69ce..4bb271b5 100644 --- a/sources/Models/GameState.hpp +++ b/sources/Models/GameState.hpp @@ -1,6 +1,6 @@ // // Created by Zoe Roux on 5/24/21. -//p +// #pragma once From 5c895ff7b26b331c6629badea3dab34b15e016a3 Mon Sep 17 00:00:00 2001 From: Bluub Date: Tue, 15 Jun 2021 17:23:32 +0200 Subject: [PATCH 27/78] try fix cmake --- CMakeLists.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 643fa719..94308555 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,13 @@ project(bomberman) set(CMAKE_CXX_STANDARD 20) -find_package(Lua REQUIRED) + +find_package(Lua QUIET) +if (NOT LUA_FOUND) + set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../lua) + find_package(Lua REQUIRED) +endif() + include_directories(bomberman ${LUA_INCLUDE_DIR}) include_directories(bomberman lib/Ray/sources) include_directories(bomberman lib/wal/sources) From 12c2747c65dfcaf2c79746af159cf26206080b84 Mon Sep 17 00:00:00 2001 From: Bluub Date: Tue, 15 Jun 2021 17:29:48 +0200 Subject: [PATCH 28/78] try fix cmake --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 94308555..327fc8c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ set(CMAKE_CXX_STANDARD 20) find_package(Lua QUIET) if (NOT LUA_FOUND) - set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../lua) + set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../lib/lua) find_package(Lua REQUIRED) endif() From 472f35c4fd234766bf854c81c1e797accfe52d67 Mon Sep 17 00:00:00 2001 From: Bluub Date: Tue, 15 Jun 2021 17:41:08 +0200 Subject: [PATCH 29/78] try fix cmake --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 327fc8c4..7bdade0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ set(CMAKE_CXX_STANDARD 20) find_package(Lua QUIET) -if (NOT LUA_FOUND) +if (NOT Lua_FOUND) set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../lib/lua) find_package(Lua REQUIRED) endif() From 0b98cf771d092234e1f635d990dd67239a24f932 Mon Sep 17 00:00:00 2001 From: Bluub Date: Tue, 15 Jun 2021 17:47:05 +0200 Subject: [PATCH 30/78] try fix cmake --- CMakeLists.txt | 2 +- lib/lua/Findlua.cmake | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7bdade0c..327fc8c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ set(CMAKE_CXX_STANDARD 20) find_package(Lua QUIET) -if (NOT Lua_FOUND) +if (NOT LUA_FOUND) set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../lib/lua) find_package(Lua REQUIRED) endif() diff --git a/lib/lua/Findlua.cmake b/lib/lua/Findlua.cmake index 2afa3892..d087ccee 100644 --- a/lib/lua/Findlua.cmake +++ b/lib/lua/Findlua.cmake @@ -40,6 +40,18 @@ This is because, the lua location is not standardized and may exist in locations other than lua/ #]=======================================================================] +if (NOT LUA_FOUND) + INCLUDE(FetchContent) + + FetchContent_Declare(lua URL https://www.lua.org/ftp/lua-5.4.3.tar.gz) + FetchContent_GetProperties(lua) + if (NOT lua_POPULATED) + SET(FETCHCONTENT_QUIET NO) + FetchContent_Populate(lua) + ADD_SUBDIRECTORY(${lua_SOURCE_DIR}) + endif() +endif() + cmake_policy(PUSH) # Policies apply to functions at definition-time cmake_policy(SET CMP0012 NEW) # For while(TRUE) From d1174fa1e1c4edc420b31d164f3e327305f3b35c Mon Sep 17 00:00:00 2001 From: Bluub Date: Tue, 15 Jun 2021 17:50:08 +0200 Subject: [PATCH 31/78] try fix cmake --- CMakeLists.txt | 3 +-- lib/lua/Findlua.cmake | 12 ------------ 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 327fc8c4..a7735c0e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,10 +3,9 @@ project(bomberman) set(CMAKE_CXX_STANDARD 20) - find_package(Lua QUIET) if (NOT LUA_FOUND) - set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../lib/lua) + set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/lib/lua) find_package(Lua REQUIRED) endif() diff --git a/lib/lua/Findlua.cmake b/lib/lua/Findlua.cmake index d087ccee..2afa3892 100644 --- a/lib/lua/Findlua.cmake +++ b/lib/lua/Findlua.cmake @@ -40,18 +40,6 @@ This is because, the lua location is not standardized and may exist in locations other than lua/ #]=======================================================================] -if (NOT LUA_FOUND) - INCLUDE(FetchContent) - - FetchContent_Declare(lua URL https://www.lua.org/ftp/lua-5.4.3.tar.gz) - FetchContent_GetProperties(lua) - if (NOT lua_POPULATED) - SET(FETCHCONTENT_QUIET NO) - FetchContent_Populate(lua) - ADD_SUBDIRECTORY(${lua_SOURCE_DIR}) - endif() -endif() - cmake_policy(PUSH) # Policies apply to functions at definition-time cmake_policy(SET CMP0012 NEW) # For while(TRUE) From dd55e19dadcd7efc86a5c521a12dbf95ee179501 Mon Sep 17 00:00:00 2001 From: Bluub Date: Wed, 16 Jun 2021 09:54:14 +0200 Subject: [PATCH 32/78] try fix cmake --- CMakeLists.txt | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a7735c0e..d47b346f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,19 @@ project(bomberman) set(CMAKE_CXX_STANDARD 20) +cmake_minimum_required(VERSION 3.10) +include(ExternalProject) + +ExternalProject_Add(lua + URL "https://www.lua.org/ftp/lua-5.4.3.tar.gz" + CONFIGURE_COMMAND "" + BUILD_COMMAND make generic + BUILD_ALWAYS true + BUILD_IN_SOURCE true + INSTALL_COMMAND "" +) +ExternalProject_Get_property(lua SOURCE_DIR) + find_package(Lua QUIET) if (NOT LUA_FOUND) set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/lib/lua) @@ -172,7 +185,7 @@ add_executable(unit_tests EXCLUDE_FROM_ALL tests/CollisionTest.cpp ) target_include_directories(unit_tests PUBLIC sources) -target_link_libraries(unit_tests PUBLIC wal ray lua) +target_link_libraries(unit_tests PUBLIC wal ray ${LUA_LIBRARIES}) find_package(Catch2 QUIET) if (NOT Catch2_FOUND) From 5929119dd3b09fc395f9a5cb9a5eb475ebab9b06 Mon Sep 17 00:00:00 2001 From: Bluub Date: Wed, 16 Jun 2021 10:02:12 +0200 Subject: [PATCH 33/78] try fix cmake --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index d47b346f..96b359a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,9 @@ ExternalProject_Add(lua ) ExternalProject_Get_property(lua SOURCE_DIR) +set(LUA_LIBRARIES ${PROJECT_SOURCE_DIR}/lua-prefix/src/lua/src/lua ${PROJECT_SOURCE_DIR}/lua-prefix/src/lua/src/lualib.a) +set(LUA_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/lua-prefix/src/lua/src) + find_package(Lua QUIET) if (NOT LUA_FOUND) set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/lib/lua) From 504823a72306ae970abbf780b74266b0d8ffa162 Mon Sep 17 00:00:00 2001 From: Bluub Date: Wed, 16 Jun 2021 10:04:28 +0200 Subject: [PATCH 34/78] try fix cmake --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 96b359a6..47fe4565 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ ExternalProject_Add(lua ) ExternalProject_Get_property(lua SOURCE_DIR) -set(LUA_LIBRARIES ${PROJECT_SOURCE_DIR}/lua-prefix/src/lua/src/lua ${PROJECT_SOURCE_DIR}/lua-prefix/src/lua/src/lualib.a) +set(LUA_LIBRARIES ./lua-prefix/src/lua/src/lua ./lua-prefix/src/lua/src/lualib.a) set(LUA_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/lua-prefix/src/lua/src) find_package(Lua QUIET) From 0d63fbab6c5aae0875991ca5678fa4bd4725d55d Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Wed, 16 Jun 2021 11:52:32 +0200 Subject: [PATCH 35/78] win size --- lib/Ray/sources/Window.cpp | 11 ++++- lib/Ray/sources/Window.hpp | 7 ++- sources/System/Renderer/RenderSystem.cpp | 58 ++++++++++++++++++++++++ sources/System/Renderer/RenderSystem.hpp | 15 ++++++ 4 files changed, 88 insertions(+), 3 deletions(-) diff --git a/lib/Ray/sources/Window.cpp b/lib/Ray/sources/Window.cpp index 8a41d850..71f531d6 100644 --- a/lib/Ray/sources/Window.cpp +++ b/lib/Ray/sources/Window.cpp @@ -70,11 +70,20 @@ bool RAY::Window::isFocused(void) const return IsWindowFocused(); } -const RAY::Vector2 &RAY::Window::getDimensions(void) const +const RAY::Vector2 &RAY::Window::getDimensions(void) { + this->_dimensions.x = GetScreenWidth(); + this->_dimensions.y = GetScreenHeight(); return this->_dimensions; } +RAY::Window &RAY::Window::setDimensions(const Vector2 &dims) +{ + this->_dimensions = dims; + SetWindowSize(dims.x, dims.y); + return *this; +} + void RAY::Window::setVisibleCursor(bool visible) { if (visible) diff --git a/lib/Ray/sources/Window.hpp b/lib/Ray/sources/Window.hpp index 525f2992..1d346b5e 100644 --- a/lib/Ray/sources/Window.hpp +++ b/lib/Ray/sources/Window.hpp @@ -38,7 +38,7 @@ namespace RAY { static Window &getInstance(); //! @return A widow insta,ce. Only one window can be open at a time - static Window &getInstance(int width, int height, const std::string &title, unsigned flags = 0, bool openNow = true) noexcept; + static Window &getInstance(int width, int height, const std::string &title, unsigned flags = FLAG_WINDOW_RESIZABLE, bool openNow = true) noexcept; //! @brief A window is movable. Window(Window &&) = default; @@ -64,8 +64,11 @@ namespace RAY { //! @brief Check if window is currently focused bool isFocused(void) const; + //! @brief Get window dimensions + const RAY::Vector2 &getDimensions(void); + //! @brief Set window dimensions - const RAY::Vector2 &getDimensions(void) const; + RAY::Window &setDimensions(const Vector2 &dims); //! @brief Set the cursor visibility //! @param visible True if the cursor is visible diff --git a/sources/System/Renderer/RenderSystem.cpp b/sources/System/Renderer/RenderSystem.cpp index d21065c2..f5349209 100644 --- a/sources/System/Renderer/RenderSystem.cpp +++ b/sources/System/Renderer/RenderSystem.cpp @@ -10,10 +10,15 @@ #include "Component/Renderer/Drawable2DComponent.hpp" #include #include "Drawables/ADrawable3D.hpp" +#include "Drawables/ADrawable2D.hpp" #include "Component/Shaders/ShaderComponent.hpp" #include #include "Models/Vector3.hpp" #include "Component/Collision/CollisionComponent.hpp" +#include +#include + +namespace RAY2D = RAY::Drawables::Drawables2D; namespace BBM { @@ -40,11 +45,60 @@ namespace BBM drawable.drawable->drawWiresOn(this->_window); } + void RenderSystem::rescaleDrawablePosition(RAY::Drawables::ADrawable2D &drawable, const Vector2f &newDims) + { + RAY::Vector2 newPosition; + RAY::Vector2 oldPosition(drawable.getPosition()); + + newPosition.x = (oldPosition.x * newDims.x) / this->_previousDims.x; + newPosition.y = (oldPosition.y * newDims.y) / this->_previousDims.y; + + drawable.setPosition(newPosition); + } + + void RenderSystem::rescaleDrawable(RAY::Drawables::ADrawable2D &drawable, const Vector2f &newDims) + { + this->rescaleDrawablePosition(drawable, newDims); + RAY2D::Text *text = dynamic_cast(&drawable); + + if (text) { + float oldHeightSize = text->getFontSize(); + float oldWidthSize = text->getFontSize() + text->getLetterSpacing(); + float newHeightSize = oldHeightSize * newDims.y / this->_previousDims.y; + float newWidthSize = oldWidthSize * newDims.x / this->_previousDims.x; + text->setFontSize((newWidthSize + newHeightSize) / 2); + return; + } + RAY2D::Rectangle *rect = dynamic_cast(&drawable); + + if (rect) { + float oldHeightSize = rect->getHeight(); + float oldWidthSize = rect->getWidth(); + rect->setHeight(oldHeightSize * newDims.y / this->_previousDims.y); + rect->setWidth(oldWidthSize * newDims.x / this->_previousDims.x); + return; + } + throw std::runtime_error(std::string("No rescaling avalable for this drawable: ") + std::string(typeid(drawable).name())); + } + + void RenderSystem::resizeWindow(Vector2f &newDims) + { + if (newDims == this->_previousDims) + return; + newDims.y = (newDims.x * 720) / 1280; + std::cout << newDims.x << " " << newDims.y << std::endl; + this->_window.setDimensions(newDims); + } + void RenderSystem::onSelfUpdate() { this->_camera.update(); this->_window.beginDrawing(); this->_window.clear(); + RAY::Vector2 rayWinDims = this->_window.getDimensions(); + Vector2f windowDimensions(rayWinDims.x, rayWinDims.y); + + this->resizeWindow(windowDimensions); this->_window.useCamera(this->_camera); for (auto &[entity, pos, drawable] : this->_wal.getScene()->view()) { @@ -68,6 +122,8 @@ namespace BBM if (shader) { RAY::Shader::BeginUsingCustomShader(shader->getShader()); } + if (windowDimensions != this->_previousDims) + this->rescaleDrawable(*drawable.drawable, windowDimensions); drawable.drawable->setPosition(Vector2f(pos.position.x, pos.position.y)); drawable.drawable->drawOn(this->_window); if (shader) { @@ -77,6 +133,8 @@ namespace BBM if (this->_debugMode) this->_window.drawFPS(Vector2f(10, 10)); this->_window.endDrawing(); + if (windowDimensions != this->_previousDims) + this->_previousDims = windowDimensions; } void RenderSystem::onUpdate(WAL::ViewEntity &entity, diff --git a/sources/System/Renderer/RenderSystem.hpp b/sources/System/Renderer/RenderSystem.hpp index bff17267..c1e3705d 100644 --- a/sources/System/Renderer/RenderSystem.hpp +++ b/sources/System/Renderer/RenderSystem.hpp @@ -11,6 +11,7 @@ #include "Camera/Camera2D.hpp" #include "Window.hpp" #include "Wal.hpp" +#include "Models/Vector2.hpp" namespace BBM { @@ -26,9 +27,23 @@ namespace BBM //! @brief Defines if the debug informations must be displayed or not bool _debugMode; + Vector2f _previousDims = {1920, 1080}; + //! @brief Window framerate limit static constexpr short FPS = 60; + //! @brief rescale the drawables dimensions according to new window dimensions + //! @param drawable the drawable to rescale + //! @param newDims the new window's dimensions + void rescaleDrawable(RAY::Drawables::ADrawable2D &drawable, const Vector2f &newDims); + + //! @brief rescale the drawables position according to new window dimensions + //! @param drawable the drawable to rescale position of + //! @param newDims the new window's dimensions + void rescaleDrawablePosition(RAY::Drawables::ADrawable2D &drawable, const Vector2f &newDims); + + void resizeWindow(Vector2f &newDims); + public: //! @brief A method called after all entities that this system manage has been updated. //! @note render on screen here From 62905e818d271ee9d6cd4e4f868758f32b3e78de Mon Sep 17 00:00:00 2001 From: Bluub Date: Wed, 16 Jun 2021 11:55:11 +0200 Subject: [PATCH 36/78] try fix cmake --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 47fe4565..d131ab89 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ ExternalProject_Add(lua ) ExternalProject_Get_property(lua SOURCE_DIR) -set(LUA_LIBRARIES ./lua-prefix/src/lua/src/lua ./lua-prefix/src/lua/src/lualib.a) +set(LUA_LIBRARIES ${PROJECT}/lua-prefix/src/lua/src/lua ${PROJECT_SOURCE_DIR}/lua-prefix/src/lua/src/lualib.a) set(LUA_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/lua-prefix/src/lua/src) find_package(Lua QUIET) From d7751422f7eb6fe49a90cdc0b61f8393b6879eaa Mon Sep 17 00:00:00 2001 From: Bluub Date: Wed, 16 Jun 2021 12:06:08 +0200 Subject: [PATCH 37/78] try fix cmake --- CMakeLists.txt | 14 -------------- lib/lua/Findlua.cmake | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d131ab89..343e2324 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,20 +4,6 @@ project(bomberman) set(CMAKE_CXX_STANDARD 20) cmake_minimum_required(VERSION 3.10) -include(ExternalProject) - -ExternalProject_Add(lua - URL "https://www.lua.org/ftp/lua-5.4.3.tar.gz" - CONFIGURE_COMMAND "" - BUILD_COMMAND make generic - BUILD_ALWAYS true - BUILD_IN_SOURCE true - INSTALL_COMMAND "" -) -ExternalProject_Get_property(lua SOURCE_DIR) - -set(LUA_LIBRARIES ${PROJECT}/lua-prefix/src/lua/src/lua ${PROJECT_SOURCE_DIR}/lua-prefix/src/lua/src/lualib.a) -set(LUA_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/lua-prefix/src/lua/src) find_package(Lua QUIET) if (NOT LUA_FOUND) diff --git a/lib/lua/Findlua.cmake b/lib/lua/Findlua.cmake index 2afa3892..c92c71d5 100644 --- a/lib/lua/Findlua.cmake +++ b/lib/lua/Findlua.cmake @@ -40,6 +40,22 @@ This is because, the lua location is not standardized and may exist in locations other than lua/ #]=======================================================================] +include(ExternalProject) + +ExternalProject_Add(lua + URL "https://www.lua.org/ftp/lua-5.4.3.tar.gz" + CONFIGURE_COMMAND "" + BUILD_COMMAND make generic + BUILD_ALWAYS true + BUILD_IN_SOURCE true + INSTALL_COMMAND "" +) +ExternalProject_Get_property(lua SOURCE_DIR) + +set(LUA_LIBRARIES ${PROJECT_SOURCE_DIR}/lua-prefix/src/lua/src/lua ${PROJECT_SOURCE_DIR}/lua-prefix/src/lua/src/lualib.a) +set(LUA_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/lua-prefix/src/lua/src) + + cmake_policy(PUSH) # Policies apply to functions at definition-time cmake_policy(SET CMP0012 NEW) # For while(TRUE) From f0393f8ad0b0bf2bc1199c8a4a77741ee5f7ef3c Mon Sep 17 00:00:00 2001 From: Bluub Date: Wed, 16 Jun 2021 12:25:51 +0200 Subject: [PATCH 38/78] try fix cmake --- lib/lua/Findlua.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/lua/Findlua.cmake b/lib/lua/Findlua.cmake index c92c71d5..454b28e5 100644 --- a/lib/lua/Findlua.cmake +++ b/lib/lua/Findlua.cmake @@ -52,8 +52,8 @@ ExternalProject_Add(lua ) ExternalProject_Get_property(lua SOURCE_DIR) -set(LUA_LIBRARIES ${PROJECT_SOURCE_DIR}/lua-prefix/src/lua/src/lua ${PROJECT_SOURCE_DIR}/lua-prefix/src/lua/src/lualib.a) -set(LUA_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/lua-prefix/src/lua/src) +set(LUA_LIBRARIES ${SOURCE_DIR}/src/lua ${SOURCE_DIR}/src/lualib.a) +set(LUA_INCLUDE_DIR ${SOURCE_DIR}/src) cmake_policy(PUSH) # Policies apply to functions at definition-time From 797589a8a0f86592c185c6a7ba286d773a149b6a Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Wed, 16 Jun 2021 12:27:40 +0200 Subject: [PATCH 39/78] fix posiion rescaling --- lib/Ray/sources/Window.hpp | 2 +- sources/Runner/Runner.cpp | 2 +- sources/System/Renderer/RenderSystem.cpp | 17 ++++++----------- sources/System/Renderer/RenderSystem.hpp | 6 +++--- 4 files changed, 11 insertions(+), 16 deletions(-) diff --git a/lib/Ray/sources/Window.hpp b/lib/Ray/sources/Window.hpp index 1d346b5e..036e01ef 100644 --- a/lib/Ray/sources/Window.hpp +++ b/lib/Ray/sources/Window.hpp @@ -38,7 +38,7 @@ namespace RAY { static Window &getInstance(); //! @return A widow insta,ce. Only one window can be open at a time - static Window &getInstance(int width, int height, const std::string &title, unsigned flags = FLAG_WINDOW_RESIZABLE, bool openNow = true) noexcept; + static Window &getInstance(int width, int height, const std::string &title, unsigned flags = 0, bool openNow = true) noexcept; //! @brief A window is movable. Window(Window &&) = default; diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 647ccfd6..021addbd 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -93,7 +93,7 @@ namespace BBM void Runner::enableRaylib(WAL::Wal &wal) { RAY::TraceLog::setLevel(LOG_WARNING); - RAY::Window &window = RAY::Window::getInstance(1920, 1080, "Bomberman"); + RAY::Window &window = RAY::Window::getInstance(1920, 1080, "Bomberman", FLAG_WINDOW_RESIZABLE); wal.addSystem() .addSystem() .addSystem(window); diff --git a/sources/System/Renderer/RenderSystem.cpp b/sources/System/Renderer/RenderSystem.cpp index f5349209..946df471 100644 --- a/sources/System/Renderer/RenderSystem.cpp +++ b/sources/System/Renderer/RenderSystem.cpp @@ -45,20 +45,14 @@ namespace BBM drawable.drawable->drawWiresOn(this->_window); } - void RenderSystem::rescaleDrawablePosition(RAY::Drawables::ADrawable2D &drawable, const Vector2f &newDims) + void RenderSystem::rescaleDrawablePosition(Vector3f &position, const Vector2f &newWinDims) { - RAY::Vector2 newPosition; - RAY::Vector2 oldPosition(drawable.getPosition()); - - newPosition.x = (oldPosition.x * newDims.x) / this->_previousDims.x; - newPosition.y = (oldPosition.y * newDims.y) / this->_previousDims.y; - - drawable.setPosition(newPosition); + position.x = (position.x * newWinDims.x) / this->_previousDims.x; + position.y = (position.y * newWinDims.y) / this->_previousDims.y; } void RenderSystem::rescaleDrawable(RAY::Drawables::ADrawable2D &drawable, const Vector2f &newDims) { - this->rescaleDrawablePosition(drawable, newDims); RAY2D::Text *text = dynamic_cast(&drawable); if (text) { @@ -86,7 +80,6 @@ namespace BBM if (newDims == this->_previousDims) return; newDims.y = (newDims.x * 720) / 1280; - std::cout << newDims.x << " " << newDims.y << std::endl; this->_window.setDimensions(newDims); } @@ -122,8 +115,10 @@ namespace BBM if (shader) { RAY::Shader::BeginUsingCustomShader(shader->getShader()); } - if (windowDimensions != this->_previousDims) + if (windowDimensions != this->_previousDims) { + this->rescaleDrawablePosition(pos.position, windowDimensions); this->rescaleDrawable(*drawable.drawable, windowDimensions); + } drawable.drawable->setPosition(Vector2f(pos.position.x, pos.position.y)); drawable.drawable->drawOn(this->_window); if (shader) { diff --git a/sources/System/Renderer/RenderSystem.hpp b/sources/System/Renderer/RenderSystem.hpp index c1e3705d..3eca69ce 100644 --- a/sources/System/Renderer/RenderSystem.hpp +++ b/sources/System/Renderer/RenderSystem.hpp @@ -37,10 +37,10 @@ namespace BBM //! @param newDims the new window's dimensions void rescaleDrawable(RAY::Drawables::ADrawable2D &drawable, const Vector2f &newDims); - //! @brief rescale the drawables position according to new window dimensions - //! @param drawable the drawable to rescale position of + //! @brief rescale the drawables position according to new window dimensions + //! @param position a reference to position //! @param newDims the new window's dimensions - void rescaleDrawablePosition(RAY::Drawables::ADrawable2D &drawable, const Vector2f &newDims); + void rescaleDrawablePosition(Vector3f &position, const Vector2f &newWinDims); void resizeWindow(Vector2f &newDims); From 9d38d5f81c14cb9007c4e83a59a4b5b4e5a510ef Mon Sep 17 00:00:00 2001 From: Bluub Date: Wed, 16 Jun 2021 14:21:11 +0200 Subject: [PATCH 40/78] try fix cmake --- CMakeLists.txt | 3 +-- lib/lua/{Findlua.cmake => FindLua.cmake} | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) rename lib/lua/{Findlua.cmake => FindLua.cmake} (98%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 343e2324..2353f001 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,9 +5,8 @@ set(CMAKE_CXX_STANDARD 20) cmake_minimum_required(VERSION 3.10) -find_package(Lua QUIET) if (NOT LUA_FOUND) - set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/lib/lua) + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/lib/lua/) find_package(Lua REQUIRED) endif() diff --git a/lib/lua/Findlua.cmake b/lib/lua/FindLua.cmake similarity index 98% rename from lib/lua/Findlua.cmake rename to lib/lua/FindLua.cmake index 454b28e5..afc099f9 100644 --- a/lib/lua/Findlua.cmake +++ b/lib/lua/FindLua.cmake @@ -51,6 +51,7 @@ ExternalProject_Add(lua INSTALL_COMMAND "" ) ExternalProject_Get_property(lua SOURCE_DIR) +message("wow") set(LUA_LIBRARIES ${SOURCE_DIR}/src/lua ${SOURCE_DIR}/src/lualib.a) set(LUA_INCLUDE_DIR ${SOURCE_DIR}/src) @@ -243,7 +244,7 @@ if (LUA_LIBRARY) endif () endif () -include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) +include(${CMAKE_SOURCE_DIR}/cmake/Modules/FindPackageHandleStandardArgs.cmake) # handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if # all listed variables are TRUE FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua From 991d1e2f5ba26a6777102ca50d17072233127621 Mon Sep 17 00:00:00 2001 From: Bluub Date: Wed, 16 Jun 2021 14:25:33 +0200 Subject: [PATCH 41/78] only find package lua --- CMakeLists.txt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2353f001..f7fa7d4f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,10 +5,12 @@ set(CMAKE_CXX_STANDARD 20) cmake_minimum_required(VERSION 3.10) -if (NOT LUA_FOUND) - set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/lib/lua/) - find_package(Lua REQUIRED) -endif() + +find_package(Lua REQUIRED) +#if (NOT LUA_FOUND) +# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/lib/lua/) +# find_package(Lua REQUIRED) +#endif() include_directories(bomberman ${LUA_INCLUDE_DIR}) include_directories(bomberman lib/Ray/sources) From 857e9c6d370cb9a23e0d1e3fcbea8572d27844b8 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Wed, 16 Jun 2021 14:30:35 +0200 Subject: [PATCH 42/78] Fixing lua cmake --- CMakeLists.txt | 9 +- lib/LuaGate/CMakeLists.txt | 14 +- lib/lua/Findlua.cmake | 255 ------------------------------------- 3 files changed, 7 insertions(+), 271 deletions(-) delete mode 100644 lib/lua/Findlua.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 343e2324..c724de45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,13 +5,6 @@ set(CMAKE_CXX_STANDARD 20) cmake_minimum_required(VERSION 3.10) -find_package(Lua QUIET) -if (NOT LUA_FOUND) - set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/lib/lua) - find_package(Lua REQUIRED) -endif() - -include_directories(bomberman ${LUA_INCLUDE_DIR}) include_directories(bomberman lib/Ray/sources) include_directories(bomberman lib/wal/sources) include_directories(bomberman lib/LuaGate/sources) @@ -157,7 +150,7 @@ set(SOURCES add_executable(bomberman sources/main.cpp ${SOURCES} - ) +) target_include_directories(bomberman PUBLIC sources ${LUA_INCLUDE_DIR}) target_link_libraries(bomberman PUBLIC wal ray ${LUA_LIBRARIES} LuaGate) diff --git a/lib/LuaGate/CMakeLists.txt b/lib/LuaGate/CMakeLists.txt index ae7c7c4d..527fd990 100644 --- a/lib/LuaGate/CMakeLists.txt +++ b/lib/LuaGate/CMakeLists.txt @@ -1,4 +1,3 @@ -#Definition of CMake version to use CMAKE_MINIMUM_REQUIRED(VERSION 3.11) set(CMAKE_CXX_STANDARD 20) set(LIB_NAME "LuaGate") @@ -11,18 +10,17 @@ if (CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}") endif () - -find_package(Lua REQUIRED) -include_directories(${LIB_NAME} ${LUA_INCLUDE_DIR}) - set(HEADERS sources/LuaGate.hpp ) set(SRC - sources/LuaGate.cpp + sources/LuaGate.cpp ) add_library(${LIB_NAME} STATIC ${SRC} ${HEADERS}) -target_compile_definitions(${LIB_NAME} INTERFACE INTERNAL=private PRIVATE INTERNAL=public) -target_link_libraries(${LIB_NAME} ${LUA_LIBRARIES}) \ No newline at end of file + + +include(FindLua) +include_directories(${LIB_NAME} ${LUA_INCLUDE_DIR}) +target_link_libraries(${LIB_NAME} ${LUA_LIBRARIES}) diff --git a/lib/lua/Findlua.cmake b/lib/lua/Findlua.cmake deleted file mode 100644 index 454b28e5..00000000 --- a/lib/lua/Findlua.cmake +++ /dev/null @@ -1,255 +0,0 @@ -# Distributed under the OSI-approved BSD 3-Clause License. See accompanying -# file Copyright.txt or https://cmake.org/licensing for details. - -#[=======================================================================[.rst: -FindLua -------- - -Locate Lua library. - -.. versionadded:: 3.18 - Support for Lua 5.4. - -This module defines:: - -:: - - LUA_FOUND - if false, do not try to link to Lua - LUA_LIBRARIES - both lua and lualib - LUA_INCLUDE_DIR - where to find lua.h - LUA_VERSION_STRING - the version of Lua found - LUA_VERSION_MAJOR - the major version of Lua - LUA_VERSION_MINOR - the minor version of Lua - LUA_VERSION_PATCH - the patch version of Lua - - - -Note that the expected include convention is - -:: - - #include "lua.h" - -and not - -:: - - #include - -This is because, the lua location is not standardized and may exist in -locations other than lua/ -#]=======================================================================] - -include(ExternalProject) - -ExternalProject_Add(lua - URL "https://www.lua.org/ftp/lua-5.4.3.tar.gz" - CONFIGURE_COMMAND "" - BUILD_COMMAND make generic - BUILD_ALWAYS true - BUILD_IN_SOURCE true - INSTALL_COMMAND "" -) -ExternalProject_Get_property(lua SOURCE_DIR) - -set(LUA_LIBRARIES ${SOURCE_DIR}/src/lua ${SOURCE_DIR}/src/lualib.a) -set(LUA_INCLUDE_DIR ${SOURCE_DIR}/src) - - -cmake_policy(PUSH) # Policies apply to functions at definition-time -cmake_policy(SET CMP0012 NEW) # For while(TRUE) - -unset(_lua_include_subdirs) -unset(_lua_library_names) -unset(_lua_append_versions) - -# this is a function only to have all the variables inside go away automatically -function(_lua_get_versions) - set(LUA_VERSIONS5 5.4 5.3 5.2 5.1 5.0) - - if (Lua_FIND_VERSION_EXACT) - if (Lua_FIND_VERSION_COUNT GREATER 1) - set(_lua_append_versions ${Lua_FIND_VERSION_MAJOR}.${Lua_FIND_VERSION_MINOR}) - endif () - elseif (Lua_FIND_VERSION) - # once there is a different major version supported this should become a loop - if (NOT Lua_FIND_VERSION_MAJOR GREATER 5) - if (Lua_FIND_VERSION_COUNT EQUAL 1) - set(_lua_append_versions ${LUA_VERSIONS5}) - else () - foreach (subver IN LISTS LUA_VERSIONS5) - if (NOT subver VERSION_LESS ${Lua_FIND_VERSION}) - list(APPEND _lua_append_versions ${subver}) - endif () - endforeach () - # New version -> Search for it (heuristic only! Defines in include might have changed) - if (NOT _lua_append_versions) - set(_lua_append_versions ${Lua_FIND_VERSION_MAJOR}.${Lua_FIND_VERSION_MINOR}) - endif() - endif () - endif () - else () - # once there is a different major version supported this should become a loop - set(_lua_append_versions ${LUA_VERSIONS5}) - endif () - - if (LUA_Debug) - message(STATUS "Considering following Lua versions: ${_lua_append_versions}") - endif() - - set(_lua_append_versions "${_lua_append_versions}" PARENT_SCOPE) -endfunction() - -function(_lua_set_version_vars) - set(_lua_include_subdirs_raw "lua") - - foreach (ver IN LISTS _lua_append_versions) - string(REGEX MATCH "^([0-9]+)\\.([0-9]+)$" _ver "${ver}") - list(APPEND _lua_include_subdirs_raw - lua${CMAKE_MATCH_1}${CMAKE_MATCH_2} - lua${CMAKE_MATCH_1}.${CMAKE_MATCH_2} - lua-${CMAKE_MATCH_1}.${CMAKE_MATCH_2} - ) - endforeach () - - # Prepend "include/" to each path directly after the path - set(_lua_include_subdirs "include") - foreach (dir IN LISTS _lua_include_subdirs_raw) - list(APPEND _lua_include_subdirs "${dir}" "include/${dir}") - endforeach () - - set(_lua_include_subdirs "${_lua_include_subdirs}" PARENT_SCOPE) -endfunction(_lua_set_version_vars) - -function(_lua_get_header_version) - unset(LUA_VERSION_STRING PARENT_SCOPE) - set(_hdr_file "${LUA_INCLUDE_DIR}/lua.h") - - if (NOT EXISTS "${_hdr_file}") - return() - endif () - - # At least 5.[012] have different ways to express the version - # so all of them need to be tested. Lua 5.2 defines LUA_VERSION - # and LUA_RELEASE as joined by the C preprocessor, so avoid those. - file(STRINGS "${_hdr_file}" lua_version_strings - REGEX "^#define[ \t]+LUA_(RELEASE[ \t]+\"Lua [0-9]|VERSION([ \t]+\"Lua [0-9]|_[MR])).*") - - string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_MAJOR[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_MAJOR ";${lua_version_strings};") - if (LUA_VERSION_MAJOR MATCHES "^[0-9]+$") - string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_MINOR[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_MINOR ";${lua_version_strings};") - string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_RELEASE[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_PATCH ";${lua_version_strings};") - set(LUA_VERSION_STRING "${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}.${LUA_VERSION_PATCH}") - else () - string(REGEX REPLACE ".*;#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([0-9.]+)\"[ \t]*;.*" "\\1" LUA_VERSION_STRING ";${lua_version_strings};") - if (NOT LUA_VERSION_STRING MATCHES "^[0-9.]+$") - string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION[ \t]+\"Lua ([0-9.]+)\"[ \t]*;.*" "\\1" LUA_VERSION_STRING ";${lua_version_strings};") - endif () - string(REGEX REPLACE "^([0-9]+)\\.[0-9.]*$" "\\1" LUA_VERSION_MAJOR "${LUA_VERSION_STRING}") - string(REGEX REPLACE "^[0-9]+\\.([0-9]+)[0-9.]*$" "\\1" LUA_VERSION_MINOR "${LUA_VERSION_STRING}") - string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]).*" "\\1" LUA_VERSION_PATCH "${LUA_VERSION_STRING}") - endif () - foreach (ver IN LISTS _lua_append_versions) - if (ver STREQUAL "${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}") - set(LUA_VERSION_MAJOR ${LUA_VERSION_MAJOR} PARENT_SCOPE) - set(LUA_VERSION_MINOR ${LUA_VERSION_MINOR} PARENT_SCOPE) - set(LUA_VERSION_PATCH ${LUA_VERSION_PATCH} PARENT_SCOPE) - set(LUA_VERSION_STRING ${LUA_VERSION_STRING} PARENT_SCOPE) - return() - endif () - endforeach () -endfunction(_lua_get_header_version) - -function(_lua_find_header) - _lua_set_version_vars() - - # Initialize as local variable - set(CMAKE_IGNORE_PATH ${CMAKE_IGNORE_PATH}) - while (TRUE) - # Find the next header to test. Check each possible subdir in order - # This prefers e.g. higher versions as they are earlier in the list - # It is also consistent with previous versions of FindLua - foreach (subdir IN LISTS _lua_include_subdirs) - find_path(LUA_INCLUDE_DIR lua.h - HINTS ENV LUA_DIR - PATH_SUFFIXES ${subdir} - ) - if (LUA_INCLUDE_DIR) - break() - endif() - endforeach() - # Did not found header -> Fail - if (NOT LUA_INCLUDE_DIR) - return() - endif() - _lua_get_header_version() - # Found accepted version -> Ok - if (LUA_VERSION_STRING) - if (LUA_Debug) - message(STATUS "Found suitable version ${LUA_VERSION_STRING} in ${LUA_INCLUDE_DIR}/lua.h") - endif() - return() - endif() - # Found wrong version -> Ignore this path and retry - if (LUA_Debug) - message(STATUS "Ignoring unsuitable version in ${LUA_INCLUDE_DIR}") - endif() - list(APPEND CMAKE_IGNORE_PATH "${LUA_INCLUDE_DIR}") - unset(LUA_INCLUDE_DIR CACHE) - unset(LUA_INCLUDE_DIR) - unset(LUA_INCLUDE_DIR PARENT_SCOPE) - endwhile () -endfunction() - -_lua_get_versions() -_lua_find_header() -_lua_get_header_version() -unset(_lua_append_versions) - -if (LUA_VERSION_STRING) - set(_lua_library_names - lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR} - lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR} - lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR} - lua.${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR} - ) -endif () - -find_library(LUA_LIBRARY - NAMES ${_lua_library_names} lua - NAMES_PER_DIR - HINTS - ENV LUA_DIR - PATH_SUFFIXES lib -) -unset(_lua_library_names) - -if (LUA_LIBRARY) - # include the math library for Unix - if (UNIX AND NOT APPLE AND NOT BEOS) - find_library(LUA_MATH_LIBRARY m) - mark_as_advanced(LUA_MATH_LIBRARY) - set(LUA_LIBRARIES "${LUA_LIBRARY};${LUA_MATH_LIBRARY}") - - # include dl library for statically-linked Lua library - get_filename_component(LUA_LIB_EXT ${LUA_LIBRARY} EXT) - if(LUA_LIB_EXT STREQUAL CMAKE_STATIC_LIBRARY_SUFFIX) - list(APPEND LUA_LIBRARIES ${CMAKE_DL_LIBS}) - endif() - - # For Windows and Mac, don't need to explicitly include the math library - else () - set(LUA_LIBRARIES "${LUA_LIBRARY}") - endif () -endif () - -include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) -# handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if -# all listed variables are TRUE -FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua - REQUIRED_VARS LUA_LIBRARIES LUA_INCLUDE_DIR - VERSION_VAR LUA_VERSION_STRING) - -mark_as_advanced(LUA_INCLUDE_DIR LUA_LIBRARY) - -cmake_policy(POP) \ No newline at end of file From 508d86953d8a450e227619f8c882b9a3ed0dffd5 Mon Sep 17 00:00:00 2001 From: Bluub Date: Wed, 16 Jun 2021 14:49:42 +0200 Subject: [PATCH 43/78] cmake installing, need to fix lib not found --- CMakeLists.txt | 9 ++++----- lib/LuaGate/CMakeLists.txt | 1 - lib/LuaGate/sources/lua.hpp | 5 +++++ lib/lua/FindLua.cmake | 9 +++++---- 4 files changed, 14 insertions(+), 10 deletions(-) create mode 100644 lib/LuaGate/sources/lua.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f7fa7d4f..0b683c27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,11 +6,10 @@ set(CMAKE_CXX_STANDARD 20) cmake_minimum_required(VERSION 3.10) -find_package(Lua REQUIRED) -#if (NOT LUA_FOUND) -# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/lib/lua/) -# find_package(Lua REQUIRED) -#endif() +if (NOT LUA_FOUND) + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/lib/lua/") + find_package(Lua REQUIRED) +endif() include_directories(bomberman ${LUA_INCLUDE_DIR}) include_directories(bomberman lib/Ray/sources) diff --git a/lib/LuaGate/CMakeLists.txt b/lib/LuaGate/CMakeLists.txt index ae7c7c4d..c1f4cf7d 100644 --- a/lib/LuaGate/CMakeLists.txt +++ b/lib/LuaGate/CMakeLists.txt @@ -12,7 +12,6 @@ if (CMAKE_COMPILER_IS_GNUCXX) endif () -find_package(Lua REQUIRED) include_directories(${LIB_NAME} ${LUA_INCLUDE_DIR}) set(HEADERS diff --git a/lib/LuaGate/sources/lua.hpp b/lib/LuaGate/sources/lua.hpp new file mode 100644 index 00000000..5d6b3a05 --- /dev/null +++ b/lib/LuaGate/sources/lua.hpp @@ -0,0 +1,5 @@ +extern "C" { +#include "lua.h" +#include "lualib.h" +#include "lauxlib.h" +} \ No newline at end of file diff --git a/lib/lua/FindLua.cmake b/lib/lua/FindLua.cmake index afc099f9..137ce9d7 100644 --- a/lib/lua/FindLua.cmake +++ b/lib/lua/FindLua.cmake @@ -53,9 +53,6 @@ ExternalProject_Add(lua ExternalProject_Get_property(lua SOURCE_DIR) message("wow") -set(LUA_LIBRARIES ${SOURCE_DIR}/src/lua ${SOURCE_DIR}/src/lualib.a) -set(LUA_INCLUDE_DIR ${SOURCE_DIR}/src) - cmake_policy(PUSH) # Policies apply to functions at definition-time cmake_policy(SET CMP0012 NEW) # For while(TRUE) @@ -244,7 +241,11 @@ if (LUA_LIBRARY) endif () endif () -include(${CMAKE_SOURCE_DIR}/cmake/Modules/FindPackageHandleStandardArgs.cmake) + +set(LUA_LIBRARIES ${SOURCE_DIR}/src/lua ${SOURCE_DIR}/src/lualib.a) +set(LUA_INCLUDE_DIR ${SOURCE_DIR}/src) + +include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if # all listed variables are TRUE FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua From ec9dacf150fb6788d52fd7cb92c8e598ec15824d Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Wed, 16 Jun 2021 15:02:09 +0200 Subject: [PATCH 44/78] Trying to fix the CI for lua --- .github/workflows/build_web.yml | 2 ++ .github/workflows/build_windows.yml | 8 +++++++- .github/workflows/test.yml | 2 +- CMakeLists.txt | 4 +--- lib/LuaGate/CMakeLists.txt | 2 +- 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build_web.yml b/.github/workflows/build_web.yml index 2b9a2f3e..cfcc7e90 100644 --- a/.github/workflows/build_web.yml +++ b/.github/workflows/build_web.yml @@ -9,6 +9,8 @@ jobs: - uses: actions/checkout@v1 with: submodules: true + - name: Install lua + run: sudo apt install -y lua-devel - name: Exec shell: bash run: ./build_web.sh diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build_windows.yml index a3a21944..f6d3daf9 100644 --- a/.github/workflows/build_windows.yml +++ b/.github/workflows/build_windows.yml @@ -22,10 +22,16 @@ jobs: - name: Install Xorg lib if: matrix.name == 'Linux' run: | - sudo apt install -y libasound2-dev mesa-common-dev libx11-dev libxrandr-dev libxi-dev xorg-dev libgl1-mesa-dev libglu1-mesa-dev + sudo apt install -y libasound2-dev mesa-common-dev libx11-dev libxrandr-dev libxi-dev xorg-dev libgl1-mesa-dev libglu1-mesa-dev lua-devel - name: Update G++ if: matrix.name == 'Linux' run: sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 100 + - name: Install Lua + if: matrix.name == 'Windows' + shell: bash + run: | + curl https://sourceforge.net/projects/luabinaries/files/5.4.2/Windows%20Libraries/Dynamic/lua-5.4.2_Win64_dll16_lib.zip/download -L > lua.zip + unzip lua - name: Build run: | mkdir build && cd build diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e87b9b9d..02435bb5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,7 +12,7 @@ jobs: submodules: true - name: Install Xorg lib run: | - sudo apt install -y libasound2-dev mesa-common-dev libx11-dev libxrandr-dev libxi-dev xorg-dev libgl1-mesa-dev libglu1-mesa-dev + sudo apt install -y libasound2-dev mesa-common-dev libx11-dev libxrandr-dev libxi-dev xorg-dev libgl1-mesa-dev libglu1-mesa-dev lua-devel - name: Update G++ run: sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 100 - name: Build diff --git a/CMakeLists.txt b/CMakeLists.txt index c724de45..b61bcca1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,8 +3,6 @@ project(bomberman) set(CMAKE_CXX_STANDARD 20) -cmake_minimum_required(VERSION 3.10) - include_directories(bomberman lib/Ray/sources) include_directories(bomberman lib/wal/sources) include_directories(bomberman lib/LuaGate/sources) @@ -157,7 +155,7 @@ target_link_libraries(bomberman PUBLIC wal ray ${LUA_LIBRARIES} LuaGate) add_executable(unit_tests EXCLUDE_FROM_ALL ${SOURCES} - tests/CacheTest.cpp + tests/CacheTest.cpp tests/EntityTests.cpp tests/MainTest.cpp tests/EngineTests.cpp diff --git a/lib/LuaGate/CMakeLists.txt b/lib/LuaGate/CMakeLists.txt index 527fd990..371618e7 100644 --- a/lib/LuaGate/CMakeLists.txt +++ b/lib/LuaGate/CMakeLists.txt @@ -1,4 +1,4 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 3.11) +cmake_minimum_required(VERSION 3.11) set(CMAKE_CXX_STANDARD 20) set(LIB_NAME "LuaGate") From d1a69eefc501f01a06fb3859706009773729b6ab Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Wed, 16 Jun 2021 15:04:10 +0200 Subject: [PATCH 45/78] Fixing lua lib name --- .github/workflows/build_web.yml | 2 +- .github/workflows/build_windows.yml | 2 +- .github/workflows/test.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build_web.yml b/.github/workflows/build_web.yml index cfcc7e90..88d67e18 100644 --- a/.github/workflows/build_web.yml +++ b/.github/workflows/build_web.yml @@ -10,7 +10,7 @@ jobs: with: submodules: true - name: Install lua - run: sudo apt install -y lua-devel + run: sudo apt install -y liblua5.3-dev - name: Exec shell: bash run: ./build_web.sh diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build_windows.yml index f6d3daf9..192c4d0b 100644 --- a/.github/workflows/build_windows.yml +++ b/.github/workflows/build_windows.yml @@ -22,7 +22,7 @@ jobs: - name: Install Xorg lib if: matrix.name == 'Linux' run: | - sudo apt install -y libasound2-dev mesa-common-dev libx11-dev libxrandr-dev libxi-dev xorg-dev libgl1-mesa-dev libglu1-mesa-dev lua-devel + sudo apt install -y libasound2-dev mesa-common-dev libx11-dev libxrandr-dev libxi-dev xorg-dev libgl1-mesa-dev libglu1-mesa-dev liblua5.3-dev - name: Update G++ if: matrix.name == 'Linux' run: sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 100 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 02435bb5..ae5f9a29 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,7 +12,7 @@ jobs: submodules: true - name: Install Xorg lib run: | - sudo apt install -y libasound2-dev mesa-common-dev libx11-dev libxrandr-dev libxi-dev xorg-dev libgl1-mesa-dev libglu1-mesa-dev lua-devel + sudo apt install -y libasound2-dev mesa-common-dev libx11-dev libxrandr-dev libxi-dev xorg-dev libgl1-mesa-dev libglu1-mesa-dev liblua5.3-dev - name: Update G++ run: sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 100 - name: Build From ea1e2254273d99d74259b360fae34f3689ecab7c Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Wed, 16 Jun 2021 15:39:52 +0200 Subject: [PATCH 46/78] Removing lua.hpp in favor of an external C --- lib/LuaGate/sources/LuaGate.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/LuaGate/sources/LuaGate.hpp b/lib/LuaGate/sources/LuaGate.hpp index dfaa2965..f26bcdf5 100644 --- a/lib/LuaGate/sources/LuaGate.hpp +++ b/lib/LuaGate/sources/LuaGate.hpp @@ -3,7 +3,12 @@ // #include -#include "lua.hpp" + +extern "C" { + #include "lua.h" + #include "lualib.h" + #include "lauxlib.h" +} namespace LuaG { From 9ca15ecfff1d87d457b4e34c0e3d8b93e1b1ade9 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Wed, 16 Jun 2021 15:42:46 +0200 Subject: [PATCH 47/78] Removing uncapsulated includes --- sources/Component/IAControllable/IAControllableComponent.cpp | 1 - sources/Component/IAControllable/IAControllableComponent.hpp | 1 - 2 files changed, 2 deletions(-) diff --git a/sources/Component/IAControllable/IAControllableComponent.cpp b/sources/Component/IAControllable/IAControllableComponent.cpp index 5bfa2643..f594ef19 100644 --- a/sources/Component/IAControllable/IAControllableComponent.cpp +++ b/sources/Component/IAControllable/IAControllableComponent.cpp @@ -7,7 +7,6 @@ #include "Map/MapInfo.hpp" #include "Component/IAControllable/IAControllableComponent.hpp" -//#include "System/IAControllable/IAControllableSystem.hpp" namespace BBM { diff --git a/sources/Component/IAControllable/IAControllableComponent.hpp b/sources/Component/IAControllable/IAControllableComponent.hpp index 99e6393e..a1556662 100644 --- a/sources/Component/IAControllable/IAControllableComponent.hpp +++ b/sources/Component/IAControllable/IAControllableComponent.hpp @@ -11,7 +11,6 @@ #include "Component/Component.hpp" #include "Entity/Entity.hpp" #include "Models/Vector3.hpp" -#include "lua.hpp" #include "LuaGate.hpp" namespace BBM From 5af28111a291652bbe435f14b896a6722f651df2 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Wed, 16 Jun 2021 15:45:55 +0200 Subject: [PATCH 48/78] Adding a debug message in the cmake --- lib/LuaGate/CMakeLists.txt | 1 + lib/LuaGate/sources/LuaGate.hpp | 7 +------ 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/LuaGate/CMakeLists.txt b/lib/LuaGate/CMakeLists.txt index 371618e7..b7f21559 100644 --- a/lib/LuaGate/CMakeLists.txt +++ b/lib/LuaGate/CMakeLists.txt @@ -22,5 +22,6 @@ add_library(${LIB_NAME} STATIC ${SRC} ${HEADERS}) include(FindLua) +message(LUA INCLUDE PATH: ${LUA_INCLUDE_DIR}) include_directories(${LIB_NAME} ${LUA_INCLUDE_DIR}) target_link_libraries(${LIB_NAME} ${LUA_LIBRARIES}) diff --git a/lib/LuaGate/sources/LuaGate.hpp b/lib/LuaGate/sources/LuaGate.hpp index f26bcdf5..cf59833a 100644 --- a/lib/LuaGate/sources/LuaGate.hpp +++ b/lib/LuaGate/sources/LuaGate.hpp @@ -3,12 +3,7 @@ // #include - -extern "C" { - #include "lua.h" - #include "lualib.h" - #include "lauxlib.h" -} +#include namespace LuaG { From e05bdfcf0c6b5a8d213fb41343f969205617fc11 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Wed, 16 Jun 2021 15:52:30 +0200 Subject: [PATCH 49/78] Fixing the cmake --- CMakeLists.txt | 15 ++++++--------- lib/LuaGate/CMakeLists.txt | 15 ++++++--------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b61bcca1..72fa0713 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,10 +3,10 @@ project(bomberman) set(CMAKE_CXX_STANDARD 20) -include_directories(bomberman lib/Ray/sources) -include_directories(bomberman lib/wal/sources) -include_directories(bomberman lib/LuaGate/sources) -include_directories(bomberman sources) +include_directories(lib/Ray/sources) +include_directories(lib/wal/sources) +include_directories(lib/LuaGate/sources) +include_directories(sources) add_subdirectory(${PROJECT_SOURCE_DIR}/lib/wal) add_subdirectory(${PROJECT_SOURCE_DIR}/lib/Ray) @@ -149,9 +149,7 @@ add_executable(bomberman sources/main.cpp ${SOURCES} ) - -target_include_directories(bomberman PUBLIC sources ${LUA_INCLUDE_DIR}) -target_link_libraries(bomberman PUBLIC wal ray ${LUA_LIBRARIES} LuaGate) +target_link_libraries(bomberman PUBLIC wal ray LuaGate) add_executable(unit_tests EXCLUDE_FROM_ALL ${SOURCES} @@ -164,8 +162,7 @@ add_executable(unit_tests EXCLUDE_FROM_ALL tests/ViewTest.cpp tests/CollisionTest.cpp ) -target_include_directories(unit_tests PUBLIC sources) -target_link_libraries(unit_tests PUBLIC wal ray ${LUA_LIBRARIES}) +target_link_libraries(unit_tests PUBLIC wal ray LuaGate) find_package(Catch2 QUIET) if (NOT Catch2_FOUND) diff --git a/lib/LuaGate/CMakeLists.txt b/lib/LuaGate/CMakeLists.txt index b7f21559..666ffd3e 100644 --- a/lib/LuaGate/CMakeLists.txt +++ b/lib/LuaGate/CMakeLists.txt @@ -1,9 +1,8 @@ cmake_minimum_required(VERSION 3.11) set(CMAKE_CXX_STANDARD 20) -set(LIB_NAME "LuaGate") +project(LuaGate) -project("${LIB_NAME}") -include_directories(${LIB_NAME} ./sources) +include_directories(sources) if (CMAKE_COMPILER_IS_GNUCXX) set(GCC_COVERAGE_COMPILE_FLAGS "-Wall -Wextra -Werror -Wshadow") @@ -18,10 +17,8 @@ set(SRC sources/LuaGate.cpp ) -add_library(${LIB_NAME} STATIC ${SRC} ${HEADERS}) - - include(FindLua) -message(LUA INCLUDE PATH: ${LUA_INCLUDE_DIR}) -include_directories(${LIB_NAME} ${LUA_INCLUDE_DIR}) -target_link_libraries(${LIB_NAME} ${LUA_LIBRARIES}) +include_directories(${LUA_INCLUDE_DIR}) + +add_library(LuaGate STATIC ${SRC} ${HEADERS}) +target_link_libraries(LuaGate ${LUA_LIBRARIES}) From a0ea2a6018bb5dd3dfa13242cd3c041c87e9e00d Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Wed, 16 Jun 2021 16:00:01 +0200 Subject: [PATCH 50/78] Using lua includes as INTERFACE --- lib/LuaGate/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/LuaGate/CMakeLists.txt b/lib/LuaGate/CMakeLists.txt index 666ffd3e..4d553905 100644 --- a/lib/LuaGate/CMakeLists.txt +++ b/lib/LuaGate/CMakeLists.txt @@ -18,7 +18,7 @@ set(SRC ) include(FindLua) -include_directories(${LUA_INCLUDE_DIR}) add_library(LuaGate STATIC ${SRC} ${HEADERS}) +target_include_directories(LuaGate INTERFACE ${LUA_INCLUDE_DIR}) target_link_libraries(LuaGate ${LUA_LIBRARIES}) From 001d146e3adee3c11af533f3e4755dbd2e1acfb1 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Wed, 16 Jun 2021 16:03:00 +0200 Subject: [PATCH 51/78] Using public instead of interface --- lib/LuaGate/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/LuaGate/CMakeLists.txt b/lib/LuaGate/CMakeLists.txt index 4d553905..9e53daeb 100644 --- a/lib/LuaGate/CMakeLists.txt +++ b/lib/LuaGate/CMakeLists.txt @@ -20,5 +20,5 @@ set(SRC include(FindLua) add_library(LuaGate STATIC ${SRC} ${HEADERS}) -target_include_directories(LuaGate INTERFACE ${LUA_INCLUDE_DIR}) +target_include_directories(LuaGate PUBLIC ${LUA_INCLUDE_DIR}) target_link_libraries(LuaGate ${LUA_LIBRARIES}) From efba6bf3c4fa79d3ba52229911aed6a73e84e5c2 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Wed, 16 Jun 2021 16:55:08 +0200 Subject: [PATCH 52/78] Trying to fix windows compilation --- .../{build_windows.yml => build.yml} | 4 ++-- .github/workflows/build_linux.yml | 21 ------------------- CMakeLists.txt | 6 +++--- lib/LuaGate/CMakeLists.txt | 4 ++++ 4 files changed, 9 insertions(+), 26 deletions(-) rename .github/workflows/{build_windows.yml => build.yml} (96%) delete mode 100644 .github/workflows/build_linux.yml diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build.yml similarity index 96% rename from .github/workflows/build_windows.yml rename to .github/workflows/build.yml index 192c4d0b..1514d6b7 100644 --- a/.github/workflows/build_windows.yml +++ b/.github/workflows/build.yml @@ -9,8 +9,8 @@ jobs: strategy: matrix: include: - # - os: ubuntu-latest - # name: Linux + - os: ubuntu-latest + name: Linux # - os: macOS-latest # name: MacOS - os: windows-latest diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml deleted file mode 100644 index 9f352ac4..00000000 --- a/.github/workflows/build_linux.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Linux Build (Epitech Container) -on: [push, pull_request] - -jobs: - testbox: - if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository - runs-on: ubuntu-latest - container: - image: epitechcontent/epitest-docker:latest - steps: - - uses: actions/checkout@v2 - with: - submodules: true - - name: Build - run: | - mkdir build && cd build - cmake .. - cmake --build . - - name: CheckBinaryName - shell: bash - run: test -f build/bomberman \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 72fa0713..62a1882b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,10 +13,10 @@ add_subdirectory(${PROJECT_SOURCE_DIR}/lib/Ray) add_subdirectory(${PROJECT_SOURCE_DIR}/lib/LuaGate) if (EMSCRIPTEN) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 -s ASYNCIFY") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 -s ASYNCIFY") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 -s ASYNCIFY") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 -s ASYNCIFY") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s NO_DISABLE_EXCEPTION_CATCHING --shell-file ../sources/wasm/frontend.html --preload-file ../assets") - set(CMAKE_EXECUTABLE_SUFFIX ".html") + set(CMAKE_EXECUTABLE_SUFFIX ".html") endif() set(SOURCES diff --git a/lib/LuaGate/CMakeLists.txt b/lib/LuaGate/CMakeLists.txt index 9e53daeb..635d88bd 100644 --- a/lib/LuaGate/CMakeLists.txt +++ b/lib/LuaGate/CMakeLists.txt @@ -18,6 +18,10 @@ set(SRC ) include(FindLua) +if (NOT LUA_FOUND AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/include/lua.hpp) + set(LUA_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include/) + set(LUA_LIBRARIES ${CMAKE_CURRENT_SOURCE_DIR}) +endif() add_library(LuaGate STATIC ${SRC} ${HEADERS}) target_include_directories(LuaGate PUBLIC ${LUA_INCLUDE_DIR}) From 12db15d8a659cfaf987a33a2008da995a7a47c4d Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Wed, 16 Jun 2021 17:05:14 +0200 Subject: [PATCH 53/78] Second try --- .github/workflows/build.yml | 3 ++- lib/LuaGate/CMakeLists.txt | 11 ++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1514d6b7..19241197 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -name: Windows Build +name: Build on: [push, pull_request] jobs: @@ -7,6 +7,7 @@ jobs: runs-on: ${{ matrix.os }} if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository strategy: + fail-fast: false matrix: include: - os: ubuntu-latest diff --git a/lib/LuaGate/CMakeLists.txt b/lib/LuaGate/CMakeLists.txt index 635d88bd..a4d9ad74 100644 --- a/lib/LuaGate/CMakeLists.txt +++ b/lib/LuaGate/CMakeLists.txt @@ -18,9 +18,14 @@ set(SRC ) include(FindLua) -if (NOT LUA_FOUND AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/include/lua.hpp) - set(LUA_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include/) - set(LUA_LIBRARIES ${CMAKE_CURRENT_SOURCE_DIR}) +if (NOT LUA_FOUND) + if (EXISTS ${CMAKE_SOURCE_DIR}/include/lua.hpp) + message("Using local lua") + set(LUA_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include/) + set(LUA_LIBRARIES ${CMAKE_SOURCE_DIR}) + else() + message(FATAL_ERROR "Lua could not be found.") + endif() endif() add_library(LuaGate STATIC ${SRC} ${HEADERS}) From ddd848dd8cd09c339dae2530428a6b21d8b75fae Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Wed, 16 Jun 2021 17:12:24 +0200 Subject: [PATCH 54/78] Linking with the lua54.dll --- lib/LuaGate/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/LuaGate/CMakeLists.txt b/lib/LuaGate/CMakeLists.txt index a4d9ad74..d12cbc48 100644 --- a/lib/LuaGate/CMakeLists.txt +++ b/lib/LuaGate/CMakeLists.txt @@ -22,7 +22,7 @@ if (NOT LUA_FOUND) if (EXISTS ${CMAKE_SOURCE_DIR}/include/lua.hpp) message("Using local lua") set(LUA_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include/) - set(LUA_LIBRARIES ${CMAKE_SOURCE_DIR}) + set(LUA_LIBRARIES ${CMAKE_SOURCE_DIR}/lua54.dll) else() message(FATAL_ERROR "Lua could not be found.") endif() From 7af629535dce256a33bcf735be1eaffa92a5887a Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Wed, 16 Jun 2021 17:20:10 +0200 Subject: [PATCH 55/78] Linking with the .lib instead of the .dll --- lib/LuaGate/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/LuaGate/CMakeLists.txt b/lib/LuaGate/CMakeLists.txt index d12cbc48..eb227570 100644 --- a/lib/LuaGate/CMakeLists.txt +++ b/lib/LuaGate/CMakeLists.txt @@ -22,7 +22,7 @@ if (NOT LUA_FOUND) if (EXISTS ${CMAKE_SOURCE_DIR}/include/lua.hpp) message("Using local lua") set(LUA_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include/) - set(LUA_LIBRARIES ${CMAKE_SOURCE_DIR}/lua54.dll) + set(LUA_LIBRARIES ${CMAKE_SOURCE_DIR}/lua54.lib) else() message(FATAL_ERROR "Lua could not be found.") endif() From 164d964bef1d48b20e348c61800945bf8b8003bb Mon Sep 17 00:00:00 2001 From: Bluub Date: Wed, 16 Jun 2021 17:29:50 +0200 Subject: [PATCH 56/78] better john --- CMakeLists.txt | 9 +- ai_scripts/john.lua | 140 ++++++++++++++++-- .../IAControllable/IAControllableSystem.cpp | 2 +- 3 files changed, 137 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b683c27..191023b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,11 +5,12 @@ set(CMAKE_CXX_STANDARD 20) cmake_minimum_required(VERSION 3.10) +find_package(Lua REQUIRED) -if (NOT LUA_FOUND) - set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/lib/lua/") - find_package(Lua REQUIRED) -endif() +#if (NOT LUA_FOUND) +# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/lib/lua/") +# find_package(Lua REQUIRED) +#endif() include_directories(bomberman ${LUA_INCLUDE_DIR}) include_directories(bomberman lib/Ray/sources) diff --git a/ai_scripts/john.lua b/ai_scripts/john.lua index cfe5e235..09070f01 100644 --- a/ai_scripts/john.lua +++ b/ai_scripts/john.lua @@ -9,7 +9,7 @@ mapinfo.dist { } ------------ ------ Debug variables -local debug = false +local debug = true if not debug then log = function() end @@ -23,9 +23,13 @@ Dirs = {{x = 1, y = 0}, {x = -1, y = 0}, {x = 0, y = -1}, {x = 0, y = 1}} MaxX = 0 MaxY = 0 Map = {} +Danger = {} ----- Map functions function PrintMap(map, MaxX, maxZ) + log("---------") + log("PRINT MAP") + log("---------") for i=0,MaxX + 1 do local s = "| " for j=0,maxZ + 1 do @@ -47,32 +51,142 @@ function CreateMyMap(infos, MaxX, MaxY) for i, info in ipairs(infos) do map[info.x][info.y] = info.type end - PrintMap(map, MaxX, MaxY) + --PrintMap(map, MaxX, MaxY) return map end +function CreateDangerMap(dangers) + local danger = {} + for i=0,MaxX + 1 do + danger[i] = {} + for j=0,MaxY + 1 do + danger[i][j] = 0 + end + end + for i, zone in ipairs(dangers) do + danger[math.floor(zone.x)][math.floor(zone.y)] = math.floor(zone.level) + end + --PrintMap(danger, MaxX, MaxY) + return danger +end + function isInExplosionRange(mapinfo, x, y) for i, danger in ipairs(mapinfo.danger) do - if danger.x == x and danger.y == y then + if Danger[x][y] > 0 then return true end end return false end - ---- Pathfinding + +function setAdd(set, toAdd) + table.insert(set, toAdd) +end + +function setRemove(set, toRemove) + for i, node in ipairs(set) do + if node == toRemove then + set[i] = set[#set] + set[#set] = nil + break + end + end +end + +function not_in(set, node) + for _,value in pairs(set) do + if value == node then + return false + end + end + return true +end + + +function getNeighbors(node) + local neighbors = {} + for dir in Dirs do + local neighborX = node.x + dir.x + local neighborY = node.y + dir.y + + if neighborY <= MaxY and neighborX <= MaxX then + if neighborY >= 0 and neighborX >= 0 then + if Map[neighborX][neighborY] == 0 then + table.insert(neighbors, {x = neighborX, y = neighborY}) + end + end + end + end +end + +function getLowestFromSet(set, f_score) + local lowest = 100000 + local best = nil + for _,node in ipairs(set) do + local score = f_score[node] + if score < lowest then + lowest = score + best = node + end + end + return best +end + +function fill_path(path, came_from, node) + if came_from[node] then + table.insert(path, 1, came_from[node]) + return fill_path(path, came_from, came_from[node]) + else + return path + end +end + +--A star search function pathfind(root, target) local closed = {} - local open = {} + local open = { root } local came_from = {} + + local g_score = {} + local f_score = {} + + g_score[root] = 0 + f_score[root] = dist(root, target) + + while #open > 0 do + local curr = getLowestFromSet(open, f_score) --get lowest node of openset + if curr.x == target.x and curr.y == target.y then + local path = fill_path({}, came_from, target) -- fill the path with came from + table.insert(path, target) + return path + end + setRemove(open, curr) -- remove curr from open + setAdd(closed, curr)-- add node to closed + + local neighbors = getNeighbors(curr) -- get neighbors of current + for _, neighbor in ipairs(neighbors) do + if not_in(closed, neighbor) then -- neighbor not in closed set + local try_g_score = g_score[curr] + 1 + if not_in(open, neighbor) or try_g_score < g_score[neighbor] then + came_from[neighbor] = curr + g_score[neighbor] = try_g_score + f_score[neighbor] = g_score[neighbor] + dist(neighbor, target) + if not_in(open, neighbor) then + setAdd(open, neighbor) + end + end + end + end + end end function dist(nodeA, nodeB) return math.sqrt(math.pow(nodeB.x - nodeA.x, 2) + math.pow(nodeB.y - nodeA.y, 2)) end -function getPathToSafeSpace(player, danger) +function getPathToSafeSpace(player) local minXesc = (player.x - 3 < 0) and 0 or (player.x - 3); local MaxXesc = (player.x + 3 > MaxX) and MaxX or (player.x + 3); local minYesc = (player.y - 3 < 0) and 0 or (player.y - 3); @@ -81,20 +195,26 @@ function getPathToSafeSpace(player, danger) local maybeSafeSpace = {} for i=minXesc,MaxXesc do for j=minYesc, MaxYesc do - if myMap[i][j] == 0 or danger[i][j] == 0 then + if Map[i][j] == 0 and Danger[i][j] == 0 then table.insert(maybeSafeSpace, {x = i, y = j}) end end end local minDist = 100000 local res = {} - for safe in pairs(maybeSafeSpace) do + for _, safe in ipairs(maybeSafeSpace) do local currDist = dist(player, safe) if currDist < minDist then minDist, res = currDist, safe end end local path = pathfind(player, res) + for _, n in ipairs(path) do + print("x") + print(n.x) + print("y") + print(n.y) + end end @@ -111,9 +231,11 @@ function Update(mapinfo) end end Map = CreateMyMap(mapinfo.raw, MaxX, MaxY) + Danger = CreateDangerMap(mapinfo.danger) + --PrintMap(Danger, MaxX, MaxY) local roundedPlayerPos = {x = math.floor(mapinfo.player.x+0.5), y = math.floor(mapinfo.player.y+0.5)} if (isInExplosionRange(mapinfo, roundedPlayerPos.x, roundedPlayerPos.y)) then - --local pathToSafeSpace = getPathToSafeSpace(roundedPlayerPos) + local pathToSafeSpace = getPathToSafeSpace(roundedPlayerPos) if (Map[roundedPlayerPos.x + 1][roundedPlayerPos.y] ~= 0) then return -1, 0, false, false else diff --git a/sources/System/IAControllable/IAControllableSystem.cpp b/sources/System/IAControllable/IAControllableSystem.cpp index f4baa9b5..01a1c90d 100644 --- a/sources/System/IAControllable/IAControllableSystem.cpp +++ b/sources/System/IAControllable/IAControllableSystem.cpp @@ -108,7 +108,7 @@ namespace BBM Vector3f bombPos = std::get<0>(bomb); int bombRadius = std::get<1>(bomb); std::chrono::nanoseconds timeleft = std::get<2>(bomb); - int dangerLevel = timeleft.count() / 1000000000; + int dangerLevel = std::chrono::duration_cast(timeleft).count(); if (dangerLevel == 0) dangerLevel = 1; pushInfoDangerPos(state, index, bombPos.x, bombPos.z, dangerLevel); From 09ad8b4efdd2755b71ff7d47036b5ab04166822b Mon Sep 17 00:00:00 2001 From: Bluub Date: Wed, 16 Jun 2021 18:56:49 +0200 Subject: [PATCH 57/78] ai scripts in assets --- a | 390 ++++++++++++++++++ {ai_scripts => assets/ai_scripts}/john.lua | 0 {ai_scripts => assets/ai_scripts}/randboi.lua | 0 sources/System/Lobby/LobbySystem.cpp | 2 +- 4 files changed, 391 insertions(+), 1 deletion(-) create mode 100644 a rename {ai_scripts => assets/ai_scripts}/john.lua (100%) rename {ai_scripts => assets/ai_scripts}/randboi.lua (100%) diff --git a/a b/a new file mode 100644 index 00000000..eecd15b0 --- /dev/null +++ b/a @@ -0,0 +1,390 @@ +--------- +PRINT MAP +--------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +--------- +PRINT MAP +--------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +--------- +PRINT MAP +--------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +--------- +PRINT MAP +--------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +--------- +PRINT MAP +--------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +--------- +PRINT MAP +--------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +--------- +PRINT MAP +--------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +--------- +PRINT MAP +--------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +--------- +PRINT MAP +--------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +--------- +PRINT MAP +--------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- +| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------------------------------------------------- diff --git a/ai_scripts/john.lua b/assets/ai_scripts/john.lua similarity index 100% rename from ai_scripts/john.lua rename to assets/ai_scripts/john.lua diff --git a/ai_scripts/randboi.lua b/assets/ai_scripts/randboi.lua similarity index 100% rename from ai_scripts/randboi.lua rename to assets/ai_scripts/randboi.lua diff --git a/sources/System/Lobby/LobbySystem.cpp b/sources/System/Lobby/LobbySystem.cpp index 9396e904..9e4c023b 100644 --- a/sources/System/Lobby/LobbySystem.cpp +++ b/sources/System/Lobby/LobbySystem.cpp @@ -186,7 +186,7 @@ namespace BBM player.addComponent(3); break; case ControllableComponent::AI: - player.addComponent("./ai_scripts/john.lua"); + player.addComponent("./assets/ai_scripts/john.lua"); break; default: throw std::runtime_error("Invalid controller for a player."); From f2a55699f758160afab519a8e18576c4507db4d0 Mon Sep 17 00:00:00 2001 From: Bluub Date: Wed, 16 Jun 2021 18:59:51 +0200 Subject: [PATCH 58/78] check if file exists before dofile --- sources/Component/IAControllable/IAControllableComponent.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sources/Component/IAControllable/IAControllableComponent.cpp b/sources/Component/IAControllable/IAControllableComponent.cpp index f594ef19..05f6eb9b 100644 --- a/sources/Component/IAControllable/IAControllableComponent.cpp +++ b/sources/Component/IAControllable/IAControllableComponent.cpp @@ -5,6 +5,7 @@ ** IAControllableComponent */ +#include #include "Map/MapInfo.hpp" #include "Component/IAControllable/IAControllableComponent.hpp" @@ -13,7 +14,8 @@ namespace BBM IAControllableComponent::IAControllableComponent(WAL::Entity &entity, std::string scriptPath) : Component(entity), _scriptPath(scriptPath), _state() { - _state.dofile(scriptPath); + if (std::filesystem::exists(scriptPath)) + _state.dofile(scriptPath); } WAL::Component *IAControllableComponent::clone(WAL::Entity &entity) const From bd758d858c26c3a0e9545188a96968540a25c4c1 Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Wed, 16 Jun 2021 20:25:21 +0200 Subject: [PATCH 59/78] win size adaptative --- sources/System/Renderer/RenderSystem.cpp | 50 +++++++++++++++--------- sources/System/Renderer/RenderSystem.hpp | 6 +-- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/sources/System/Renderer/RenderSystem.cpp b/sources/System/Renderer/RenderSystem.cpp index 9086a812..4d6a3043 100644 --- a/sources/System/Renderer/RenderSystem.cpp +++ b/sources/System/Renderer/RenderSystem.cpp @@ -45,22 +45,36 @@ namespace BBM drawable.drawable->drawWiresOn(this->_window); } - void RenderSystem::rescaleDrawablePosition(Vector3f &position, const Vector2f &newWinDims) + Vector2f RenderSystem::getRescaledPosition(Vector3f &position, const Vector2f &newWinDims) { - position.x = (position.x * newWinDims.x) / this->_previousDims.x; - position.y = (position.y * newWinDims.y) / this->_previousDims.y; + Vector2f newPosition; + newPosition.x = (position.x * newWinDims.x) / 1920; + newPosition.y = (position.y * newWinDims.y) / 1080; + return newPosition; } - void RenderSystem::rescaleDrawable(RAY::Drawables::ADrawable2D &drawable, const Vector2f &newDims) + void RenderSystem::drawRescaledDrawable(RAY::Drawables::ADrawable2D &drawable, const Vector2f &newDims) { RAY2D::Text *text = dynamic_cast(&drawable); if (text) { float oldHeightSize = text->getFontSize(); float oldWidthSize = text->getFontSize() + text->getLetterSpacing(); - float newHeightSize = oldHeightSize * newDims.y / this->_previousDims.y; - float newWidthSize = oldWidthSize * newDims.x / this->_previousDims.x; + float newHeightSize = oldHeightSize * newDims.y / 1080; + float newWidthSize = oldWidthSize * newDims.x / 1920; text->setFontSize((newWidthSize + newHeightSize) / 2); + drawable.drawOn(this->_window); + text->setFontSize(oldHeightSize); + return; + } + RAY::Texture *texture = dynamic_cast(&drawable); + + if (texture) { + float oldScale = texture->getScale(); + float newScale = (texture->getWidth() * newDims.x / 1920) / texture->getWidth(); + texture->setScale(newScale); + drawable.drawOn(this->_window); + texture->setScale(oldScale); return; } RAY2D::Rectangle *rect = dynamic_cast(&drawable); @@ -68,18 +82,22 @@ namespace BBM if (rect) { float oldHeightSize = rect->getHeight(); float oldWidthSize = rect->getWidth(); - rect->setHeight(oldHeightSize * newDims.y / this->_previousDims.y); - rect->setWidth(oldWidthSize * newDims.x / this->_previousDims.x); + rect->setHeight(oldHeightSize * newDims.y / 1080); + rect->setWidth(oldWidthSize * newDims.x / 1920); + drawable.drawOn(this->_window); + rect->setWidth(oldWidthSize); + rect->setHeight(oldHeightSize); return; } - throw std::runtime_error(std::string("No rescaling avalable for this drawable: ") + std::string(typeid(drawable).name())); } void RenderSystem::resizeWindow(Vector2f &newDims) { - if (newDims == this->_previousDims) - return; newDims.y = (newDims.x * 720) / 1280; + if (newDims.y < 720 || newDims.x < 1280) { + newDims.y = 720; + newDims.x = 1280; + } this->_window.setDimensions(newDims); } @@ -132,12 +150,8 @@ namespace BBM if (shader) { RAY::Shader::BeginUsingCustomShader(shader->getShader()); } - if (windowDimensions != this->_previousDims) { - this->rescaleDrawablePosition(pos.position, windowDimensions); - this->rescaleDrawable(*drawable.drawable, windowDimensions); - } - drawable.drawable->setPosition(Vector2f(pos.position.x, pos.position.y)); - drawable.drawable->drawOn(this->_window); + drawable.drawable->setPosition(this->getRescaledPosition(pos.position, windowDimensions)); + this->drawRescaledDrawable(*drawable.drawable, windowDimensions); if (shader) { RAY::Shader::EndUsingCustomShader(); } @@ -145,8 +159,6 @@ namespace BBM if (this->_debugMode) this->_window.drawFPS(Vector2f(10, 10)); this->_window.endDrawing(); - if (windowDimensions != this->_previousDims) - this->_previousDims = windowDimensions; } void RenderSystem::onUpdate(WAL::ViewEntity &entity, diff --git a/sources/System/Renderer/RenderSystem.hpp b/sources/System/Renderer/RenderSystem.hpp index 3eca69ce..0e229f2a 100644 --- a/sources/System/Renderer/RenderSystem.hpp +++ b/sources/System/Renderer/RenderSystem.hpp @@ -27,20 +27,18 @@ namespace BBM //! @brief Defines if the debug informations must be displayed or not bool _debugMode; - Vector2f _previousDims = {1920, 1080}; - //! @brief Window framerate limit static constexpr short FPS = 60; //! @brief rescale the drawables dimensions according to new window dimensions //! @param drawable the drawable to rescale //! @param newDims the new window's dimensions - void rescaleDrawable(RAY::Drawables::ADrawable2D &drawable, const Vector2f &newDims); + void drawRescaledDrawable(RAY::Drawables::ADrawable2D &drawable, const Vector2f &newDims); //! @brief rescale the drawables position according to new window dimensions //! @param position a reference to position //! @param newDims the new window's dimensions - void rescaleDrawablePosition(Vector3f &position, const Vector2f &newWinDims); + Vector2f getRescaledPosition(Vector3f &position, const Vector2f &newWinDims); void resizeWindow(Vector2f &newDims); From 84dfc16be17d5ed9f4899034d20c5b37e967924f Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Wed, 16 Jun 2021 20:41:56 +0200 Subject: [PATCH 60/78] mouse event scale to new window size --- .../System/MenuControllable/MenuControllableSystem.cpp | 10 +++++----- .../System/MenuControllable/MenuControllableSystem.hpp | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sources/System/MenuControllable/MenuControllableSystem.cpp b/sources/System/MenuControllable/MenuControllableSystem.cpp index d3158774..29eee5b6 100644 --- a/sources/System/MenuControllable/MenuControllableSystem.cpp +++ b/sources/System/MenuControllable/MenuControllableSystem.cpp @@ -51,14 +51,12 @@ namespace BBM this->_currentButton->getComponent().onEvent(*this->_currentButton, this->_wal); } - bool MenuControllableSystem::_mouseOnButton(WAL::ViewEntity &entity) const + bool MenuControllableSystem::_mouseOnButton(const Vector2f &mousePos, WAL::ViewEntity &entity) const { auto &positionComponent = entity.get(); - RAY::Vector2 rayMousePos = RAYControl::Mouse::getCursorPosition(); RAY::Texture *texture = dynamic_cast(entity.get().drawable.get()); RAY2D::Text *text = dynamic_cast(entity.get().drawable.get()); Vector2f buttonPos(positionComponent.getX(), positionComponent.getY()); - Vector2f mousePos(rayMousePos.x, rayMousePos.y); Vector2f dimensions; WAL::Entity *newButton = nullptr; @@ -77,7 +75,9 @@ namespace BBM void MenuControllableSystem::onSelfUpdate() { - + RAY::Vector2 rayMousePos = RAYControl::Mouse::getCursorPosition(); + RAY::Vector2 winSize = RAY::Window::getInstance().getDimensions(); + Vector2f relativeMousePos(rayMousePos.x * 1920 / winSize.x, rayMousePos.y * 1080 / winSize.y); auto &controllableView = this->_wal.getScene()->view(); auto &buttons = _wal.getScene()->view(); @@ -99,7 +99,7 @@ namespace BBM return; } for (auto &entity: buttons) { - if (_mouseOnButton(entity)) { + if (_mouseOnButton(relativeMousePos, entity)) { if (this->_currentButton) this->_currentButton->getComponent().onEvent(*this->_currentButton, this->_wal); this->_currentButton = &(*entity); diff --git a/sources/System/MenuControllable/MenuControllableSystem.hpp b/sources/System/MenuControllable/MenuControllableSystem.hpp index 67254369..45e7c8fb 100644 --- a/sources/System/MenuControllable/MenuControllableSystem.hpp +++ b/sources/System/MenuControllable/MenuControllableSystem.hpp @@ -25,7 +25,7 @@ namespace BBM void _updateCurrentButton(bool selected, Vector2f move); //! @return true if mouse on entity - bool _mouseOnButton(WAL::ViewEntity &entity) const; + bool _mouseOnButton(const Vector2f &mousePos, WAL::ViewEntity &entity) const; public: //! @brief time (in millisecond) since last check std::chrono::time_point now; From cf842903bec1cdcf7180a9b45a39f0296d72ddae Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Wed, 16 Jun 2021 20:59:16 +0200 Subject: [PATCH 61/78] add fullscreen button to settings --- screenshot000.png | Bin 82420 -> 0 bytes sources/Runner/SettingsMenuScene.cpp | 42 +++++++++++++++++++++------ 2 files changed, 33 insertions(+), 9 deletions(-) delete mode 100644 screenshot000.png diff --git a/screenshot000.png b/screenshot000.png deleted file mode 100644 index e4060bf1c23c5d11d6397ecd306201439e42a350..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 82420 zcmeI&KWkrA0LS5L37QlOj#5w%1aZqy(7~mDY#Y!b;w%9jy16)XaHtLiL2;<7lg_>Y z7ex?pkjX4;(zi@#&DE_Y%TGe&6%S<$n6som-bKUcR_(+ohA+H{Ra1 zr|xgt!K;T)p8e0CkAJwnJ#qEBlN(pxx%cjS@1LIj^Xu`&o7YdT9Gv^hgO3i6KmY0X zyN91W`2O5q{yO~l(a~>@zI^TSg|A;YKHrxgUp%<^(*0Wx|33Fmb@%Y;htE9w)%N_G zznuH0I{OB1Ts!^n!o4dmfAK$n9Utvr-vIlMzkk3Mf9rq&>+0FC#p4MWu!M-L2+6!6 zfdT8E1xkPMFC}2WIt|6JL0RyJ=d%7&Htd(6KO}QCV8B|h!gXGU>#beuk<@D-rn){PNGAHg`|5r z-U4jYm|N{vfdNzcJ&uKI$3wUZ*M3rjt8mR3Dl0y)O_glkCV zYQTUg{hlt1Ype8ub!e5o((kl*d&k>5i4GkWlJ4nv3$RgRZna+p22APqI2NuQ58*0Y z`$-Y5!Zl~8tO!Z>bi4)Fs4=$^u8UT{fHm^>que8ErQfwx`buBvFD?TxV4c#Ghtdzp zTn!ko)~j$`Tw7qkIt|6JL0RyJ=d%7&HtI&@e_x~JnUz($R^)qWKiFs0w)Sh#jPgsX7vCq=jl*PNlUA|&0@@fKjC#@tG{ zE?NNt*2v$Fa*wE$e%Ds%D}ANExD3F6bxKnnN9V-CN*`E|M^zl=xr;Q#;t diff --git a/sources/Runner/SettingsMenuScene.cpp b/sources/Runner/SettingsMenuScene.cpp index 8883bbeb..49a27031 100644 --- a/sources/Runner/SettingsMenuScene.cpp +++ b/sources/Runner/SettingsMenuScene.cpp @@ -35,7 +35,7 @@ namespace BBM .addComponent(1920 / 3, 180, 0) .addComponent("assets/logo_small.png"); auto &music = scene->addEntity("music text") - .addComponent(1920 / 2.5, 1080 - 540, 0) + .addComponent(1920 / 2.5, 1080 - 100 - 540, 0) .addComponent("Music Volume", 70, RAY::Vector2(), BLACK) .addComponent() .addComponent([](WAL::Entity &entity, WAL::Wal &) @@ -48,7 +48,7 @@ namespace BBM }); auto &musicUp = scene->addEntity("music up button") - .addComponent(1920 / 1.5, 1080 - 540, 0) + .addComponent(1920 / 1.5, 1080 - 100 - 540, 0) .addComponent("assets/buttons/button_plus.png") .addComponent("assets/musics/music_title.ogg") .addComponent([](WAL::Entity &entity, WAL::Wal &) @@ -71,7 +71,7 @@ namespace BBM }); auto &musicDown = scene->addEntity("music down button") - .addComponent(1920 / 3, 1080 - 540, 0) + .addComponent(1920 / 3, 1080 - 100 - 540, 0) .addComponent("assets/buttons/button_minus.png") .addComponent("assets/musics/music_title.ogg") .addComponent([](WAL::Entity &entity, WAL::Wal &) @@ -94,7 +94,7 @@ namespace BBM }); auto &sound = scene->addEntity("sound text") - .addComponent(1920 / 2.5, 1080 - 360, 0) + .addComponent(1920 / 2.5, 1080 - 100 - 360, 0) .addComponent("Sound Volume", 70, RAY::Vector2(), BLACK) .addComponent() .addComponent([](WAL::Entity &entity, WAL::Wal &) @@ -107,7 +107,7 @@ namespace BBM }); auto &soundUp = scene->addEntity("sound up button") - .addComponent(1920 / 1.5, 1080 - 360, 0) + .addComponent(1920 / 1.5, 1080 - 100 - 360, 0) .addComponent("assets/buttons/button_plus.png") .addComponent(sounds) .addComponent([](WAL::Entity &entity, WAL::Wal &) @@ -130,7 +130,7 @@ namespace BBM }); auto &soundDown = scene->addEntity("sound down button") - .addComponent(1920 / 3, 1080 - 360, 0) + .addComponent(1920 / 3, 1080 - 100 - 360, 0) .addComponent("assets/buttons/button_minus.png") .addComponent(sounds) .addComponent([](WAL::Entity &entity, WAL::Wal &) @@ -153,7 +153,7 @@ namespace BBM }); auto &debug = scene->addEntity("debug text") - .addComponent(1920 / 2.5, 1080 - 180, 0) + .addComponent(1920 / 2.5, 1080 - 100 - 180, 0) .addComponent("Debug Mode: Off", 70, RAY::Vector2(), BLACK) .addComponent([](WAL::Entity &entity, WAL::Wal &wal) { @@ -175,6 +175,29 @@ namespace BBM { entity.getComponent().drawable->setColor(ORANGE); }); + auto &fullscreen = scene->addEntity("fullscreen text") + .addComponent(1920 / 2.5, 1080 - 100 - 50, 0) + .addComponent("Fullscreen: On", 70, RAY::Vector2(), BLACK) + .addComponent([](WAL::Entity &entity, WAL::Wal &wal) + { + RAY2D::Text *text = dynamic_cast(entity.getComponent().drawable.get()); + + if (text->getString().find("Off") != std::string::npos) { + text->setText("Fullscreen: On"); + //do + } else { + text->setText("Fullscreen: Off"); + //do + } + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + entity.getComponent().drawable->setColor(BLACK); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + entity.getComponent().drawable->setColor(ORANGE); + }); auto &back = scene->addEntity("back to menu") .addComponent(10, 1080 - 85, 0) .addComponent("assets/buttons/button_back.png") @@ -204,8 +227,9 @@ namespace BBM sound.getComponent().setButtonLinks(&music, &debug, &soundDown, &soundUp); soundDown.getComponent().setButtonLinks(&music, &debug, nullptr, &sound); soundUp.getComponent().setButtonLinks(&music, &debug, &sound); - debug.getComponent().setButtonLinks(&sound, &back, &back); - back.getComponent().setButtonLinks(&debug, nullptr, nullptr, &debug); + debug.getComponent().setButtonLinks(&sound, &fullscreen); + fullscreen.getComponent().setButtonLinks(&debug, &back, &back); + back.getComponent().setButtonLinks(&fullscreen, nullptr, nullptr, &fullscreen); return scene; } } \ No newline at end of file From 7fcdd05de6b44e673d1e44ab4b46a113c8c61dba Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Wed, 16 Jun 2021 21:18:45 +0200 Subject: [PATCH 62/78] add fullscreen toggle --- lib/Ray/sources/Window.cpp | 19 +++++++++++++++++++ lib/Ray/sources/Window.hpp | 8 ++++++++ sources/Runner/SettingsMenuScene.cpp | 11 ++++++++--- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/lib/Ray/sources/Window.cpp b/lib/Ray/sources/Window.cpp index 71f531d6..151cd615 100644 --- a/lib/Ray/sources/Window.cpp +++ b/lib/Ray/sources/Window.cpp @@ -193,4 +193,23 @@ bool RAY::Window::isReady() const void RAY::Window::setExitKey(RAY::Controller::Keyboard::Key key) { SetExitKey(key); +} + +unsigned RAY::Window::getConfigFlags(void) const +{ + return this->_flags; +} + +RAY::Window &RAY::Window::setConfigFlags(unsigned flags) +{ + if (this->_isOpen) + SetWindowState(flags); + this->_flags = flags; + return *this; +} + +RAY::Window &RAY::Window::toggleFullscreen() +{ + ToggleFullscreen(); + return *this; } \ No newline at end of file diff --git a/lib/Ray/sources/Window.hpp b/lib/Ray/sources/Window.hpp index 036e01ef..81d4b1e4 100644 --- a/lib/Ray/sources/Window.hpp +++ b/lib/Ray/sources/Window.hpp @@ -139,6 +139,14 @@ namespace RAY { //! @info Calling this function override the previous closing key void setExitKey(Controller::Keyboard::Key key); + //! @return the configuration flgs for the window + unsigned getConfigFlags(void) const; + + //! @param flag the configuration flgs for the window + RAY::Window &setConfigFlags(unsigned flags); + + //! @brief set window to fullscreen + RAY::Window &toggleFullscreen(); private: //! @brief Creates window, and opens it if openNow is set to true diff --git a/sources/Runner/SettingsMenuScene.cpp b/sources/Runner/SettingsMenuScene.cpp index 49a27031..9a7e60d9 100644 --- a/sources/Runner/SettingsMenuScene.cpp +++ b/sources/Runner/SettingsMenuScene.cpp @@ -177,17 +177,22 @@ namespace BBM }); auto &fullscreen = scene->addEntity("fullscreen text") .addComponent(1920 / 2.5, 1080 - 100 - 50, 0) - .addComponent("Fullscreen: On", 70, RAY::Vector2(), BLACK) + .addComponent("Fullscreen: Off", 70, RAY::Vector2(), BLACK) .addComponent([](WAL::Entity &entity, WAL::Wal &wal) { RAY2D::Text *text = dynamic_cast(entity.getComponent().drawable.get()); + RAY::Window &window = RAY::Window::getInstance(); + unsigned oldFlags = window.getConfigFlags(); + + if (oldFlags == FLAG_WINDOW_RESIZABLE) + window.toggleFullscreen(); + else + window.setConfigFlags(FLAG_WINDOW_RESIZABLE); if (text->getString().find("Off") != std::string::npos) { text->setText("Fullscreen: On"); - //do } else { text->setText("Fullscreen: Off"); - //do } }) .addComponent([](WAL::Entity &entity, WAL::Wal &) From cb3c29369a1892863fdb970148c65ba7fd55252c Mon Sep 17 00:00:00 2001 From: Bluub Date: Thu, 17 Jun 2021 02:45:19 +0200 Subject: [PATCH 63/78] john is running but need to fix ai not perfect precision --- a | 390 ------------------------------------- assets/ai_scripts/john.lua | 38 ++-- sources/Map/Map.cpp | 6 +- 3 files changed, 21 insertions(+), 413 deletions(-) delete mode 100644 a diff --git a/a b/a deleted file mode 100644 index eecd15b0..00000000 --- a/a +++ /dev/null @@ -1,390 +0,0 @@ ---------- -PRINT MAP ---------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- ---------- -PRINT MAP ---------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- ---------- -PRINT MAP ---------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- ---------- -PRINT MAP ---------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- ---------- -PRINT MAP ---------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- ---------- -PRINT MAP ---------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- ---------- -PRINT MAP ---------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- ---------- -PRINT MAP ---------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- ---------- -PRINT MAP ---------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- ---------- -PRINT MAP ---------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- -| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | --------------------------------------------------------------------------- diff --git a/assets/ai_scripts/john.lua b/assets/ai_scripts/john.lua index 09070f01..e06a3332 100644 --- a/assets/ai_scripts/john.lua +++ b/assets/ai_scripts/john.lua @@ -64,17 +64,19 @@ function CreateDangerMap(dangers) end end for i, zone in ipairs(dangers) do + if danger[math.floor(zone.x)] == nil then + danger[math.floor(zone.x)] = {} + end danger[math.floor(zone.x)][math.floor(zone.y)] = math.floor(zone.level) + print("c") end - --PrintMap(danger, MaxX, MaxY) + PrintMap(danger, MaxX, MaxY) return danger end -function isInExplosionRange(mapinfo, x, y) - for i, danger in ipairs(mapinfo.danger) do - if Danger[x][y] > 0 then +function isInExplosionRange(x, y) + if Danger[x][y] > 0 then return true - end end return false end @@ -107,10 +109,9 @@ end function getNeighbors(node) local neighbors = {} - for dir in Dirs do + for _, dir in ipairs(Dirs) do local neighborX = node.x + dir.x local neighborY = node.y + dir.y - if neighborY <= MaxY and neighborX <= MaxX then if neighborY >= 0 and neighborX >= 0 then if Map[neighborX][neighborY] == 0 then @@ -119,6 +120,7 @@ function getNeighbors(node) end end end + return neighbors end function getLowestFromSet(set, f_score) @@ -164,7 +166,6 @@ function pathfind(root, target) end setRemove(open, curr) -- remove curr from open setAdd(closed, curr)-- add node to closed - local neighbors = getNeighbors(curr) -- get neighbors of current for _, neighbor in ipairs(neighbors) do if not_in(closed, neighbor) then -- neighbor not in closed set @@ -209,12 +210,14 @@ function getPathToSafeSpace(player) end end local path = pathfind(player, res) + print("player") + print(player.x) + print(player.y) for _, n in ipairs(path) do - print("x") print(n.x) - print("y") print(n.y) end + return path end @@ -232,18 +235,13 @@ function Update(mapinfo) end Map = CreateMyMap(mapinfo.raw, MaxX, MaxY) Danger = CreateDangerMap(mapinfo.danger) - --PrintMap(Danger, MaxX, MaxY) + PrintMap(Danger, MaxX, MaxY) local roundedPlayerPos = {x = math.floor(mapinfo.player.x+0.5), y = math.floor(mapinfo.player.y+0.5)} - if (isInExplosionRange(mapinfo, roundedPlayerPos.x, roundedPlayerPos.y)) then + if (isInExplosionRange(roundedPlayerPos.x, roundedPlayerPos.y)) then local pathToSafeSpace = getPathToSafeSpace(roundedPlayerPos) - if (Map[roundedPlayerPos.x + 1][roundedPlayerPos.y] ~= 0) then - return -1, 0, false, false - else - return 1, 0, false, false - end - --play defensive RUN + local f = pathToSafeSpace[1] + return f.x - roundedPlayerPos.x, f.y - roundedPlayerPos.y, false, false else - return 1, 0, true, true; - --play offensive + return 0, 0, false, false; end end \ No newline at end of file diff --git a/sources/Map/Map.cpp b/sources/Map/Map.cpp index ad5049ca..199f13af 100644 --- a/sources/Map/Map.cpp +++ b/sources/Map/Map.cpp @@ -243,9 +243,9 @@ namespace BBM .addComponent>() .addComponent>() .addComponent(1, &MapGenerator::wallDestroyed) - .addComponent( - WAL::Callback(), - &MapGenerator::wallCollided, 0.25, .75) + //.addComponent( + // WAL::Callback(), + // &MapGenerator::wallCollided, 0.25, .75) .addComponent(breakableObj, false, std::make_pair(MAP_DIFFUSE, breakablePng)); } From a8f5cb85a5495c45e2b84c91a6e33bfb5d0b5689 Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Thu, 17 Jun 2021 09:47:36 +0200 Subject: [PATCH 64/78] fix sound on click --- sources/Runner/CreditScene.cpp | 2 +- sources/Runner/HowToPlayScene.cpp | 2 +- sources/Runner/LobbyScene.cpp | 2 +- sources/Runner/MainMenuScene.cpp | 2 +- sources/Runner/PauseMenuScene.cpp | 2 +- sources/Runner/Runner.cpp | 5 ++++- sources/Runner/Runner.hpp | 4 +++- sources/Runner/ScoreScene.cpp | 2 +- sources/Runner/SettingsMenuScene.cpp | 4 +++- sources/Runner/TitleScreenScene.cpp | 2 +- 10 files changed, 17 insertions(+), 10 deletions(-) diff --git a/sources/Runner/CreditScene.cpp b/sources/Runner/CreditScene.cpp index fa77c9ff..a0dfb539 100644 --- a/sources/Runner/CreditScene.cpp +++ b/sources/Runner/CreditScene.cpp @@ -23,7 +23,7 @@ namespace BBM {SoundComponent::JUMP, "assets/sounds/click.ogg"} }; - addMenuControl(*scene); + addMenuControl(*scene, sounds); scene->addEntity("background") .addComponent() .addComponent("assets/plain_menu_background.png"); diff --git a/sources/Runner/HowToPlayScene.cpp b/sources/Runner/HowToPlayScene.cpp index cfb2cb7e..782a70c0 100644 --- a/sources/Runner/HowToPlayScene.cpp +++ b/sources/Runner/HowToPlayScene.cpp @@ -22,7 +22,7 @@ namespace BBM {SoundComponent::JUMP, "assets/sounds/click.ogg"} }; - addMenuControl(*scene); + addMenuControl(*scene, sounds); scene->addEntity("Control entity") .addComponent("assets/musics/music_player_select.ogg") .addComponent(sounds); diff --git a/sources/Runner/LobbyScene.cpp b/sources/Runner/LobbyScene.cpp index 7254006e..41628f37 100644 --- a/sources/Runner/LobbyScene.cpp +++ b/sources/Runner/LobbyScene.cpp @@ -33,7 +33,7 @@ namespace BBM }; auto scene = std::make_shared(); - addMenuControl(*scene); + addMenuControl(*scene, sounds); scene->addEntity("Control entity") .addComponent("assets/musics/music_player_select.ogg") .addComponent(sounds); diff --git a/sources/Runner/MainMenuScene.cpp b/sources/Runner/MainMenuScene.cpp index 42067222..33377954 100644 --- a/sources/Runner/MainMenuScene.cpp +++ b/sources/Runner/MainMenuScene.cpp @@ -23,7 +23,7 @@ namespace BBM }; auto scene = std::make_shared(); - addMenuControl(*scene); + addMenuControl(*scene, sounds); scene->addEntity("Control entity") .addComponent("assets/musics/music_title.ogg") .addComponent(sounds); diff --git a/sources/Runner/PauseMenuScene.cpp b/sources/Runner/PauseMenuScene.cpp index cf7d66c6..3154e360 100644 --- a/sources/Runner/PauseMenuScene.cpp +++ b/sources/Runner/PauseMenuScene.cpp @@ -23,7 +23,7 @@ namespace BBM }; auto scene = std::make_shared(); - addMenuControl(*scene); + addMenuControl(*scene, sounds); scene->addEntity("Control entity") .addComponent("assets/musics/music_player_select.ogg") .addComponent(sounds); diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 2bcc5fc4..bbb3ae73 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -110,17 +110,20 @@ namespace BBM .addSystem(window); } - void Runner::addMenuControl(WAL::Scene &scene) + void Runner::addMenuControl(WAL::Scene &scene, const std::map &sounds) { scene.addEntity("Keyboard default control") .addComponent() + .addComponent(sounds) .addComponent(); scene.addEntity("Keyboard second control") .addComponent() + .addComponent(sounds) .addComponent(ControllableComponent::Layout::KEYBOARD_1); for (int i = 0; i < 4; i++) { scene.addEntity("Gamepad controller") .addComponent() + .addComponent(sounds) .addComponent(i); } } diff --git a/sources/Runner/Runner.hpp b/sources/Runner/Runner.hpp index 4fa9f6a1..3c1d9d04 100644 --- a/sources/Runner/Runner.hpp +++ b/sources/Runner/Runner.hpp @@ -5,6 +5,8 @@ #pragma once #include "Models/GameState.hpp" #include "Wal.hpp" +#include +#include "Component/Sound/SoundComponent.hpp" namespace BBM { @@ -30,7 +32,7 @@ namespace BBM //! @brief init all raylib-related data & context static void enableRaylib(WAL::Wal &wal); - static void addMenuControl(WAL::Scene &scene); + static void addMenuControl(WAL::Scene &scene, const std::map &sounds = {}); //! @brief load all data related to title screen static std::shared_ptr loadTitleScreenScene(); diff --git a/sources/Runner/ScoreScene.cpp b/sources/Runner/ScoreScene.cpp index 76a3008f..4f80babb 100644 --- a/sources/Runner/ScoreScene.cpp +++ b/sources/Runner/ScoreScene.cpp @@ -45,7 +45,7 @@ namespace BBM playersIconPath.push_back(path.replace(path.find("textures"), std::string("textures").size(), "icons")); } - addMenuControl(*scene); + addMenuControl(*scene, sounds); scene->addEntity("Audio ressources") .addComponent("assets/musics/music_result.ogg") .addComponent(sounds); diff --git a/sources/Runner/SettingsMenuScene.cpp b/sources/Runner/SettingsMenuScene.cpp index 8883bbeb..aeb087b8 100644 --- a/sources/Runner/SettingsMenuScene.cpp +++ b/sources/Runner/SettingsMenuScene.cpp @@ -24,7 +24,7 @@ namespace BBM {SoundComponent::JUMP, "assets/sounds/click.ogg"} }; - addMenuControl(*scene); + addMenuControl(*scene, sounds); scene->addEntity("Control entity") .addComponent("assets/musics/music_title.ogg") .addComponent(sounds); @@ -110,6 +110,7 @@ namespace BBM .addComponent(1920 / 1.5, 1080 - 360, 0) .addComponent("assets/buttons/button_plus.png") .addComponent(sounds) + .addComponent() .addComponent([](WAL::Entity &entity, WAL::Wal &) { auto &component = entity.getComponent(); @@ -133,6 +134,7 @@ namespace BBM .addComponent(1920 / 3, 1080 - 360, 0) .addComponent("assets/buttons/button_minus.png") .addComponent(sounds) + .addComponent() .addComponent([](WAL::Entity &entity, WAL::Wal &) { RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); diff --git a/sources/Runner/TitleScreenScene.cpp b/sources/Runner/TitleScreenScene.cpp index 729434f3..defa265e 100644 --- a/sources/Runner/TitleScreenScene.cpp +++ b/sources/Runner/TitleScreenScene.cpp @@ -22,7 +22,7 @@ namespace BBM {SoundComponent::JUMP, "assets/sounds/click.ogg"} }; auto scene = std::make_shared(); - addMenuControl(*scene); + addMenuControl(*scene, sounds); scene->addEntity("control") .addComponent(sounds) .addComponent("assets/musics/music_title.ogg"); From bbce773c98b232607deaffa22b12263dc1f75a68 Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Thu, 17 Jun 2021 10:00:43 +0200 Subject: [PATCH 65/78] add readme in main page --- Doxyfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doxyfile b/Doxyfile index 12d9ca89..a8900e66 100644 --- a/Doxyfile +++ b/Doxyfile @@ -889,7 +889,6 @@ FILE_PATTERNS = *.c \ *.dox \ *.doc \ *.txt \ - *.py \ *.pyw \ *.f90 \ *.f95 \ @@ -919,6 +918,8 @@ RECURSIVE = YES EXCLUDE = */tests/* \ cmake-build-debug/* + build*/* + emsdk/* # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded @@ -1027,7 +1028,7 @@ FILTER_SOURCE_PATTERNS = # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. -USE_MDFILE_AS_MAINPAGE = +USE_MDFILE_AS_MAINPAGE = README.md #--------------------------------------------------------------------------- # Configuration options related to source browsing From 9bf73f37a0bf670a326e1596b38440d58a04e2b7 Mon Sep 17 00:00:00 2001 From: Bluub Date: Thu, 17 Jun 2021 10:53:02 +0200 Subject: [PATCH 66/78] john is running --- assets/ai_scripts/john.lua | 78 ++++++++++++++----- .../IAControllable/IAControllableSystem.cpp | 2 + 2 files changed, 60 insertions(+), 20 deletions(-) diff --git a/assets/ai_scripts/john.lua b/assets/ai_scripts/john.lua index e06a3332..571d0caf 100644 --- a/assets/ai_scripts/john.lua +++ b/assets/ai_scripts/john.lua @@ -12,7 +12,7 @@ mapinfo.dist { } local debug = true if not debug then - log = function() end + log = function() end else log = function(a) print(a) @@ -32,22 +32,22 @@ function PrintMap(map, MaxX, maxZ) log("---------") for i=0,MaxX + 1 do local s = "| " - for j=0,maxZ + 1 do + for j=0,maxZ + 1 do s = s .. tostring(map[i][j]) .. " | "; end log(s) log(string.rep("-", (maxZ - 1) * 5 - 1)) - end + end end function CreateMyMap(infos, MaxX, MaxY) local map = {} - for i=0,MaxX + 1 do - map[i] = {} - for j=0,MaxY + 1 do - map[i][j] = 0 - end - end + for i=0,MaxX + 1 do + map[i] = {} + for j=0,MaxY + 1 do + map[i][j] = 0 + end + end for i, info in ipairs(infos) do map[info.x][info.y] = info.type end @@ -57,18 +57,17 @@ end function CreateDangerMap(dangers) local danger = {} - for i=0,MaxX + 1 do - danger[i] = {} - for j=0,MaxY + 1 do - danger[i][j] = 0 - end - end + for i=0,MaxX + 1 do + danger[i] = {} + for j=0,MaxY + 1 do + danger[i][j] = 0 + end + end for i, zone in ipairs(dangers) do if danger[math.floor(zone.x)] == nil then danger[math.floor(zone.x)] = {} end danger[math.floor(zone.x)][math.floor(zone.y)] = math.floor(zone.level) - print("c") end PrintMap(danger, MaxX, MaxY) return danger @@ -114,7 +113,7 @@ function getNeighbors(node) local neighborY = node.y + dir.y if neighborY <= MaxY and neighborX <= MaxX then if neighborY >= 0 and neighborX >= 0 then - if Map[neighborX][neighborY] == 0 then + if Map[neighborX][neighborY] == 0 and Danger[neighborX][neighborY] ~= 1 then table.insert(neighbors, {x = neighborX, y = neighborY}) end end @@ -159,18 +158,25 @@ function pathfind(root, target) while #open > 0 do local curr = getLowestFromSet(open, f_score) --get lowest node of openset + log("f") if curr.x == target.x and curr.y == target.y then local path = fill_path({}, came_from, target) -- fill the path with came from table.insert(path, target) + log("wow") return path end setRemove(open, curr) -- remove curr from open setAdd(closed, curr)-- add node to closed + log("g") local neighbors = getNeighbors(curr) -- get neighbors of current + log("h") for _, neighbor in ipairs(neighbors) do + log("i") if not_in(closed, neighbor) then -- neighbor not in closed set + log("j") local try_g_score = g_score[curr] + 1 if not_in(open, neighbor) or try_g_score < g_score[neighbor] then + log("e") came_from[neighbor] = curr g_score[neighbor] = try_g_score f_score[neighbor] = g_score[neighbor] + dist(neighbor, target) @@ -194,6 +200,7 @@ function getPathToSafeSpace(player) local MaxYesc = (player.y + 3 > MaxY) and MaxY or (player.y + 3); local maybeSafeSpace = {} + log("a") for i=minXesc,MaxXesc do for j=minYesc, MaxYesc do if Map[i][j] == 0 and Danger[i][j] == 0 then @@ -203,20 +210,20 @@ function getPathToSafeSpace(player) end local minDist = 100000 local res = {} + log("b") for _, safe in ipairs(maybeSafeSpace) do local currDist = dist(player, safe) if currDist < minDist then minDist, res = currDist, safe end end + log("c") local path = pathfind(player, res) - print("player") - print(player.x) - print(player.y) for _, n in ipairs(path) do print(n.x) print(n.y) end + log("d") return path end @@ -225,6 +232,7 @@ end function Update(mapinfo) MaxX = 0 MaxY = 0 + log("NEW FRAME") for i, info in ipairs(mapinfo.raw) do if info.x > MaxX then MaxX = info.x @@ -236,12 +244,42 @@ function Update(mapinfo) Map = CreateMyMap(mapinfo.raw, MaxX, MaxY) Danger = CreateDangerMap(mapinfo.danger) PrintMap(Danger, MaxX, MaxY) + log("Current player pos") + log(mapinfo.player.x) + log(mapinfo.player.y) + log("Rounded player pos") local roundedPlayerPos = {x = math.floor(mapinfo.player.x+0.5), y = math.floor(mapinfo.player.y+0.5)} + log(roundedPlayerPos.x) + log(roundedPlayerPos.y) + log("Last target") + if LastTarget ~= nil then + log(LastTarget.x) + log(LastTarget.y) + if math.abs(LastTarget.x - mapinfo.player.x) <= 0.1 and math.abs(LastTarget.x - mapinfo.player.x) <= 0.1 then + LastTarget = nil + else + return (LastTarget.x - mapinfo.player.x), (LastTarget.y - mapinfo.player.y), false, false + end + else + log("No last target") + end if (isInExplosionRange(roundedPlayerPos.x, roundedPlayerPos.y)) then + log("IN DANGER") local pathToSafeSpace = getPathToSafeSpace(roundedPlayerPos) + log("PATH") + for i,p in ipairs(pathToSafeSpace) do + log(i) + log(p.x) + log(p.y) + end local f = pathToSafeSpace[1] + log("first way of the path") + log(f.x) + log(f.y) + LastTarget = {x = f.x, y = f.y} return f.x - roundedPlayerPos.x, f.y - roundedPlayerPos.y, false, false else + log("SAFE") return 0, 0, false, false; end end \ No newline at end of file diff --git a/sources/System/IAControllable/IAControllableSystem.cpp b/sources/System/IAControllable/IAControllableSystem.cpp index 01a1c90d..65a45c3a 100644 --- a/sources/System/IAControllable/IAControllableSystem.cpp +++ b/sources/System/IAControllable/IAControllableSystem.cpp @@ -111,6 +111,8 @@ namespace BBM int dangerLevel = std::chrono::duration_cast(timeleft).count(); if (dangerLevel == 0) dangerLevel = 1; + std::cout << "bombpos: " << bombPos.x << ", " << bombPos.z << std::endl; + pushInfoDangerPos(state, index, bombPos.x, bombPos.z, dangerLevel); pushInfoDangerPos(state, index, bombPos.x, bombPos.z, dangerLevel); for (int i = 1; i < bombRadius; i++) { Vector3f pos = bombPos - Vector3f(i, 0, 0); From 1f1379a5a5c095c1b0648d918c834b8aeb27d63a Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Thu, 17 Jun 2021 11:17:18 +0200 Subject: [PATCH 67/78] when a resource is not found, an exceptions is thrown --- lib/Ray/sources/Drawables/Image.cpp | 8 +++++++- lib/Ray/sources/Drawables/Texture.cpp | 10 ++++++++-- lib/Ray/sources/Exceptions/RayError.cpp | 5 +++++ lib/Ray/sources/Exceptions/RayError.hpp | 17 +++++++++++++++++ lib/Ray/sources/Font.cpp | 8 +++++++- lib/Ray/sources/Model/Model.cpp | 8 +++++++- lib/Ray/sources/Model/ModelAnimations.cpp | 8 +++++++- screenshot000.png | Bin 82420 -> 0 bytes sources/Runner/LobbyScene.cpp | 2 +- sources/Runner/Runner.cpp | 10 ++-------- sources/main.cpp | 7 ++++++- 11 files changed, 67 insertions(+), 16 deletions(-) delete mode 100644 screenshot000.png diff --git a/lib/Ray/sources/Drawables/Image.cpp b/lib/Ray/sources/Drawables/Image.cpp index a95246be..6b971898 100644 --- a/lib/Ray/sources/Drawables/Image.cpp +++ b/lib/Ray/sources/Drawables/Image.cpp @@ -11,7 +11,13 @@ #include "Exceptions/RayError.hpp" namespace RAY { - Cache<::Image> Image::_imagesCache(LoadImage, UnloadImage); + Cache<::Image> Image::_imagesCache([] (const char *str) { + ::Image image = LoadImage(str); + + if (image.data == nullptr) + throw Exception::ResourceNotFound(std::string(str)); + return image; + }, UnloadImage); Image::Image(const std::string &filename, bool lonely): Rectangle(Vector2(0, 0), Vector2(0, 0), WHITE), diff --git a/lib/Ray/sources/Drawables/Texture.cpp b/lib/Ray/sources/Drawables/Texture.cpp index ee017382..8114f98d 100644 --- a/lib/Ray/sources/Drawables/Texture.cpp +++ b/lib/Ray/sources/Drawables/Texture.cpp @@ -11,10 +11,16 @@ namespace RAY { - Cache<::Texture> Texture::_texturesCache(LoadTexture, UnloadTexture); + Cache<::Texture> Texture::_texturesCache([] (const char *str) { + ::Texture texture = LoadTexture(str); + + if (texture.id <= 0) + throw Exception::ResourceNotFound(std::string(str)); + return texture; + }, UnloadTexture); Texture::Texture() - : Rectangle(Vector2(0, 0), Vector2(0, 0), WHITE, 0, 0) + : Rectangle(Vector2(0, 0), Vector2(0, 0), WHITE, 1, 0), _resourcePath("") {} Texture::Texture(const std::string &filename, bool lonely, float scale, float rotation): diff --git a/lib/Ray/sources/Exceptions/RayError.cpp b/lib/Ray/sources/Exceptions/RayError.cpp index a4de1200..24fb4be8 100644 --- a/lib/Ray/sources/Exceptions/RayError.cpp +++ b/lib/Ray/sources/Exceptions/RayError.cpp @@ -26,3 +26,8 @@ RAY::Exception::WrongInputError::WrongInputError(const std::string &what): RayError(what) { } + +RAY::Exception::ResourceNotFound::ResourceNotFound(const std::string &path): + RayError("\033[36m" + path + "\033[31m couldn't be loaded\033[0m") +{ +} diff --git a/lib/Ray/sources/Exceptions/RayError.hpp b/lib/Ray/sources/Exceptions/RayError.hpp index 158640d6..43c5590f 100644 --- a/lib/Ray/sources/Exceptions/RayError.hpp +++ b/lib/Ray/sources/Exceptions/RayError.hpp @@ -76,6 +76,23 @@ namespace RAY::Exception { //! @brief A default assignment operator WrongInputError &operator=(const WrongInputError &) = default; }; + + //! @brief exception used when a resource is not found + class ResourceNotFound: public RayError { + public: + //! @brief Create a new exception instance + //! @param path path of the un-loadable path + explicit ResourceNotFound(const std::string &path); + + //! @brief A default destructor + ~ResourceNotFound() override = default; + + //! @brief An exception is copy constructable + ResourceNotFound(const ResourceNotFound &) = default; + + //! @brief A default assignment operator + ResourceNotFound &operator=(const ResourceNotFound &) = default; + }; } #endif /* !RAYERROR_HPP_ */ diff --git a/lib/Ray/sources/Font.cpp b/lib/Ray/sources/Font.cpp index 89bf9517..50bb26a8 100644 --- a/lib/Ray/sources/Font.cpp +++ b/lib/Ray/sources/Font.cpp @@ -7,7 +7,13 @@ #include "Font.hpp" -RAY::Cache<::Font> RAY::Font::_fontsCache(LoadFont, UnloadFont); +RAY::Cache<::Font> RAY::Font::_fontsCache([] (const char *str) { + ::Font font = LoadFont(str); + + if (font.texture.id <= 0) + throw Exception::ResourceNotFound(std::string(str)); + return font; + }, UnloadFont); RAY::Font::Font(const std::string &filename, bool lonely): _font(_fontsCache.fetch(filename, lonely)) diff --git a/lib/Ray/sources/Model/Model.cpp b/lib/Ray/sources/Model/Model.cpp index b694fb4d..59a508c6 100644 --- a/lib/Ray/sources/Model/Model.cpp +++ b/lib/Ray/sources/Model/Model.cpp @@ -13,7 +13,13 @@ namespace RAY::Drawables::Drawables3D { - RAY::Cache<::Model> Model::_modelsCache(LoadModel, UnloadModel); + RAY::Cache<::Model> Model::_modelsCache([] (const char *str) { + ::Model model = LoadModel(str); + + if (model.meshCount == 0) + throw Exception::ResourceNotFound(std::string(str)); + return model; + }, UnloadModel); Model::Model(const std::string &filename, bool lonely, diff --git a/lib/Ray/sources/Model/ModelAnimations.cpp b/lib/Ray/sources/Model/ModelAnimations.cpp index 6d41832d..b1eedebc 100644 --- a/lib/Ray/sources/Model/ModelAnimations.cpp +++ b/lib/Ray/sources/Model/ModelAnimations.cpp @@ -7,7 +7,13 @@ #include "Model/ModelAnimations.hpp" -RAY::Cache<::ModelAnimation> RAY::ModelAnimations::_animationsCache(LoadModelAnimations, UnloadModelAnimations); +RAY::Cache<::ModelAnimation> RAY::ModelAnimations::_animationsCache([] (const char *str, int *counter) { + ::ModelAnimation *modelanimations = LoadModelAnimations(str, counter); + + if (modelanimations == nullptr) + throw Exception::ResourceNotFound(std::string(str)); + return modelanimations; + }, UnloadModelAnimations); RAY::ModelAnimations::ModelAnimations(const std::string &filePath): _animationsPtr(_animationsCache.fetch(filePath, &this->_animationCount)), diff --git a/screenshot000.png b/screenshot000.png deleted file mode 100644 index e4060bf1c23c5d11d6397ecd306201439e42a350..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 82420 zcmeI&KWkrA0LS5L37QlOj#5w%1aZqy(7~mDY#Y!b;w%9jy16)XaHtLiL2;<7lg_>Y z7ex?pkjX4;(zi@#&DE_Y%TGe&6%S<$n6som-bKUcR_(+ohA+H{Ra1 zr|xgt!K;T)p8e0CkAJwnJ#qEBlN(pxx%cjS@1LIj^Xu`&o7YdT9Gv^hgO3i6KmY0X zyN91W`2O5q{yO~l(a~>@zI^TSg|A;YKHrxgUp%<^(*0Wx|33Fmb@%Y;htE9w)%N_G zznuH0I{OB1Ts!^n!o4dmfAK$n9Utvr-vIlMzkk3Mf9rq&>+0FC#p4MWu!M-L2+6!6 zfdT8E1xkPMFC}2WIt|6JL0RyJ=d%7&Htd(6KO}QCV8B|h!gXGU>#beuk<@D-rn){PNGAHg`|5r z-U4jYm|N{vfdNzcJ&uKI$3wUZ*M3rjt8mR3Dl0y)O_glkCV zYQTUg{hlt1Ype8ub!e5o((kl*d&k>5i4GkWlJ4nv3$RgRZna+p22APqI2NuQ58*0Y z`$-Y5!Zl~8tO!Z>bi4)Fs4=$^u8UT{fHm^>que8ErQfwx`buBvFD?TxV4c#Ghtdzp zTn!ko)~j$`Tw7qkIt|6JL0RyJ=d%7&HtI&@e_x~JnUz($R^)qWKiFs0w)Sh#jPgsX7vCq=jl*PNlUA|&0@@fKjC#@tG{ zE?NNt*2v$Fa*wE$e%Ds%D}ANExD3F6bxKnnN9V-CN*`E|M^zl=xr;Q#;t diff --git a/sources/Runner/LobbyScene.cpp b/sources/Runner/LobbyScene.cpp index 7254006e..667e84f6 100644 --- a/sources/Runner/LobbyScene.cpp +++ b/sources/Runner/LobbyScene.cpp @@ -196,7 +196,7 @@ namespace BBM auto &ready = scene->addEntity("ready") .addComponent(224 * (i + 1) + 200 * i, 1080 / 3, 0) // todo check why it does this | hacky way to fix ready texture - .addComponent(""); + .addComponent(); player.addComponent(i, ready, playerTile); } scene->addEntity("camera") diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 2bcc5fc4..15fcbb64 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -145,13 +145,7 @@ namespace BBM Runner::enableRaylib(wal); Runner::loadScenes(); wal.changeScene(Runner::gameState._loadedScenes[GameState::SceneID::SplashScreen]); - - try { - wal.run(Runner::updateState, Runner::gameState); - return 0; - } catch (const std::exception &ex) { - std::cerr << ex.what() << std::endl; - return 1; - } + wal.run(Runner::updateState, Runner::gameState); + return 0; } } \ No newline at end of file diff --git a/sources/main.cpp b/sources/main.cpp index c4e69c4a..9cf4bf85 100644 --- a/sources/main.cpp +++ b/sources/main.cpp @@ -23,5 +23,10 @@ int main(int argc, char **argv) usage(argv[0]); return 1; } - return BBM::Runner::run(); + try { + return BBM::Runner::run(); + } catch (const std::exception &ex) { + std::cerr << ex.what() << std::endl; + return 84; + } } From 6f9609a2f2cbe521b3769f86e45f221c5af12855 Mon Sep 17 00:00:00 2001 From: Askou Date: Thu, 17 Jun 2021 11:18:42 +0200 Subject: [PATCH 68/78] fix player heigth --- assets/map/floorAdd.png | Bin 0 -> 1250 bytes sources/Runner/GameScene.cpp | 2 +- sources/System/Lobby/LobbySystem.cpp | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 assets/map/floorAdd.png diff --git a/assets/map/floorAdd.png b/assets/map/floorAdd.png new file mode 100644 index 0000000000000000000000000000000000000000..f9464e14452221eff1b46e41a31c0491ffd4b68e GIT binary patch literal 1250 zcmV<81ReW{P)}P8=p_f?wJmMxH)m&Mo zI!1FGHquBS4hafM*n|!TQK}|o*4h`V`Ib;552MvW8Jrw>6v!JPwM1Q2sv7AkeLBh_ z_y2j?+RU`qJroBzUtRZe0toH{)r#x>p1N-J3<$gc*Ji_Cq@3oyNv|}t@G&s316uUnb{#Vet-FPy_|<(KMi&8_tWt>yv=jF zA0wOh_TxG{eI2`d8vFfWxLi&{He!BJ(D+9Iv{)=20b)EqAG_d8Bo^n0gfxErJk>%} zklxW+J1xeb%y1Y^Eg7%$7I0o6^6+R0Ehxs-(QXLTzolBC5LZ>hL^b~Wy*~?tNK-~x zedqVJp-~Y~B@s+qbvgjN`rU$l%x{SXT}u%UpT>#|iwIOiSG~W#)^$sRI}u7u5N{M_ zCo)4R;s}{QC7W9jTILmU6am_V^X-02qKKpgLCPzU2_#-$=T>#5j}T~~YQ4o+kuOM{ zh#KmoCNcGT$U3f&7iGw9i2IRgYs+b9d`eIXCWt-R&tDE5txT-2lDNiX@~&hu4-lNL zbblw%h?wy_Xknb9N?H;N-9atInA`8_H;doDq4PF1!@sL0|<6E6DF0?1wE@2W4cmV3n>ab}=OzFu*>Y6HC-2Go%IwgKa(6bO24<|GuS+pBh5w~7Z<^}pcgPVzS zeh2*oT9J0lhsk>!I)ja{vGU M07*qoM6N<$g1%8a0{{R3 literal 0 HcmV?d00001 diff --git a/sources/Runner/GameScene.cpp b/sources/Runner/GameScene.cpp index b2e6f279..4dbc2c55 100644 --- a/sources/Runner/GameScene.cpp +++ b/sources/Runner/GameScene.cpp @@ -62,7 +62,7 @@ namespace BBM {SoundComponent::BOMB, "assets/sounds/bomb_drop.ogg"}, //{SoundComponent::DEATH, "assets/sounds/death.ogg"} }; - + return scene.addEntity("player") .addComponent() .addComponent("assets/player/player.iqm", true) diff --git a/sources/System/Lobby/LobbySystem.cpp b/sources/System/Lobby/LobbySystem.cpp index 4d2fd563..c07da926 100644 --- a/sources/System/Lobby/LobbySystem.cpp +++ b/sources/System/Lobby/LobbySystem.cpp @@ -214,7 +214,7 @@ namespace BBM auto &player = Runner::createPlayer(*scene); _addController(player, lobby.layout); player.getComponent().position = Vector3f(mapWidth * (playerCount % 2), - 0, + (Runner::hasHeights ? 1.01 : 0), mapHeight * (!(playerCount % 3))); auto *model = dynamic_cast(player.getComponent().drawable.get()); model->setTextureToMaterial(MAP_DIFFUSE, "assets/player/textures/" + _colors[lobby.color] + ".png"); From b9dbfebdc3c47ef4f5a60c15822f512f4330e934 Mon Sep 17 00:00:00 2001 From: Bluub Date: Thu, 17 Jun 2021 11:21:11 +0200 Subject: [PATCH 69/78] john is running even better --- assets/ai_scripts/john.lua | 28 ++++++++++++++++++- .../IAControllable/IAControllableSystem.cpp | 16 ++++++++++- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/assets/ai_scripts/john.lua b/assets/ai_scripts/john.lua index 571d0caf..ad41de5b 100644 --- a/assets/ai_scripts/john.lua +++ b/assets/ai_scripts/john.lua @@ -98,7 +98,7 @@ end function not_in(set, node) for _,value in pairs(set) do - if value == node then + if value.x == node.x and value.y == node.y then return false end end @@ -119,6 +119,19 @@ function getNeighbors(node) end end end + if #neighbors == 0 then + for _, dir in ipairs(Dirs) do + local neighborX = node.x + dir.x + local neighborY = node.y + dir.y + if neighborY <= MaxY and neighborX <= MaxX then + if neighborY >= 0 and neighborX >= 0 then + if Map[neighborX][neighborY] == 0 then + table.insert(neighbors, {x = neighborX, y = neighborY}) + end + end + end + end + end return neighbors end @@ -157,7 +170,10 @@ function pathfind(root, target) f_score[root] = dist(root, target) while #open > 0 do + log(#open) local curr = getLowestFromSet(open, f_score) --get lowest node of openset + log(curr.x) + log(curr.y) log("f") if curr.x == target.x and curr.y == target.y then local path = fill_path({}, came_from, target) -- fill the path with came from @@ -167,6 +183,12 @@ function pathfind(root, target) end setRemove(open, curr) -- remove curr from open setAdd(closed, curr)-- add node to closed + log("closed set") + for i, c in ipairs(closed) do + log("member") + log(c.x) + log(c.y) + end log("g") local neighbors = getNeighbors(curr) -- get neighbors of current log("h") @@ -187,6 +209,7 @@ function pathfind(root, target) end end end + return {} end function dist(nodeA, nodeB) @@ -272,6 +295,9 @@ function Update(mapinfo) log(p.x) log(p.y) end + if #pathToSafeSpace == 0 then + return 0, 0, false, false + end local f = pathToSafeSpace[1] log("first way of the path") log(f.x) diff --git a/sources/System/IAControllable/IAControllableSystem.cpp b/sources/System/IAControllable/IAControllableSystem.cpp index 65a45c3a..26432c1f 100644 --- a/sources/System/IAControllable/IAControllableSystem.cpp +++ b/sources/System/IAControllable/IAControllableSystem.cpp @@ -80,6 +80,21 @@ namespace BBM state.setTable(); state.setTable(); } + for (auto &bomb : _bombs) { + Vector3f bombPos = std::get<0>(bomb); + state.push(index++); + state.newTable(); + state.push("x"); + state.push(bombPos.x); + state.setTable(); + state.push("y"); + state.push(bombPos.z); + state.setTable(); + state.push("type"); + state.push(10); + state.setTable(); + state.setTable(); + } state.setTable(); } @@ -111,7 +126,6 @@ namespace BBM int dangerLevel = std::chrono::duration_cast(timeleft).count(); if (dangerLevel == 0) dangerLevel = 1; - std::cout << "bombpos: " << bombPos.x << ", " << bombPos.z << std::endl; pushInfoDangerPos(state, index, bombPos.x, bombPos.z, dangerLevel); pushInfoDangerPos(state, index, bombPos.x, bombPos.z, dangerLevel); for (int i = 1; i < bombRadius; i++) { From e16e726881d1ad6ef7f950797b7a5e60bd461267 Mon Sep 17 00:00:00 2001 From: Askou Date: Thu, 17 Jun 2021 11:21:58 +0200 Subject: [PATCH 70/78] remove useless file --- assets/map/floorAdd.png | Bin 1250 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 assets/map/floorAdd.png diff --git a/assets/map/floorAdd.png b/assets/map/floorAdd.png deleted file mode 100644 index f9464e14452221eff1b46e41a31c0491ffd4b68e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1250 zcmV<81ReW{P)}P8=p_f?wJmMxH)m&Mo zI!1FGHquBS4hafM*n|!TQK}|o*4h`V`Ib;552MvW8Jrw>6v!JPwM1Q2sv7AkeLBh_ z_y2j?+RU`qJroBzUtRZe0toH{)r#x>p1N-J3<$gc*Ji_Cq@3oyNv|}t@G&s316uUnb{#Vet-FPy_|<(KMi&8_tWt>yv=jF zA0wOh_TxG{eI2`d8vFfWxLi&{He!BJ(D+9Iv{)=20b)EqAG_d8Bo^n0gfxErJk>%} zklxW+J1xeb%y1Y^Eg7%$7I0o6^6+R0Ehxs-(QXLTzolBC5LZ>hL^b~Wy*~?tNK-~x zedqVJp-~Y~B@s+qbvgjN`rU$l%x{SXT}u%UpT>#|iwIOiSG~W#)^$sRI}u7u5N{M_ zCo)4R;s}{QC7W9jTILmU6am_V^X-02qKKpgLCPzU2_#-$=T>#5j}T~~YQ4o+kuOM{ zh#KmoCNcGT$U3f&7iGw9i2IRgYs+b9d`eIXCWt-R&tDE5txT-2lDNiX@~&hu4-lNL zbblw%h?wy_Xknb9N?H;N-9atInA`8_H;doDq4PF1!@sL0|<6E6DF0?1wE@2W4cmV3n>ab}=OzFu*>Y6HC-2Go%IwgKa(6bO24<|GuS+pBh5w~7Z<^}pcgPVzS zeh2*oT9J0lhsk>!I)ja{vGU M07*qoM6N<$g1%8a0{{R3 From 71a0b9cd34c3efdbb19cefbca617a91c021fe2bb Mon Sep 17 00:00:00 2001 From: Bluub Date: Thu, 17 Jun 2021 11:33:52 +0200 Subject: [PATCH 71/78] less log --- assets/ai_scripts/john.lua | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/assets/ai_scripts/john.lua b/assets/ai_scripts/john.lua index ad41de5b..ceeebcee 100644 --- a/assets/ai_scripts/john.lua +++ b/assets/ai_scripts/john.lua @@ -170,15 +170,15 @@ function pathfind(root, target) f_score[root] = dist(root, target) while #open > 0 do + log("openset size") log(#open) local curr = getLowestFromSet(open, f_score) --get lowest node of openset + log("current node") log(curr.x) log(curr.y) - log("f") if curr.x == target.x and curr.y == target.y then local path = fill_path({}, came_from, target) -- fill the path with came from table.insert(path, target) - log("wow") return path end setRemove(open, curr) -- remove curr from open @@ -189,16 +189,11 @@ function pathfind(root, target) log(c.x) log(c.y) end - log("g") local neighbors = getNeighbors(curr) -- get neighbors of current - log("h") for _, neighbor in ipairs(neighbors) do - log("i") if not_in(closed, neighbor) then -- neighbor not in closed set - log("j") local try_g_score = g_score[curr] + 1 if not_in(open, neighbor) or try_g_score < g_score[neighbor] then - log("e") came_from[neighbor] = curr g_score[neighbor] = try_g_score f_score[neighbor] = g_score[neighbor] + dist(neighbor, target) @@ -223,7 +218,6 @@ function getPathToSafeSpace(player) local MaxYesc = (player.y + 3 > MaxY) and MaxY or (player.y + 3); local maybeSafeSpace = {} - log("a") for i=minXesc,MaxXesc do for j=minYesc, MaxYesc do if Map[i][j] == 0 and Danger[i][j] == 0 then @@ -233,20 +227,13 @@ function getPathToSafeSpace(player) end local minDist = 100000 local res = {} - log("b") for _, safe in ipairs(maybeSafeSpace) do local currDist = dist(player, safe) if currDist < minDist then minDist, res = currDist, safe end end - log("c") local path = pathfind(player, res) - for _, n in ipairs(path) do - print(n.x) - print(n.y) - end - log("d") return path end From e3b6b87b11173b4c08f66c02744b9adf38ce3a0d Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Thu, 17 Jun 2021 11:39:55 +0200 Subject: [PATCH 72/78] menu controllable: when the mouse doesn't move: the keyboard event overlaod mouse's --- .../MenuControllable/MenuControllableSystem.cpp | 12 +++++++++--- .../MenuControllable/MenuControllableSystem.hpp | 3 +++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/sources/System/MenuControllable/MenuControllableSystem.cpp b/sources/System/MenuControllable/MenuControllableSystem.cpp index 29eee5b6..24787a3d 100644 --- a/sources/System/MenuControllable/MenuControllableSystem.cpp +++ b/sources/System/MenuControllable/MenuControllableSystem.cpp @@ -18,8 +18,9 @@ namespace BBM { MenuControllableSystem::MenuControllableSystem(WAL::Wal &wal) : System(wal), - _currentButton() - {} + _currentButton(), _oldMousePosition(-1, -1) + { + } void MenuControllableSystem::_updateCurrentButton(bool selected, Vector2f move) { @@ -66,7 +67,7 @@ namespace BBM dimensions.y = texture->getDimensions().y; } else if (text) { dimensions.y = text->getFontSize(); - dimensions.x = text->getString().size() * (text->getLetterSpacing() + text->getFontSize()); + dimensions.x = text->getString().size() * (text->getFontSize()); } else return false; return ((buttonPos.x <= mousePos.x && mousePos.x <= buttonPos.x + dimensions.x) @@ -82,6 +83,8 @@ namespace BBM auto &buttons = _wal.getScene()->view(); + if (this->_oldMousePosition == Vector2f(-1, -1)) + this->_oldMousePosition = relativeMousePos; if (this->_currentButton && this->_currentButton->_scene.getID() != this->_wal.getScene()->getID()) { this->_currentButton->getComponent().onEvent(*this->_currentButton, this->_wal); this->_currentButton = nullptr; @@ -98,6 +101,9 @@ namespace BBM this->_updateCurrentButton(controllable.select, controllable.move); return; } + if (relativeMousePos == this->_oldMousePosition && !RAYControl::Mouse::isPressed(RAYControl::Mouse::Button::MOUSE_BUTTON_LEFT)) + return; + this->_oldMousePosition = relativeMousePos; for (auto &entity: buttons) { if (_mouseOnButton(relativeMousePos, entity)) { if (this->_currentButton) diff --git a/sources/System/MenuControllable/MenuControllableSystem.hpp b/sources/System/MenuControllable/MenuControllableSystem.hpp index 45e7c8fb..7462a358 100644 --- a/sources/System/MenuControllable/MenuControllableSystem.hpp +++ b/sources/System/MenuControllable/MenuControllableSystem.hpp @@ -20,6 +20,9 @@ namespace BBM //! @brief index of the current button selected WAL::Entity *_currentButton; + //! @brief position of the mouse at the precedent scene (to know which controller event to watch) + Vector2f _oldMousePosition; + //! @brief update current button reference //! @param selected lets know if te new selected button is 'pressed' void _updateCurrentButton(bool selected, Vector2f move); From 3da5ae9961d535cbdc9ee67be796e1e35a3ae7f0 Mon Sep 17 00:00:00 2001 From: Bluub Date: Thu, 17 Jun 2021 11:52:18 +0200 Subject: [PATCH 73/78] remoe lua.hpp --- lib/LuaGate/sources/lua.hpp | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 lib/LuaGate/sources/lua.hpp diff --git a/lib/LuaGate/sources/lua.hpp b/lib/LuaGate/sources/lua.hpp deleted file mode 100644 index 5d6b3a05..00000000 --- a/lib/LuaGate/sources/lua.hpp +++ /dev/null @@ -1,5 +0,0 @@ -extern "C" { -#include "lua.h" -#include "lualib.h" -#include "lauxlib.h" -} \ No newline at end of file From 57f895b563036449d4765f8714dee988a2782dd9 Mon Sep 17 00:00:00 2001 From: "arthur.jamet" Date: Thu, 17 Jun 2021 12:07:07 +0200 Subject: [PATCH 74/78] remve ascii escape --- lib/Ray/sources/Exceptions/RayError.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Ray/sources/Exceptions/RayError.cpp b/lib/Ray/sources/Exceptions/RayError.cpp index 24fb4be8..ee0d4fa7 100644 --- a/lib/Ray/sources/Exceptions/RayError.cpp +++ b/lib/Ray/sources/Exceptions/RayError.cpp @@ -28,6 +28,6 @@ RAY::Exception::WrongInputError::WrongInputError(const std::string &what): } RAY::Exception::ResourceNotFound::ResourceNotFound(const std::string &path): - RayError("\033[36m" + path + "\033[31m couldn't be loaded\033[0m") + RayError(path + " couldn't be loaded") { } From ee951f8ca5b21213112def6102811f285c3ec9eb Mon Sep 17 00:00:00 2001 From: Bluub Date: Thu, 17 Jun 2021 12:33:27 +0200 Subject: [PATCH 75/78] starting aggressive pathing --- assets/ai_scripts/john.lua | 52 ++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/assets/ai_scripts/john.lua b/assets/ai_scripts/john.lua index ceeebcee..3363cb37 100644 --- a/assets/ai_scripts/john.lua +++ b/assets/ai_scripts/john.lua @@ -9,7 +9,7 @@ mapinfo.dist { } ------------ ------ Debug variables -local debug = true +local debug = false if not debug then log = function() end @@ -24,6 +24,7 @@ MaxX = 0 MaxY = 0 Map = {} Danger = {} +LastPos = nil ----- Map functions function PrintMap(map, MaxX, maxZ) @@ -119,7 +120,7 @@ function getNeighbors(node) end end end - if #neighbors == 0 then + if #neighbors == 0 and Danger[node.x][node.y] <= 1 then for _, dir in ipairs(Dirs) do local neighborX = node.x + dir.x local neighborY = node.y + dir.y @@ -217,23 +218,36 @@ function getPathToSafeSpace(player) local minYesc = (player.y - 3 < 0) and 0 or (player.y - 3); local MaxYesc = (player.y + 3 > MaxY) and MaxY or (player.y + 3); - local maybeSafeSpace = {} + local minDist = 100000 + local res = {} for i=minXesc,MaxXesc do for j=minYesc, MaxYesc do if Map[i][j] == 0 and Danger[i][j] == 0 then - table.insert(maybeSafeSpace, {x = i, y = j}) + local safe = {x = i, y = j} + local currDist = dist(player, safe) + if currDist < minDist then + minDist, res = currDist, safe + end end end end + local path = pathfind(player, res) + return path +end + +function getNeighborAttack() +end + +function getPathToEnemy(player, enemies) local minDist = 100000 local res = {} - for _, safe in ipairs(maybeSafeSpace) do - local currDist = dist(player, safe) + for _, enemy in ipairs(enemies) do + local currDist = dist(player, enemy) if currDist < minDist then - minDist, res = currDist, safe + minDist, res = currDist, enemy end end - local path = pathfind(player, res) + local path = pathfind(player, res, getNeighborAttack) return path end @@ -292,7 +306,25 @@ function Update(mapinfo) LastTarget = {x = f.x, y = f.y} return f.x - roundedPlayerPos.x, f.y - roundedPlayerPos.y, false, false else - log("SAFE") - return 0, 0, false, false; + local enemies = mapinfo.enemies + local pathToEnemy = getPathToEnemy(roundedPlayerPos, enemies) + if #pathToEnemy == 0 then + return 0, 0, false, false + end + local f = pathToEnemy[1] + log("first way of the path") + log(f.x) + log(f.y) + LastTarget = {x = f.x, y = f.y} + --pathfind to closest player + if LastPos == nil then + LastPos = {x = mapinfo.player.x, y = mapinfo.player.y} + else + if mapinfo.player.x == LastPos.x and mapinfo.player.y == LastPos.y then + return 0, 0, true, true + end + end + LastTarget = {x = f.x, y = f.y} + return f.x - roundedPlayerPos.x, f.y - roundedPlayerPos.y, false, false; end end \ No newline at end of file From 4f782e9d75d047373f60ee95a899408ba39ced3e Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Thu, 17 Jun 2021 12:37:40 +0200 Subject: [PATCH 76/78] Spawning a bomb inside a player dont block him anymore --- sources/Component/Bomb/BasicBombComponent.cpp | 14 +++++++----- sources/Component/Bomb/BasicBombComponent.hpp | 8 +++---- sources/System/Bomb/BombSystem.cpp | 11 +++++----- .../System/BombHolder/BombHolderSystem.cpp | 22 ++++++++++++------- .../System/BombHolder/BombHolderSystem.hpp | 2 +- 5 files changed, 32 insertions(+), 25 deletions(-) diff --git a/sources/Component/Bomb/BasicBombComponent.cpp b/sources/Component/Bomb/BasicBombComponent.cpp index 97cbb70d..9de464d7 100644 --- a/sources/Component/Bomb/BasicBombComponent.cpp +++ b/sources/Component/Bomb/BasicBombComponent.cpp @@ -4,17 +4,19 @@ #include "BasicBombComponent.hpp" +#include + namespace BBM { - BasicBombComponent::BasicBombComponent(WAL::Entity &entity, int damage, int explosionRadius, unsigned ownerID) - : WAL::Component(entity), - damage(damage), - explosionRadius(explosionRadius), - ownerID(ownerID) + BasicBombComponent::BasicBombComponent(WAL::Entity &entity, int damage, int explosionRadius, std::vector ignored) + : WAL::Component(entity), + damage(damage), + explosionRadius(explosionRadius), + ignoredEntities(std::move(ignored)) {} WAL::Component *BasicBombComponent::clone(WAL::Entity &entity) const { - return new BasicBombComponent(entity, this->damage, this->explosionRadius, this->ownerID); + return new BasicBombComponent(entity, this->damage, this->explosionRadius, this->ignoredEntities); } } \ No newline at end of file diff --git a/sources/Component/Bomb/BasicBombComponent.hpp b/sources/Component/Bomb/BasicBombComponent.hpp index 1b9b46bf..5d3838c8 100644 --- a/sources/Component/Bomb/BasicBombComponent.hpp +++ b/sources/Component/Bomb/BasicBombComponent.hpp @@ -19,16 +19,14 @@ namespace BBM const int explosionRadius = 3; //! @brief The damage made by the explosion on an entity const int damage = 1; - //! @brief The ID of the owner. - unsigned ownerID; - //! @brief Should collisions with the owner be disabled.² - bool ignoreOwner = true; + //! @brief The list of IDs of ignored entities. + std::vector ignoredEntities; //! @inherit WAL::Component *clone(WAL::Entity &entity) const override; //! @brief A component can't be instantiated, it should be derived. - explicit BasicBombComponent(WAL::Entity &entity, int damage, int explosionRadius, unsigned ownerID); + explicit BasicBombComponent(WAL::Entity &entity, int damage, int explosionRadius, std::vector ignored); //! @brief A component can't be instantiated, it should be derived. BasicBombComponent(const BasicBombComponent &) = default; diff --git a/sources/System/Bomb/BombSystem.cpp b/sources/System/Bomb/BombSystem.cpp index 60ff5a30..39b7698b 100644 --- a/sources/System/Bomb/BombSystem.cpp +++ b/sources/System/Bomb/BombSystem.cpp @@ -14,15 +14,16 @@ namespace BBM void BombSystem::onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds dtime) { auto &bomb = entity.get(); - if (!bomb.ignoreOwner) + + if (bomb.ignoredEntities.empty()) return; + auto &pos = entity.get(); for (auto &[owner, ownerPos, _] : this->_wal.getScene()->view()) { - if (owner.getUid() != bomb.ownerID) - continue; if (pos.position.distance(ownerPos.position) >= 1.1) { - bomb.ignoreOwner = false; - return; + bomb.ignoredEntities.erase( + std::remove(bomb.ignoredEntities.begin(), bomb.ignoredEntities.end(), owner.getUid()), + bomb.ignoredEntities.end()); } } } diff --git a/sources/System/BombHolder/BombHolderSystem.cpp b/sources/System/BombHolder/BombHolderSystem.cpp index 0a69c435..8bbf673e 100644 --- a/sources/System/BombHolder/BombHolderSystem.cpp +++ b/sources/System/BombHolder/BombHolderSystem.cpp @@ -2,7 +2,6 @@ // Created by Zoe Roux on 5/31/21. // -#include #include #include "Component/Timer/TimerComponent.hpp" #include "System/Event/EventSystem.hpp" @@ -31,7 +30,8 @@ namespace BBM CollisionComponent::CollidedAxis collidedAxis) { auto &bombInfo = bomb.getComponent(); - if (bombInfo.ignoreOwner && bombInfo.ownerID == entity.getUid()) + auto found = std::find(bombInfo.ignoredEntities.begin(), bombInfo.ignoredEntities.end(), entity.getUid()); + if (found != bombInfo.ignoredEntities.end()) return; return MapGenerator::wallCollided(entity, bomb, collidedAxis); } @@ -115,8 +115,15 @@ namespace BBM _dispatchExplosion(position, wal, explosionRadius); } - void BombHolderSystem::_spawnBomb(Vector3f position, BombHolderComponent &holder, unsigned id) + void BombHolderSystem::_spawnBomb(Vector3f position, BombHolderComponent &holder) { + std::vector overlapping; + + for (auto &[entity, pos, _] : this->_wal.getScene()->view()) { + if (position.distance(pos.position) <= 1.1) + overlapping.emplace_back(entity.getUid()); + } + this->_wal.getScene()->scheduleNewEntity("Bomb") .addComponent(position.round()) .addComponent(1, [](WAL::Entity &entity, WAL::Wal &wal) { @@ -154,7 +161,7 @@ namespace BBM }) .addComponent() .addComponent>() - .addComponent(holder.damage, holder.explosionRadius, id) + .addComponent(holder.damage, holder.explosionRadius, overlapping) .addComponent(BombHolderSystem::explosionTimer, &BombHolderSystem::_bombExplosion) .addComponent( WAL::Callback(), @@ -166,9 +173,8 @@ namespace BBM )); } - void - BombHolderSystem::onUpdate(WAL::ViewEntity &entity, - std::chrono::nanoseconds dtime) + void BombHolderSystem::onUpdate(WAL::ViewEntity &entity, + std::chrono::nanoseconds dtime) { auto &holder = entity.get(); auto &position = entity.get(); @@ -176,7 +182,7 @@ namespace BBM if (controllable.bomb && holder.bombCount > 0) { holder.bombCount--; - this->_spawnBomb(position.position, holder, entity->getUid()); + this->_spawnBomb(position.position, holder); } if (holder.bombCount < holder.maxBombCount) { holder.nextBombRefill -= dtime; diff --git a/sources/System/BombHolder/BombHolderSystem.hpp b/sources/System/BombHolder/BombHolderSystem.hpp index c5631190..9ba67f2b 100644 --- a/sources/System/BombHolder/BombHolderSystem.hpp +++ b/sources/System/BombHolder/BombHolderSystem.hpp @@ -35,7 +35,7 @@ namespace BBM { private: //! @brief Spawn a bomb at the specified position. - void _spawnBomb(Vector3f position, BombHolderComponent &holder, unsigned id); + void _spawnBomb(Vector3f position, BombHolderComponent &holder); //! @brief Spawn a bomb at the specified position. static void _dispatchExplosion(const Vector3f &position, From ff172e9b472890bbf0c32b8d3ef7dc910c771962 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Bihan?= Date: Thu, 17 Jun 2021 13:55:20 +0200 Subject: [PATCH 77/78] fixing ci ? --- .github/workflows/build.yml | 7 +++++++ .github/workflows/build_linux.yml | 21 --------------------- 2 files changed, 7 insertions(+), 21 deletions(-) delete mode 100644 .github/workflows/build_linux.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a1ff5a94..25ab6fac 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -43,7 +43,14 @@ jobs: if: matrix.name == 'Linux' run: test -f build/bomberman - name: Archive production artifact for Windows binary + if: matrix.name == 'Windows' uses: actions/upload-artifact@v1 with: name: BombermanWindows.exe path: build/Debug/bomberman.exe + - name: Archive production artifact for Linux binary + if: matrix.name == 'Linux' + uses: actions/upload-artifact@v1 + with: + name: BombermanLinux + path: build/bomberman diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml deleted file mode 100644 index 9f352ac4..00000000 --- a/.github/workflows/build_linux.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Linux Build (Epitech Container) -on: [push, pull_request] - -jobs: - testbox: - if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository - runs-on: ubuntu-latest - container: - image: epitechcontent/epitest-docker:latest - steps: - - uses: actions/checkout@v2 - with: - submodules: true - - name: Build - run: | - mkdir build && cd build - cmake .. - cmake --build . - - name: CheckBinaryName - shell: bash - run: test -f build/bomberman \ No newline at end of file From fcb1c910449dfdcc9d3585e0743934316fba1bbc Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Thu, 17 Jun 2021 14:00:30 +0200 Subject: [PATCH 78/78] Fixing multiple bombs at the same pos --- sources/System/BombHolder/BombHolderSystem.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/sources/System/BombHolder/BombHolderSystem.cpp b/sources/System/BombHolder/BombHolderSystem.cpp index 8bbf673e..02ed40aa 100644 --- a/sources/System/BombHolder/BombHolderSystem.cpp +++ b/sources/System/BombHolder/BombHolderSystem.cpp @@ -125,7 +125,7 @@ namespace BBM } this->_wal.getScene()->scheduleNewEntity("Bomb") - .addComponent(position.round()) + .addComponent(position) .addComponent(1, [](WAL::Entity &entity, WAL::Wal &wal) { // the bomb explode when hit entity.scheduleDeletion(); @@ -180,10 +180,6 @@ namespace BBM auto &position = entity.get(); auto &controllable = entity.get(); - if (controllable.bomb && holder.bombCount > 0) { - holder.bombCount--; - this->_spawnBomb(position.position, holder); - } if (holder.bombCount < holder.maxBombCount) { holder.nextBombRefill -= dtime; if (holder.nextBombRefill <= 0ns) { @@ -191,5 +187,14 @@ namespace BBM holder.bombCount++; } } + if (controllable.bomb && holder.bombCount > 0) { + auto spawnPos = position.position.round(); + for (auto &[entity, pos, _] : this->_wal.getScene()->view()) { + if (pos.position == spawnPos) + return; + } + holder.bombCount--; + this->_spawnBomb(spawnPos, holder); + } } } \ No newline at end of file