Working on web, change python to lua

This commit is contained in:
Vladislav Khorev 2026-04-04 14:29:20 +03:00
parent 90e2a369f4
commit 178f69967b
14 changed files with 327 additions and 162 deletions

View File

@ -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")

View File

@ -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<T&>::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()

View File

@ -0,0 +1,14 @@
--- a/include/sol/optional_implementation.hpp
+++ b/include/sol/optional_implementation.hpp
@@ -2189,7 +2189,10 @@
template <class... Args>
T& emplace(Args&&... args) noexcept {
static_assert(std::is_constructible<T, Args&&...>::value, "T must be constructible with Args");
*this = nullopt;
- this->construct(std::forward<Args>(args)...);
+ // Reference specialization stores a pointer; set it directly.
+ // construct() only exists in the non-reference specialization.
+ m_value = std::addressof(std::forward<Args>(args)...);
+ return *m_value;
}

View File

@ -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<T&>::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 .
)

View File

@ -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)

16
resources/start.lua Normal file
View File

@ -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()

View File

@ -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()

View File

@ -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)) {
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> (<28><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
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<Bone>& nextFrameBones = animations[0].keyFrames[startingFrame+1].bones;
std::vector<Matrix4f> skinningMatrixForEachBone;
//std::vector<Matrix3f> 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);
}
}

View File

@ -1,5 +1,6 @@
#include "Character.h"
#include <cmath>
#include <iostream>
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<float>(deltaMs) / 24.f;
//std::cout << "Current animation frame: " << anim.currentFrame << " / " << anim.totalFrames << " -- " << anim.lastFrame << std::endl;
if (static_cast<int>(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;

View File

@ -9,6 +9,12 @@
namespace ZL {
#ifdef EMSCRIPTEN
using std::min;
using std::max;
#endif
constexpr float DEFAULT_ZOOM = 36.f;
class Environment {

View File

@ -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<Texture>(CreateTextureDataFromPng("resources/loading.png", CONST_ZIP_FILE));
loadingTexture = std::make_unique<Texture>(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<Texture>(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<Texture>(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<Texture>(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<Texture>(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<Texture>(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<Texture>(CreateTextureDataFromPng("resources/w/default_skin001.png", CONST_ZIP_FILE));
auto npc01 = std::make_unique<Character>();
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<Texture>(CreateTextureDataFromPng("resources/w/ghost_skin001.png", CONST_ZIP_FILE));
std::cout << "Load resurces step 11" << std::endl;
auto npc02 = std::make_unique<Character>();
//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;
}

View File

@ -1,74 +1,60 @@
#include "ScriptEngine.h"
#include "Game.h"
#include <pybind11/embed.h>
#include <iostream>
#include <fstream>
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<int>(npcs.size())) {
std::cerr << "[script] game_api.npc_walk_to: index " << index
<< " out of range (0.." << npcs.size() - 1 << ")\n";
return;
}
std::function<void()> 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 <sol/sol.hpp>
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<py::scoped_interpreter>();
runScript("resources/start.py");
impl = std::make_unique<Impl>();
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<int>(npcs.size())) {
std::cerr << "[script] npc_walk_to: index " << index
<< " out of range (0.." << npcs.size() - 1 << ")\n";
return;
}
std::function<void()> cb;
if (on_arrived.is<sol::protected_function>()) {
sol::protected_function fn = on_arrived.as<sol::protected_function>();
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<char>(file)),
std::istreambuf_iterator<char>());
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";
}
}

View File

@ -2,9 +2,6 @@
#include <string>
#include <memory>
// 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<pybind11::scoped_interpreter> interpreter;
struct Impl;
std::unique_ptr<Impl> impl;
};
} // namespace ZL

View File

@ -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));
}