Skip to content

Commit

Permalink
Emscripten build (#187)
Browse files Browse the repository at this point in the history
* building with emscripten and interfacing like python

* more wrapper code

* more wrapper code

* more progress on observers

* converting into react project so its easier to use with components etc

* the pain of trying to make this a react module

* all working asynchronously with react

* fixing some refactor bits

* adding phaser for rendering

* more work on renderer, using phaser

* renderers working for sprite and block2D

* correct tiling for sprite2D tilsets

* more work on level-builder

* more progress on editor tool, can now edit and save in window and hot-swap gdy

* actions now automatically mapped

* calculating action mappings to keyboard mapping

* more mechanics and fixings for making crafter work

* fixing some issues with behaviours/probabilities overriding others

* working on tests for improved behaviours

* fixing python tests for updatd behaviours

* very close to having working crafter envs

* much more updates for GriddlyJS and fixes for grafter envs

* some more fixes to allow arrows to be launched in the right directions with the right images, also bug fix for collision detections
  • Loading branch information
Bam4d authored Apr 24, 2022
1 parent 5f0c427 commit d1a692e
Show file tree
Hide file tree
Showing 79 changed files with 32,166 additions and 469 deletions.
111 changes: 81 additions & 30 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ set(BINARY ${CMAKE_PROJECT_NAME})

set(BIN_OUTPUT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_BUILD_TYPE}/bin)

