diff --git a/cmake/FetchDependencies.cmake b/cmake/FetchDependencies.cmake index 5d4b1bf..24903fc 100644 --- a/cmake/FetchDependencies.cmake +++ b/cmake/FetchDependencies.cmake @@ -48,5 +48,8 @@ check_and_download("https://download.savannah.gnu.org/releases/freetype/freetype # 8) SDL_ttf check_and_download("https://github.com/libsdl-org/SDL_ttf/archive/refs/tags/release-2.24.0.zip" "release-2.24.0.zip" "SDL_ttf-release-2.24.0" "CMakeLists.txt") -# 9) pybind11 -check_and_download("https://github.com/pybind/pybind11/archive/refs/tags/v3.0.3.zip" "pybind11-v3.0.3.zip" "pybind11-3.0.3" "CMakeLists.txt") +# 9) Lua +check_and_download("https://github.com/lua/lua/archive/refs/tags/v5.4.8.zip" "lua-v5.4.8.zip" "lua-5.4.8" "lapi.c") + +# 10) sol2 (header-only C++ bindings for Lua) +check_and_download("https://github.com/ThePhD/sol2/archive/refs/tags/v3.3.0.zip" "sol2-v3.3.0.zip" "sol2-3.3.0" "include/sol/sol.hpp") diff --git a/cmake/ThirdParty.cmake b/cmake/ThirdParty.cmake index f208b87..8e940c3 100644 --- a/cmake/ThirdParty.cmake +++ b/cmake/ThirdParty.cmake @@ -8,6 +8,11 @@ endmacro() set(BUILD_CONFIGS Debug Release) +# Map MinSizeRel and RelWithDebInfo to Release libs for all imported targets. +# Without this CMake warns that IMPORTED_LOCATION is missing for those configs. +set(CMAKE_MAP_IMPORTED_CONFIG_MINSIZEREL Release) +set(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBINFO Release) + # =========================================== # 1) ZLIB (zlib131.zip → zlib-1.3.2) - без изменений @@ -549,12 +554,57 @@ if(NOT TARGET boost_external_lib) endif() # =========================================== -# 9) pybind11 (3.0.3) - Python embedding +# 9) Lua (5.5.0) - embedded scripting language # =========================================== -set(PYBIND11_SRC_DIR "${THIRDPARTY_DIR}/pybind11-3.0.3") +set(LUA_SRC_DIR "${THIRDPARTY_DIR}/lua-5.4.8") -if(NOT TARGET pybind11::headers) - # pybind11 is header-only; add_subdirectory gives us pybind11::embed which - # also locates and links the Python interpreter and development libraries. - add_subdirectory("${PYBIND11_SRC_DIR}" "${CMAKE_BINARY_DIR}/pybind11_build" EXCLUDE_FROM_ALL) +if(NOT TARGET lua_static) + file(GLOB LUA_SOURCES "${LUA_SRC_DIR}/*.c") + # Exclude the standalone interpreter, compiler, and unity-build wrapper. + # onelua.c #includes all other .c files — compiling it alongside them + # causes every symbol to be defined twice. + list(REMOVE_ITEM LUA_SOURCES + "${LUA_SRC_DIR}/lua.c" + "${LUA_SRC_DIR}/luac.c" + "${LUA_SRC_DIR}/onelua.c" + ) + + add_library(lua_static STATIC ${LUA_SOURCES}) + target_include_directories(lua_static PUBLIC "${LUA_SRC_DIR}") + target_compile_definitions(lua_static PRIVATE _CRT_SECURE_NO_WARNINGS) +endif() + +# =========================================== +# 10) sol2 (3.3.0) - header-only C++ bindings for Lua +# =========================================== +set(SOL2_SRC_DIR "${THIRDPARTY_DIR}/sol2-3.3.0") + +# Apply patch for Clang/Emscripten compatibility in optional::emplace(). +# The sentinel file prevents re-applying on subsequent cmake runs. +set(_sol2_sentinel "${SOL2_SRC_DIR}/.patched") +if(NOT EXISTS "${_sol2_sentinel}") + find_package(Git QUIET) + if(GIT_FOUND) + execute_process( + COMMAND ${GIT_EXECUTABLE} apply --ignore-whitespace + "${CMAKE_CURRENT_LIST_DIR}/patches/sol2-3.3.0-clang-optional.patch" + WORKING_DIRECTORY "${SOL2_SRC_DIR}" + RESULT_VARIABLE _sol2_patch_res + ) + if(_sol2_patch_res EQUAL 0) + file(WRITE "${_sol2_sentinel}" "patched\n") + message(STATUS "Applied sol2 Clang optional patch") + else() + message(WARNING "sol2 patch failed (exit ${_sol2_patch_res}) — Clang/Emscripten builds may not compile") + endif() + else() + message(WARNING "Git not found — cannot apply sol2 patch automatically. " + "Apply cmake/patches/sol2-3.3.0-clang-optional.patch manually.") + endif() +endif() + +if(NOT TARGET sol2_external_lib) + add_library(sol2_external_lib INTERFACE) + target_include_directories(sol2_external_lib INTERFACE "${SOL2_SRC_DIR}/include") + target_link_libraries(sol2_external_lib INTERFACE lua_static) endif() \ No newline at end of file diff --git a/cmake/patches/sol2-3.3.0-clang-optional.patch b/cmake/patches/sol2-3.3.0-clang-optional.patch new file mode 100644 index 0000000..65eb907 --- /dev/null +++ b/cmake/patches/sol2-3.3.0-clang-optional.patch @@ -0,0 +1,14 @@ +--- a/include/sol/optional_implementation.hpp ++++ b/include/sol/optional_implementation.hpp +@@ -2189,7 +2189,10 @@ + template + T& emplace(Args&&... args) noexcept { + static_assert(std::is_constructible::value, "T must be constructible with Args"); + + *this = nullopt; +- this->construct(std::forward(args)...); ++ // Reference specialization stores a pointer; set it directly. ++ // construct() only exists in the non-reference specialization. ++ m_value = std::addressof(std::forward(args)...); ++ return *m_value; + } diff --git a/proj-web/CMakeLists.txt b/proj-web/CMakeLists.txt index d7f6fc6..2d7f707 100644 --- a/proj-web/CMakeLists.txt +++ b/proj-web/CMakeLists.txt @@ -8,7 +8,7 @@ if(NOT CMAKE_MAKE_PROGRAM AND WIN32) endif() endif() -project(space-game001 CXX) +project(space-game001 LANGUAGES C CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -17,11 +17,52 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) include("${CMAKE_CURRENT_SOURCE_DIR}/../cmake/FetchDependencies.cmake") # Теперь гарантированно есть папка ../thirdparty со всеми исходниками -# Список исходных файлов (без изменений) +# =========================================== +# Lua (5.5.0) - embedded scripting, pure C, compiles with Emscripten +# =========================================== +set(LUA_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty/lua-5.4.8") +file(GLOB LUA_SOURCES "${LUA_SRC_DIR}/*.c") +list(REMOVE_ITEM LUA_SOURCES + "${LUA_SRC_DIR}/lua.c" + "${LUA_SRC_DIR}/luac.c" + "${LUA_SRC_DIR}/onelua.c" +) +add_library(lua_static STATIC ${LUA_SOURCES}) +target_include_directories(lua_static PUBLIC "${LUA_SRC_DIR}") + +# sol2 (header-only) +set(SOL2_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty/sol2-3.3.0") + +# Apply patch for Clang/Emscripten compatibility in optional::emplace(). +set(_sol2_sentinel "${SOL2_SRC_DIR}/.patched") +if(NOT EXISTS "${_sol2_sentinel}") + find_package(Git QUIET) + if(GIT_FOUND) + execute_process( + COMMAND ${GIT_EXECUTABLE} apply --ignore-whitespace + "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/patches/sol2-3.3.0-clang-optional.patch" + WORKING_DIRECTORY "${SOL2_SRC_DIR}" + RESULT_VARIABLE _sol2_patch_res + ) + if(_sol2_patch_res EQUAL 0) + file(WRITE "${_sol2_sentinel}" "patched\n") + message(STATUS "Applied sol2 Clang optional patch") + else() + message(WARNING "sol2 patch failed (exit ${_sol2_patch_res}) — Clang/Emscripten builds may not compile") + endif() + else() + message(WARNING "Git not found — cannot apply sol2 patch automatically. " + "Apply cmake/patches/sol2-3.3.0-clang-optional.patch manually.") + endif() +endif() + +# Список исходных файлов (синхронизирован с proj-windows/CMakeLists.txt) set(SOURCES ../src/main.cpp ../src/Game.cpp ../src/Game.h + ../src/Character.cpp + ../src/Character.h ../src/Environment.cpp ../src/Environment.h ../src/render/Renderer.cpp @@ -42,39 +83,41 @@ set(SOURCES ../src/utils/Utils.h ../src/SparkEmitter.cpp ../src/SparkEmitter.h - ../src/planet/PlanetObject.cpp - ../src/planet/PlanetObject.h - ../src/planet/PlanetData.cpp - ../src/planet/PlanetData.h - ../src/utils/Perlin.cpp - ../src/utils/Perlin.h - ../src/utils/TaskManager.cpp - ../src/utils/TaskManager.h - ../src/planet/StoneObject.cpp - ../src/planet/StoneObject.h - ../src/render/FrameBuffer.cpp - ../src/render/FrameBuffer.h +# ../src/planet/PlanetObject.cpp +# ../src/planet/PlanetObject.h +# ../src/planet/PlanetData.cpp +# ../src/planet/PlanetData.h + ../src/utils/Perlin.cpp + ../src/utils/Perlin.h + ../src/utils/TaskManager.cpp + ../src/utils/TaskManager.h +# ../src/planet/StoneObject.cpp +# ../src/planet/StoneObject.h + ../src/render/FrameBuffer.cpp + ../src/render/FrameBuffer.h ../src/UiManager.cpp ../src/UiManager.h ../src/Projectile.h ../src/Projectile.cpp - ../src/network/NetworkInterface.h - ../src/network/LocalClient.h - ../src/network/LocalClient.cpp - ../src/network/ClientState.h - ../src/network/ClientState.cpp - ../src/network/WebSocketClientBase.h - ../src/network/WebSocketClientBase.cpp - ../src/network/WebSocketClientEmscripten.h - ../src/network/WebSocketClientEmscripten.cpp - ../src/render/TextRenderer.h - ../src/render/TextRenderer.cpp - ../src/MenuManager.h - ../src/MenuManager.cpp - ../src/Space.h - ../src/Space.cpp - ../src/GameConstants.h - ../src/GameConstants.cpp +# ../src/network/NetworkInterface.h +# ../src/network/LocalClient.h +# ../src/network/LocalClient.cpp +# ../src/network/ClientState.h +# ../src/network/ClientState.cpp +# ../src/network/WebSocketClientBase.h +# ../src/network/WebSocketClientBase.cpp +# ../src/network/WebSocketClientEmscripten.h +# ../src/network/WebSocketClientEmscripten.cpp + ../src/render/TextRenderer.h + ../src/render/TextRenderer.cpp + ../src/MenuManager.h + ../src/MenuManager.cpp +# ../src/Space.h +# ../src/Space.cpp + ../src/GameConstants.h + ../src/GameConstants.cpp + ../src/ScriptEngine.h + ../src/ScriptEngine.cpp ) add_executable(space-game001 ${SOURCES}) @@ -84,10 +127,10 @@ target_include_directories(space-game001 PRIVATE ../src ../thirdparty/eigen-5.0.0 ../thirdparty/boost_1_90_0 + "${SOL2_SRC_DIR}/include" ) # Сборка libzip через add_subdirectory (Emscripten соберет её из исходников) -# Опции для либзипа, чтобы он не искал лишнего в системе set(ENABLE_GNUTLS OFF CACHE BOOL "" FORCE) set(ENABLE_OPENSSL OFF CACHE BOOL "" FORCE) set(ENABLE_WINDOWS_CRYPTO OFF CACHE BOOL "" FORCE) @@ -95,7 +138,7 @@ set(ENABLE_COMMONCRYPTO OFF CACHE BOOL "" FORCE) add_subdirectory("../thirdparty/libzip-1.11.4" libzip-build) -target_link_libraries(space-game001 PRIVATE zip z websocket.js) +target_link_libraries(space-game001 PRIVATE zip z lua_static websocket.js) # Эмскриптен-флаги set(EMSCRIPTEN_FLAGS @@ -107,7 +150,7 @@ set(EMSCRIPTEN_FLAGS #"-pthread" #"-sUSE_PTHREADS=1" "-fexceptions" - "-DNETWORK" + "-DNETWORK" ) target_compile_options(space-game001 PRIVATE ${EMSCRIPTEN_FLAGS} "-O2") @@ -119,9 +162,10 @@ set(EMSCRIPTEN_LINK_FLAGS "-O2" #"-sPTHREAD_POOL_SIZE=4" "-sALLOW_MEMORY_GROWTH=1" - "-sFULL_ES3=1" + "-sFULL_ES3=1" "--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/loading.png@resources/loading.png" "--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/shaders@resources/shaders" + "--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start.lua@resources/start.lua" ) # Применяем настройки линковки @@ -129,7 +173,7 @@ target_link_options(space-game001 PRIVATE ${EMSCRIPTEN_LINK_FLAGS}) # Для совместимости со старыми версиями CMake, если target_link_options недостаточно string(REPLACE ";" " " EMSCRIPTEN_LINK_FLAGS_STR "${EMSCRIPTEN_LINK_FLAGS}") -set_target_properties(space-game001 PROPERTIES +set_target_properties(space-game001 PROPERTIES LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS_STR}" SUFFIX ".html" ) @@ -159,15 +203,14 @@ install(TARGETS space-game001 ) # 2. Устанавливаем сопутствующие файлы (JS, WASM и сгенерированный архив данных) -# Emscripten создает их в той же папке, что и таргет -install(FILES +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/space-game001.js" "${CMAKE_CURRENT_BINARY_DIR}/space-game001.wasm" "${CMAKE_CURRENT_BINARY_DIR}/space-game001.data" DESTINATION . ) -install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/space-game001plain.html" +install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/space-game001plain.html" DESTINATION . ) diff --git a/proj-windows/CMakeLists.txt b/proj-windows/CMakeLists.txt index b76bfaf..4d361bd 100644 --- a/proj-windows/CMakeLists.txt +++ b/proj-windows/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.16) -project(space-game001 LANGUAGES CXX) +project(space-game001 LANGUAGES C CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -111,7 +111,7 @@ target_link_libraries(space-game001 PRIVATE SDL2_ttf_external_lib eigen_external_lib boost_external_lib - pybind11::embed + sol2_external_lib ) # Линкуем OpenGL (Windows) diff --git a/resources/start.lua b/resources/start.lua new file mode 100644 index 0000000..ccffe4d --- /dev/null +++ b/resources/start.lua @@ -0,0 +1,16 @@ +-- Chain of waypoints for NPC 0. +-- Each on_arrived callback issues the next walk command. + +local function step3() + game_api.npc_walk_to(0, 0.0, 0.0, -30.0, step1) +end + +local function step2() + game_api.npc_walk_to(0, -2.0, 0.0, -2.0, step3) +end + +function step1() + game_api.npc_walk_to(0, 2.0, 0.0, -2.0, step2) +end + +step1() diff --git a/resources/start.py b/resources/start.py deleted file mode 100644 index 7a62639..0000000 --- a/resources/start.py +++ /dev/null @@ -1,15 +0,0 @@ -import game_api - -# Chain of waypoints for NPC 0. -# Each on_arrived callback issues the next walk command. - -def step3(): - game_api.npc_walk_to(0, 0.0, 0.0, -30.0, on_arrived=step1) - -def step2(): - game_api.npc_walk_to(0, -2.0, 0.0, -2.0, on_arrived=step3) - -def step1(): - game_api.npc_walk_to(0, 2.0, 0.0, -2.0, on_arrived=step2) - -step1() \ No newline at end of file diff --git a/src/BoneAnimatedModel.cpp b/src/BoneAnimatedModel.cpp index f693295..c61ee41 100644 --- a/src/BoneAnimatedModel.cpp +++ b/src/BoneAnimatedModel.cpp @@ -17,6 +17,10 @@ namespace ZL return i; } } + + + std::cout << "Bone name not found: " << name << std::endl; + throw std::runtime_error("Bone name not found: " + name); return -1; } @@ -178,22 +182,34 @@ namespace ZL } + std::cout << "bone names count : " << boneNames.size() << std::endl; + //Now process all the bones: for (int i = 0; i < numberBones; i++) { std::string boneName = boneNames[i]; std::string boneParent = boneParentNames[i]; - if (boneParent == "") + if (boneParent == "" || boneParent == "None") { bones[i].parent = -1; } else { + /*std::cout << "-Processing bone: " << boneName << ", parent: " << boneParent << " " << "sizeof:" << boneParent.size() << " " << strlen("None") << + int(boneParent[0])<<","<< + int(boneParent[1]) << ","<< + int(boneParent[2]) << ","<< + int(boneParent[3]) << ","<< + int(boneParent[4]) << "," << + int(boneParent[5]) << "," + << std::endl;*/ bones[i].parent = getIndexByValue(boneParent, boneNames); } for (int j = 0; j < boneChildren[boneName].size(); j++) { + //std::cout << "Enumerating bones:" << j << " " << boneName << " " << boneChildren[boneName][j] << std::endl; + bones[i].children.push_back(getIndexByValue(boneChildren[boneName][j], boneNames)); } @@ -241,7 +257,7 @@ namespace ZL //==== process uv and normals begin - std::cout << "Hello x1" << std::endl; + //std::cout << "Hello x1" << std::endl; std::getline(f, tempLine); //===UV Coordinates: @@ -310,7 +326,7 @@ namespace ZL } - std::cout << "Hello eee" << std::endl; + //std::cout << "Hello eee" << std::endl; std::getline(f, tempLine); //===Normals: @@ -395,10 +411,9 @@ namespace ZL { std::getline(f, tempLine); //Group: 'Bone', Weight: 0.9929084181785583 if (std::regex_search(tempLine, match, pattern_bone_weight)) { - // ��������� ����� (��� �������) std::string word = match.str(1); double weight = std::stod(match.str(2)); - + //std::cout << "Bone name: " << word << ", weight: " << weight << std::endl; int boneNumber = getIndexByValue(word, boneNames); localVerticesBoneWeight[i][j].boneIndex = boneNumber; localVerticesBoneWeight[i][j].weight = weight; @@ -450,10 +465,10 @@ namespace ZL throw std::runtime_error("No number found in the input string."); } - if (i == 0) + /*if (i == 0) { - startingFrame == numberFrame; - } + startingFrame = numberFrame; + }*/ animations[0].keyFrames[i].frame = numberFrame; @@ -463,6 +478,7 @@ namespace ZL { std::getline(f, tempLine); std::string boneName = tempLine.substr(8); + //std::cout << "Processing keyframe " << i << ", bone: " << j << " " << boneName << std::endl; int boneNumber = getIndexByValue(boneName, boneNames); animations[0].keyFrames[i].bones[boneNumber] = startBones[boneNumber]; @@ -588,6 +604,7 @@ namespace ZL if (startingFrame == -1) { + std::cout << "Exception here: frame number is out of range of keyframes. Frame: " << frame << std::endl; throw std::runtime_error("Exception here"); } @@ -601,7 +618,6 @@ namespace ZL std::vector& nextFrameBones = animations[0].keyFrames[startingFrame+1].bones; std::vector skinningMatrixForEachBone; - //std::vector skinningMatrixForEachBone; skinningMatrixForEachBone.resize(currentBones.size()); @@ -645,7 +661,14 @@ namespace ZL skinningMatrixForEachBone[i] = currentBoneMatrixWorld4 * inverstedStartBoneMatrixWorld4; } - + + /*std::cout << "m=" << skinningMatrixForEachBone[5] << std::endl; + + std::cout << "Start Mesh data " << std::endl; + std::cout << startMesh.PositionData[0] << std::endl; + std::cout << startMesh.PositionData[10] << std::endl; + std::cout << startMesh.PositionData[100] << std::endl; + */ for (int i = 0; i < mesh.PositionData.size(); i++) { Vector4f originalPos = { @@ -661,16 +684,36 @@ namespace ZL { if (verticesBoneWeight[i][j].weight != 0) { + if (verticesBoneWeight[i][j].boneIndex == -1) + { + std::cout << "Exception here: bone index is -1 but weight is > 0" << std::endl; + throw std::runtime_error("Bones loaded incorrectly - bone index is -1 but weight is > 0"); + } vMoved = true; - //finalPos = finalPos + MultVectorMatrix(originalPos, skinningMatrixForEachBone[verticesBoneWeight[i][j].boneIndex]) * verticesBoneWeight[i][j].weight; finalPos = finalPos + (skinningMatrixForEachBone[verticesBoneWeight[i][j].boneIndex] * originalPos) * verticesBoneWeight[i][j].weight; + + /*if (i == 100) + { + std::cout << "bone index=" << verticesBoneWeight[i][j].boneIndex << std::endl; + std::cout << "weight=" << verticesBoneWeight[i][j].weight << std::endl; + std::cout << "skinning matrix=" << skinningMatrixForEachBone[verticesBoneWeight[i][j].boneIndex] << std::endl; + std::cout << "original pos=" << originalPos.transpose() << std::endl; + std::cout << "final pos=" << finalPos.transpose() << std::endl; + std::cout << "-----------------" << std::endl; + }*/ } } - if (abs(finalPos(0) - originalPos(0)) > 1 || abs(finalPos(1) - originalPos(1)) > 1 || abs(finalPos(2) - originalPos(2)) > 1) + /*if (i == 100) + { + std::cout << originalPos << std::endl; + std::cout << finalPos << std::endl; + }*/ + + /*if (abs(finalPos(0) - originalPos(0)) > 1 || abs(finalPos(1) - originalPos(1)) > 1 || abs(finalPos(2) - originalPos(2)) > 1) { - } + }*/ if (!vMoved) { @@ -682,9 +725,6 @@ namespace ZL mesh.PositionData[i](2) = finalPos(2); } - - - } diff --git a/src/Character.cpp b/src/Character.cpp index 9349a49..a65a9d9 100644 --- a/src/Character.cpp +++ b/src/Character.cpp @@ -1,5 +1,6 @@ #include "Character.h" #include +#include namespace ZL { @@ -29,6 +30,7 @@ AnimationState Character::resolveActiveState() const { } void Character::update(int64_t deltaMs) { + //std::cout << "update called with deltaMs: " << deltaMs << std::endl; // Move toward walk target on the XZ plane Eigen::Vector3f toTarget = walkTarget - position; toTarget.y() = 0.f; @@ -72,6 +74,7 @@ void Character::update(int64_t deltaMs) { auto& anim = it->second; anim.currentFrame += static_cast(deltaMs) / 24.f; + //std::cout << "Current animation frame: " << anim.currentFrame << " / " << anim.totalFrames << " -- " << anim.lastFrame << std::endl; if (static_cast(anim.currentFrame) >= anim.totalFrames-1) { anim.currentFrame = anim.model.startingFrame; } @@ -82,6 +85,7 @@ void Character::update(int64_t deltaMs) { } void Character::draw(Renderer& renderer) { + //std::cout << "draw called for Character at position: " << position.transpose() << std::endl; AnimationState drawState = resolveActiveState(); auto it = animations.find(drawState); if (it == animations.end() || !texture) return; diff --git a/src/Environment.h b/src/Environment.h index 81cc7b9..90ab3f6 100644 --- a/src/Environment.h +++ b/src/Environment.h @@ -9,6 +9,12 @@ namespace ZL { + +#ifdef EMSCRIPTEN + using std::min; + using std::max; +#endif + constexpr float DEFAULT_ZOOM = 36.f; class Environment { diff --git a/src/Game.cpp b/src/Game.cpp index ac30e5d..55a1bb9 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -39,6 +39,7 @@ namespace ZL Game* Game::s_instance = nullptr; void Game::onResourcesZipLoaded(const char* /*filename*/) { + std::cout << "Resources.zip loaded successfully" << std::endl; if (s_instance) { s_instance->mainThreadHandler.EnqueueMainThreadTask([&]() { s_instance->setupPart2(); @@ -47,7 +48,7 @@ namespace ZL } void Game::onResourcesZipError(const char* /*filename*/) { - std::cerr << "Failed to download resources.zip" << std::endl; + std::cout << "Failed to download resources.zip" << std::endl; } #endif @@ -84,7 +85,7 @@ namespace ZL renderer.shaderManager.AddShaderFromFiles("defaultColor", "resources/shaders/defaultColor.vertex", "resources/shaders/defaultColor_desktop.fragment", CONST_ZIP_FILE); renderer.shaderManager.AddShaderFromFiles("default", "resources/shaders/default.vertex", "resources/shaders/default_desktop.fragment", CONST_ZIP_FILE); #endif - loadingTexture = std::make_unique(CreateTextureDataFromPng("resources/loading.png", CONST_ZIP_FILE)); + loadingTexture = std::make_unique(CreateTextureDataFromPng("resources/loading.png", "")); float minDimension; float width = Environment::projectionWidth; @@ -139,22 +140,28 @@ namespace ZL renderer.shaderManager.AddShaderFromFiles("spark", "resources/shaders/spark.vertex", "resources/shaders/spark_desktop.fragment", CONST_ZIP_FILE); #endif + std::cout << "Load resurces step 4" << std::endl; + roomTexture = std::make_unique(CreateTextureDataFromPng("resources/w/room005.png", CONST_ZIP_FILE)); roomMesh.data = LoadFromTextFile02("resources/w/room001.txt", CONST_ZIP_FILE); roomMesh.data.RotateByMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-M_PI*0.5, Eigen::Vector3f::UnitY())).toRotationMatrix()); roomMesh.RefreshVBO(); - + std::cout << "Load resurces step 5" << std::endl; fireboxTexture = std::make_unique(CreateTextureDataFromPng("resources/w/Cube001.png", CONST_ZIP_FILE)); fireboxMesh.data = LoadFromTextFile02("resources/w/firebox.txt", CONST_ZIP_FILE); fireboxMesh.data.RotateByMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-M_PI * 0.5, Eigen::Vector3f::UnitY())).toRotationMatrix()); fireboxMesh.RefreshVBO(); + + std::cout << "Load resurces step 6" << std::endl; inaiTexture = std::make_unique(CreateTextureDataFromPng("resources/w/inai001.png", CONST_ZIP_FILE)); + std::cout << "Load resurces step 6.1" << std::endl; inaiMesh.data = LoadFromTextFile02("resources/w/inai001.txt", CONST_ZIP_FILE); inaiMesh.data.RotateByMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-M_PI * 0.5, Eigen::Vector3f::UnitY())).toRotationMatrix()); inaiMesh.data.Move({ 2.5, 1.4, -9.9 }); inaiMesh.RefreshVBO(); + std::cout << "Load resurces step 7" << std::endl; benchTexture = std::make_unique(CreateTextureDataFromPng("resources/w/bench001opt.png", CONST_ZIP_FILE)); benchMesh.data = LoadFromTextFile02("resources/w/bench002opt.txt", CONST_ZIP_FILE); benchMesh.data.Scale(3.f); @@ -162,6 +169,8 @@ namespace ZL benchMesh.data.Move({ -2.1, 0.5, -7.9 }); benchMesh.RefreshVBO(); + std::cout << "Load resurces step 8" << std::endl; + auto violaTexture = std::make_shared(CreateTextureDataFromPng("resources/viola.png", CONST_ZIP_FILE)); // Player (Viola) @@ -176,39 +185,51 @@ namespace ZL Eigen::Quaternionf(Eigen::AngleAxisf(-M_PI * 0.5f, Eigen::Vector3f::UnitX())) * Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitZ())); + std::cout << "Load resurces step 9" << std::endl; auto defaultTexture = std::make_shared(CreateTextureDataFromPng("resources/w/default_skin001.png", CONST_ZIP_FILE)); auto npc01 = std::make_unique(); npc01->loadAnimation(AnimationState::IDLE, "resources/w/default_idle002.txt", CONST_ZIP_FILE); npc01->loadAnimation(AnimationState::WALK, "resources/w/default_walk001.txt", CONST_ZIP_FILE); + //npc01->loadAnimation(AnimationState::IDLE, "resources/idleviola_uv010.txt", CONST_ZIP_FILE); + //npc01->loadAnimation(AnimationState::WALK, "resources/walkviola_uv010.txt", CONST_ZIP_FILE); npc01->setTexture(defaultTexture); npc01->walkSpeed = 1.5f; npc01->rotationSpeed = 8.0f; npc01->modelScale = 0.01f; + //npc01->modelScale = 0.1f; npc01->modelCorrectionRotation = Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitY())); - npc01->position = Eigen::Vector3f(0.f, 0.f, -45.f); + std::cout << "Load resurces step 10" << std::endl; + npc01->position = Eigen::Vector3f(0.f, 0.f, -10.f); npc01->setTarget(npc01->position); npcs.push_back(std::move(npc01)); auto ghostTexture = std::make_shared(CreateTextureDataFromPng("resources/w/ghost_skin001.png", CONST_ZIP_FILE)); + std::cout << "Load resurces step 11" << std::endl; auto npc02 = std::make_unique(); - //npc02->loadAnimation(AnimationState::IDLE, "resources/w/default_float001.txt", CONST_ZIP_FILE); - npc02->loadAnimation(AnimationState::IDLE, "resources/w/float_attack003.txt", CONST_ZIP_FILE); + npc02->loadAnimation(AnimationState::IDLE, "resources/w/default_float001.txt", CONST_ZIP_FILE); + //npc02->loadAnimation(AnimationState::IDLE, "resources/w/float_attack003.txt", CONST_ZIP_FILE); + //npc02->loadAnimation(AnimationState::IDLE, "resources/idleviola_uv010.txt", CONST_ZIP_FILE); npc02->setTexture(ghostTexture); npc02->walkSpeed = 1.5f; npc02->rotationSpeed = 8.0f; npc02->modelScale = 0.01f; + //npc02->modelScale = 0.1f; npc02->modelCorrectionRotation = Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitY())); npc02->position = Eigen::Vector3f(0.f, 0.f, -20.f); npc02->setTarget(npc02->position); npcs.push_back(std::move(npc02)); + std::cout << "Load resurces step 12" << std::endl; + loadingCompleted = true; scriptEngine.init(this); + + std::cout << "Load resurces step 13" << std::endl; } diff --git a/src/ScriptEngine.cpp b/src/ScriptEngine.cpp index 9fd699d..0951a18 100644 --- a/src/ScriptEngine.cpp +++ b/src/ScriptEngine.cpp @@ -1,74 +1,60 @@ #include "ScriptEngine.h" #include "Game.h" -#include #include -#include -namespace py = pybind11; - -// Static pointer used by the embedded module (set before interpreter starts). -static ZL::Game* s_game = nullptr; - -// The embedded module must be defined at file scope before the interpreter -// is started. It exposes a minimal surface: one function per scripting command. -PYBIND11_EMBEDDED_MODULE(game_api, m) { - m.doc() = "Game scripting API"; - - // npc_walk_to(index, x, y, z, on_arrived=None) - // Tells the NPC at `index` to walk to (x,y,z). - // on_arrived is an optional Python callable invoked once when the NPC arrives. - // It can call npc_walk_to again (or anything else) to chain behaviour. - m.def("npc_walk_to", [](int index, float x, float y, float z, py::object on_arrived) { - if (!s_game) { - std::cerr << "[script] game_api.npc_walk_to: engine not ready\n"; - return; - } - auto& npcs = s_game->npcs; - if (index < 0 || index >= static_cast(npcs.size())) { - std::cerr << "[script] game_api.npc_walk_to: index " << index - << " out of range (0.." << npcs.size() - 1 << ")\n"; - return; - } - std::function cb; - if (!on_arrived.is_none()) { - cb = [on_arrived]() { - try { - on_arrived(); - } catch (const py::error_already_set& e) { - std::cerr << "[script] on_arrived callback error:\n" << e.what() << "\n"; - } - }; - } - npcs[index]->setTarget(Eigen::Vector3f(x, y, z), std::move(cb)); - }, - py::arg("index"), py::arg("x"), py::arg("y"), py::arg("z"), - py::arg("on_arrived") = py::none(), - "Command NPC[index] to walk to (x,y,z). on_arrived is called when the NPC arrives."); -} +#define SOL_ALL_SAFETIES_ON 1 +#include namespace ZL { +struct ScriptEngine::Impl { + sol::state lua; +}; + ScriptEngine::ScriptEngine() = default; ScriptEngine::~ScriptEngine() = default; void ScriptEngine::init(Game* game) { - s_game = game; - interpreter = std::make_unique(); - runScript("resources/start.py"); + impl = std::make_unique(); + sol::state& lua = impl->lua; + + lua.open_libraries(sol::lib::base, sol::lib::math, sol::lib::string, sol::lib::table); + + auto api = lua.create_named_table("game_api"); + + // npc_walk_to(index, x, y, z [, on_arrived]) + // on_arrived is an optional Lua function called when the NPC reaches the target. + // It can call npc_walk_to again (or anything else) to chain behaviour. + api.set_function("npc_walk_to", + [game](int index, float x, float y, float z, sol::object on_arrived) { + auto& npcs = game->npcs; + if (index < 0 || index >= static_cast(npcs.size())) { + std::cerr << "[script] npc_walk_to: index " << index + << " out of range (0.." << npcs.size() - 1 << ")\n"; + return; + } + std::function cb; + if (on_arrived.is()) { + sol::protected_function fn = on_arrived.as(); + cb = [fn]() mutable { + auto result = fn(); + if (!result.valid()) { + sol::error err = result; + std::cerr << "[script] on_arrived error: " << err.what() << "\n"; + } + }; + } + npcs[index]->setTarget(Eigen::Vector3f(x, y, z), std::move(cb)); + }); + + runScript("resources/start.lua"); } void ScriptEngine::runScript(const std::string& path) { - std::ifstream file(path); - if (!file.is_open()) { - std::cerr << "[script] Could not open script: " << path << "\n"; - return; - } - std::string source((std::istreambuf_iterator(file)), - std::istreambuf_iterator()); - try { - py::exec(source); - } catch (const py::error_already_set& e) { - std::cerr << "[script] Error in " << path << ":\n" << e.what() << "\n"; + auto result = impl->lua.safe_script_file(path, sol::script_pass_on_error); + if (!result.valid()) { + sol::error err = result; + std::cerr << "[script] Error in " << path << ": " << err.what() << "\n"; } } diff --git a/src/ScriptEngine.h b/src/ScriptEngine.h index aa0e1b0..5c45d51 100644 --- a/src/ScriptEngine.h +++ b/src/ScriptEngine.h @@ -2,9 +2,6 @@ #include #include -// Forward-declare the heavy pybind11 type so including this header stays cheap. -namespace pybind11 { class scoped_interpreter; } - namespace ZL { class Game; @@ -17,11 +14,12 @@ public: // Must be called once, after the Game's NPCs are ready. void init(Game* game); - // Execute a Python script file. Logs errors to stderr. + // Execute a Lua script file. Logs errors to stderr. void runScript(const std::string& path); private: - std::unique_ptr interpreter; + struct Impl; + std::unique_ptr impl; }; } // namespace ZL diff --git a/src/TextModel.cpp b/src/TextModel.cpp index 4927485..079a220 100644 --- a/src/TextModel.cpp +++ b/src/TextModel.cpp @@ -51,6 +51,7 @@ namespace ZL numberVertices = std::stoi(number_str); } else { + std::cout << "No number found in the input string: " << tempLine << std::endl; throw std::runtime_error("No number found in the input string."); } @@ -85,7 +86,8 @@ namespace ZL numberTriangles = std::stoi(number_str); } else { - throw std::runtime_error("No number found in the input string."); + std::cout << "-No number found in the input string: " << tempLine << std::endl; + throw std::runtime_error("-No number found in the input string."); } @@ -105,11 +107,13 @@ namespace ZL uvCount = std::stoi(number_str); } else { - throw std::runtime_error("No number found in the input string."); + std::cout << "2 No number found in the input string: " << tempLine << std::endl; + throw std::runtime_error("2 No number found in the input string."); } if (uvCount != 3) { + std::cout << "UV count is not 3 for triangle " << i << ": " << uvCount << std::endl; throw std::runtime_error("more than 3 uvs"); } @@ -129,6 +133,7 @@ namespace ZL if (floatValues.size() != 2) { + std::cout << "UV count is not 2: " << j << " " << floatValues.size() << std::endl; throw std::runtime_error("more than 2 uvs---"); } @@ -136,7 +141,7 @@ namespace ZL } } - std::cout << "Normals go" << std::endl; + //std::cout << "Normals go" << std::endl; std::getline(f, tempLine); //===Normals: @@ -160,7 +165,7 @@ namespace ZL normals[i] = Vector3f{ floatValues[0], floatValues[1], floatValues[2] }; } - std::cout << "Triangles go:" << std::endl; + //std::cout << "Triangles go:" << std::endl; std::getline(f, tempLine); //===Triangles: 3974 @@ -198,11 +203,6 @@ namespace ZL result.PositionData.push_back(vertices[triangles[i][1]]); result.PositionData.push_back(vertices[triangles[i][2]]); - /* - result.NormalData.push_back(normals[triangles[i][0]]); - result.NormalData.push_back(normals[triangles[i][1]]); - result.NormalData.push_back(normals[triangles[i][2]]); - */ result.TexCoordData.push_back(uvCoords[i][0]); result.TexCoordData.push_back(uvCoords[i][1]); result.TexCoordData.push_back(uvCoords[i][2]); @@ -280,6 +280,7 @@ namespace ZL numberVertices = std::stoi(match.str()); } else { + std::cout << "Vertices header not found or invalid: " << tempLine << std::endl; throw std::runtime_error("Vertices header not found or invalid."); } @@ -314,14 +315,10 @@ namespace ZL // UV - [7], [8] if (floatValues.size() < 9) { + std::cout << "Malformed vertex line at index " << i << ": " << tempLine << std::endl; throw std::runtime_error("Malformed vertex line at index " + std::to_string(i)); } - /*if (floatValues[2] > 1.f) - { - std::cout << "got" << std::endl; - }*/ - tempPositions[i] = Vector3f{ floatValues[1], floatValues[2], floatValues[3] }; tempNormals[i] = Vector3f{ floatValues[4], floatValues[5], floatValues[6] }; tempUVs[i] = Vector2f{ floatValues[7], floatValues[8] }; @@ -339,6 +336,7 @@ namespace ZL numberTriangles = std::stoi(match.str()); } else { + std::cout << "Triangles header not found or invalid: " << tempLine << std::endl; throw std::runtime_error("Triangles header not found."); } @@ -363,6 +361,7 @@ namespace ZL } if (indices.size() != 3) { + std::cout << "Malformed triangle line at index " << i << ": " << tempLine << std::endl; throw std::runtime_error("Malformed triangle line at index " + std::to_string(i)); }