message(STATUS ${CMAKE_SYSTEM_NAME})
if(${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten")
set(WASM ON)
message(STATUS "Compiling for webassembly using emscripten")
add_definitions(-DWASM)
add_compile_options("-fexceptions")
else()
set(WASM OFF)
endif()

if(MSVC)
message("Compiling with MSVC")

Expand Down Expand Up @@ -44,7 +54,9 @@ set(CMAKE_CONFIG_FOLDER ${CMAKE_SOURCE_DIR}/cmake)
add_subdirectory("libs/glm")

# PyBind
add_subdirectory("libs/pybind11")
if(NOT WASM)
add_subdirectory("libs/pybind11")
endif()

# Yaml-Cpp
set(YAML_CPP_BUILD_TESTS OFF CACHE BOOL "disable yaml tests")
Expand All @@ -61,10 +73,6 @@ add_library(project_warnings INTERFACE)
include(${CMAKE_CONFIG_FOLDER}/settings/CompilerWarnings.cmake)
set_project_warnings(project_warnings)


find_package(Vulkan REQUIRED FATAL_ERROR)
set(VULKAN_SHADER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/Griddly/Core/Observers/Vulkan/resources/shaders)

file(GLOB_RECURSE GRIDDLY_SOURCES "src/*.cpp")

set (GRIDDLY_INCLUDE_DIRS "")
Expand All @@ -74,18 +82,41 @@ foreach (_headerFile ${GRIDDLY_HEADERS})
endforeach()
list(REMOVE_DUPLICATES GRIDDLY_INCLUDE_DIRS)

message(STATUS "Compiling shaders...")
if(WASM)
list(
REMOVE_ITEM
GRIDDLY_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/Griddly/Core/Observers/SpriteObserver.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Griddly/Core/Observers/BlockObserver.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Griddly/Core/Observers/IsometricSpriteObserver.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Griddly/Core/Observers/VulkanGridObserver.cpp
)

list(
FILTER
GRIDDLY_SOURCES
EXCLUDE
REGEX
"src/Griddly/Core/Observers/Vulkan/.*"
)
endif()

# Compile shaders and copy them into resources directory in build output

if(MSVC)
execute_process ( COMMAND ${VULKAN_SHADER_DIR}/compile_shaders.bat
WORKING_DIRECTORY ${VULKAN_SHADER_DIR}
RESULT_VARIABLE rv)
else()
execute_process ( COMMAND bash ${VULKAN_SHADER_DIR}/compile_shaders.sh
WORKING_DIRECTORY ${VULKAN_SHADER_DIR}
RESULT_VARIABLE rv)
# Compile shaders and copy them into resources directory in build output
if(NOT WASM)
message(STATUS "Compiling shaders...")
find_package(Vulkan REQUIRED FATAL_ERROR)
set(VULKAN_SHADER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/Griddly/Core/Observers/Vulkan/resources/shaders)

if(MSVC)
execute_process ( COMMAND ${VULKAN_SHADER_DIR}/compile_shaders.bat
WORKING_DIRECTORY ${VULKAN_SHADER_DIR}
RESULT_VARIABLE rv)
else()
execute_process ( COMMAND bash ${VULKAN_SHADER_DIR}/compile_shaders.sh
WORKING_DIRECTORY ${VULKAN_SHADER_DIR}
RESULT_VARIABLE rv)
endif()
endif()

# Add the spdlog libraries to the build
Expand All @@ -96,12 +127,30 @@ include_directories(${SPDLOG_DIR})
set(STB_DIR "libs/stb")
include_directories(${STB_DIR})

add_library(${BINARY} STATIC ${GRIDDLY_SOURCES})
target_link_libraries(${BINARY} PRIVATE project_warnings Vulkan::Vulkan yaml-cpp glm)
if(WASM)
add_library(${BINARY} STATIC ${GRIDDLY_SOURCES})
target_link_libraries(${BINARY} PRIVATE yaml-cpp glm)

file(GLOB_RECURSE JIDDLY_SOURCES "js/bindings/*.cpp")

add_executable(jiddly ${JIDDLY_SOURCES} )
target_link_libraries(jiddly PRIVATE ${BINARY} yaml-cpp glm)

# These properties specify what kind of Emscripten build to perform and are assigned to our 'a-simple-triangle' executable target.
set_target_properties(
jiddly
PROPERTIES
LINK_FLAGS
"-lembind -fexceptions -s ENVIRONMENT=web -s ALLOW_MEMORY_GROWTH=1 -sNO_DISABLE_EXCEPTION_THROWING -sASYNCIFY -sMODULARIZE=1"
)
else()
add_library(${BINARY} STATIC ${GRIDDLY_SOURCES})
target_link_libraries(${BINARY} PRIVATE project_warnings Vulkan::Vulkan yaml-cpp glm)

# Add the pybind11 module
set(PYTHON_MODULE python_griddly)
pybind11_add_module(${PYTHON_MODULE} bindings/python.cpp)
# Add the pybind11 module
set(PYTHON_MODULE python_griddly)
pybind11_add_module(${PYTHON_MODULE} bindings/python.cpp)
endif()

# Want the python lib to be output in the same directory as the other dll/so
if(MSVC)
Expand All @@ -111,17 +160,19 @@ if(MSVC)
endforeach( OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES )
endif()

set_target_properties(${PYTHON_MODULE} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${BIN_OUTPUT_DIR})
target_link_libraries(${PYTHON_MODULE} PRIVATE ${BINARY} project_warnings Vulkan::Vulkan yaml-cpp glm )
if(NOT WASM)
set_target_properties(${PYTHON_MODULE} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${BIN_OUTPUT_DIR})
target_link_libraries(${PYTHON_MODULE} PRIVATE ${BINARY} project_warnings Vulkan::Vulkan yaml-cpp glm )

set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)

# Testing stuff
include(CTest)
enable_testing()
# Testing stuff
include(CTest)
enable_testing()

if(BUILD_TESTING)
add_subdirectory(tests)
if(BUILD_TESTING)
add_subdirectory(tests)
endif()
endif()
2 changes: 1 addition & 1 deletion bindings/wrapper/GameWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ class Py_GameWrapper {
py_objectInfo["Location"] = py::cast(std::vector<int32_t>{
objectInfo.location.x,
objectInfo.location.y});
py_objectInfo["Orientation"] = objectInfo.orientation.getName();
py_objectInfo["Orientation"] = objectInfo.orientationName;
py_objectInfo["PlayerId"] = objectInfo.playerId;
py_objectInfo["Variables"] = py_objectVariables;

Expand Down
22 changes: 11 additions & 11 deletions bindings/wrapper/StepPlayerWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,11 @@ class Py_StepPlayerWrapper {
}

std::shared_ptr<Action> buildAction(std::string actionName, std::vector<int32_t> actionArray) {
auto actionInputsDefinition = gdyFactory_->findActionInputsDefinition(actionName);
const auto& actionInputsDefinition = gdyFactory_->findActionInputsDefinition(actionName);
auto playerAvatar = player_->getAvatar();
auto playerId = player_->getId();

auto inputMappings = actionInputsDefinition.inputMappings;
const auto& inputMappings = actionInputsDefinition.inputMappings;

if (playerAvatar != nullptr) {
auto actionId = actionArray[0];
Expand All @@ -174,11 +174,11 @@ class Py_StepPlayerWrapper {
return nullptr;
}

auto mapping = inputMappings[actionId];
auto vectorToDest = mapping.vectorToDest;
auto orientationVector = mapping.orientationVector;
auto metaData = mapping.metaData;
auto action = std::make_shared<Action>(Action(gameProcess_->getGrid(), actionName, playerId, 0, metaData));
const auto& mapping = inputMappings.at(actionId);
const auto& vectorToDest = mapping.vectorToDest;
const auto& orientationVector = mapping.orientationVector;
const auto& metaData = mapping.metaData;
const auto& action = std::make_shared<Action>(Action(gameProcess_->getGrid(), actionName, playerId, 0, metaData));
action->init(playerAvatar, vectorToDest, orientationVector, actionInputsDefinition.relative);

return action;
Expand All @@ -191,10 +191,10 @@ class Py_StepPlayerWrapper {
return nullptr;
}

auto mapping = inputMappings[actionId];
auto vector = mapping.vectorToDest;
auto orientationVector = mapping.orientationVector;
auto metaData = mapping.metaData;
const auto& mapping = inputMappings.at(actionId);
const auto& vector = mapping.vectorToDest;
const auto& orientationVector = mapping.orientationVector;
const auto& metaData = mapping.metaData;
glm::ivec2 destinationLocation = sourceLocation + vector;

auto action = std::make_shared<Action>(Action(gameProcess_->getGrid(), actionName, playerId, 0, metaData));
Expand Down
28 changes: 28 additions & 0 deletions js/bindings/Jiddly.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include "Jiddly.hpp"

#include <spdlog/spdlog.h>

#include <iostream>

#include "../../src/Griddly/Core/GDY/GDYFactory.hpp"
#include "../../src/Griddly/Core/GDY/Objects/ObjectGenerator.hpp"
#include "../../src/Griddly/Core/GDY/TerminationGenerator.hpp"

Jiddly::Jiddly() {
#ifndef NDEBUG
spdlog::set_level(spdlog::level::debug);
#else
spdlog::set_level(spdlog::level::info);
#endif

spdlog::debug("Jiddly module loaded!");
}

std::shared_ptr<JiddlyGDYWrapper> Jiddly::loadString(std::string levelString) {
auto objectGenerator = std::make_shared<griddly::ObjectGenerator>(griddly::ObjectGenerator());
auto terminationGenerator = std::make_shared<griddly::TerminationGenerator>(griddly::TerminationGenerator());
auto gdyFactory = std::make_shared<griddly::GDYFactory>(griddly::GDYFactory(objectGenerator, terminationGenerator));
std::istringstream s(levelString);
gdyFactory->parseFromStream(s);
return std::make_shared<JiddlyGDYWrapper>(JiddlyGDYWrapper(gdyFactory));
}
89 changes: 89 additions & 0 deletions js/bindings/Jiddly.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#include <emscripten/bind.h>
#include <emscripten/html5.h>

#include "../../src/Griddly/Core/Grid.hpp"
#include "JiddlyGDYWrapper.hpp"

namespace e = emscripten;

class Jiddly {
public:
Jiddly();
std::shared_ptr<JiddlyGDYWrapper> loadString(std::string levelString);
};

template <typename K, typename V>
e::class_<std::unordered_map<K, V>> register_unordered_map(const char* name) {
typedef std::unordered_map<K, V> MapType;

size_t (MapType::*size)() const = &MapType::size;
return e::class_<MapType>(name)
.template constructor<>()
.function("size", size)
.function("get", e::internal::MapAccess<MapType>::get)
.function("set", e::internal::MapAccess<MapType>::set)
.function("keys", e::internal::MapAccess<MapType>::keys);
}

EMSCRIPTEN_BINDINGS(Jiddly) {
// Classes
e::class_<Jiddly>("Jiddly")
.constructor()
.function("loadString", &Jiddly::loadString);

e::class_<JiddlyGDYWrapper>("JiddlyGDYWrapper")
.smart_ptr<std::shared_ptr<JiddlyGDYWrapper>>("JiddlyGDYWrapper")
.function("setMaxSteps", &JiddlyGDYWrapper::setMaxSteps)
.function("getPlayerCount", &JiddlyGDYWrapper::getPlayerCount)
.function("getAvatarObject", &JiddlyGDYWrapper::getAvatarObject)
.function("getExternalActionNames", &JiddlyGDYWrapper::getExternalActionNames)
.function("getLevelCount", &JiddlyGDYWrapper::getLevelCount)
.function("getObserverType", &JiddlyGDYWrapper::getObserverType)
.function("getActionInputMappings", &JiddlyGDYWrapper::getActionInputMappings)
.function("createGame", &JiddlyGDYWrapper::createGame);

e::class_<JiddlyGameWrapper>("JiddlyGameWrapper")
.smart_ptr<std::shared_ptr<JiddlyGameWrapper>>("JiddlyGameWrapper")
.function("getActionTypeId", &JiddlyGameWrapper::getActionTypeId)
.function("init", &JiddlyGameWrapper::init)
.function("release", &JiddlyGameWrapper::release)
.function("registerPlayer", &JiddlyGameWrapper::registerPlayer)
.function("loadLevel", &JiddlyGameWrapper::loadLevel)
.function("loadLevelString", &JiddlyGameWrapper::loadLevelString)
.function("reset", &JiddlyGameWrapper::reset)
.function("getGlobalObservationDescription", &JiddlyGameWrapper::getGlobalObservationDescription)
.function("observe", &JiddlyGameWrapper::observe)
.function("stepParallel", &JiddlyGameWrapper::stepParallel)
.function("getWidth", &JiddlyGameWrapper::getWidth)
.function("getHeight", &JiddlyGameWrapper::getHeight)
.function("getState", &JiddlyGameWrapper::getState)
.function("getGlobalVariableNames", &JiddlyGameWrapper::getGlobalVariableNames)
.function("getObjectVariableMap", &JiddlyGameWrapper::getObjectVariableMap)
.function("getGlobalVariables", &JiddlyGameWrapper::getGlobalVariables)
.function("getObjectNames", &JiddlyGameWrapper::getObjectNames)
.function("getObjectVariableNames", &JiddlyGameWrapper::getObjectVariableNames)
.function("seedRandomGenerator", &JiddlyGameWrapper::seedRandomGenerator);

e::class_<JiddlyPlayerWrapper>("JiddlyPlayerWrapper")
.smart_ptr<std::shared_ptr<JiddlyPlayerWrapper>>("JiddlyPlayerWrapper");

// Types
e::value_object<glm::ivec2>("glm::ivec2")
.field("x", &glm::ivec2::x)
.field("y", &glm::ivec2::y);

e::value_object<glm::vec2>("glm::vec2")
.field("x", &glm::vec2::x)
.field("y", &glm::vec2::y);

e::register_vector<int32_t>("IntVector");
e::register_vector<uint32_t>("UInt32Vector");
e::register_vector<uint8_t>("UInt8Vector");
e::register_vector<std::string>("StringVector");

e::enum_<griddly::ObserverType>("ObserverType")
.value("VECTOR", griddly::ObserverType::VECTOR)
.value("ASCII", griddly::ObserverType::ASCII)
.value("ENTITY", griddly::ObserverType::ENTITY)
.value("NONE", griddly::ObserverType::NONE);
}
Loading

0 comments on commit d1a692e

Please sign in to comment.