diff --git a/proj-web/CMakeLists.txt b/proj-web/CMakeLists.txt index 1373cd4..64c3c73 100644 --- a/proj-web/CMakeLists.txt +++ b/proj-web/CMakeLists.txt @@ -109,6 +109,8 @@ set(SOURCES ../src/LocationState.cpp ../src/LocationEditor.h ../src/LocationEditor.cpp + ../src/NpcCar.h + ../src/NpcCar.cpp ../src/GameConstants.h ../src/GameConstants.cpp ../src/GameState.h @@ -195,6 +197,7 @@ set(EMSCRIPTEN_LINK_FLAGS #"-sPTHREAD_POOL_SIZE=4" "-sALLOW_MEMORY_GROWTH=1" "-sFULL_ES3=1" + "-lidbfs.js" "--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/loading.png@resources/loading.png" "--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/loadingProgressBar.png@resources/loadingProgressBar.png" "--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/loadingProgressBarFrame.png@resources/loadingProgressBarFrame.png" diff --git a/resources/shaders/default_shadow_web.vertex b/resources/shaders/default_shadow_web.vertex new file mode 100644 index 0000000..7f3b9c5 --- /dev/null +++ b/resources/shaders/default_shadow_web.vertex @@ -0,0 +1,19 @@ +attribute vec3 vPosition; +attribute vec2 vTexCoord; +attribute vec3 vNormal; + +varying vec2 texCoord; +varying vec4 fragPosLightSpace; +varying vec3 fragNormal; + +uniform mat4 ProjectionModelViewMatrix; +uniform mat4 ModelViewMatrix; +uniform mat4 uLightFromCamera; + +void main() +{ + gl_Position = ProjectionModelViewMatrix * vec4(vPosition, 1.0); + texCoord = vTexCoord; + fragPosLightSpace = uLightFromCamera * ModelViewMatrix * vec4(vPosition, 1.0); + fragNormal = mat3(ModelViewMatrix) * vNormal; +} diff --git a/resources/shaders/fog_shadow_web.vertex b/resources/shaders/fog_shadow_web.vertex new file mode 100644 index 0000000..8d072e0 --- /dev/null +++ b/resources/shaders/fog_shadow_web.vertex @@ -0,0 +1,23 @@ +attribute vec3 vPosition; +attribute vec2 vTexCoord; +attribute vec3 vNormal; + +varying vec2 texCoord; +varying vec4 fragPosLightSpace; +varying vec3 fragNormal; +varying float fogDistance; + +uniform mat4 ProjectionModelViewMatrix; +uniform mat4 ModelViewMatrix; +uniform mat4 uLightFromCamera; +uniform vec3 uPlayerEyePos; + +void main() +{ + vec4 eyePos = ModelViewMatrix * vec4(vPosition, 1.0); + fogDistance = length(eyePos.xyz - uPlayerEyePos); + gl_Position = ProjectionModelViewMatrix * vec4(vPosition, 1.0); + texCoord = vTexCoord; + fragPosLightSpace = uLightFromCamera * eyePos; + fragNormal = mat3(ModelViewMatrix) * vNormal; +} diff --git a/resources/shaders/fog_skinning_shadow_web.vertex b/resources/shaders/fog_skinning_shadow_web.vertex new file mode 100644 index 0000000..eaefa96 --- /dev/null +++ b/resources/shaders/fog_skinning_shadow_web.vertex @@ -0,0 +1,69 @@ +attribute vec3 vPosition; +attribute vec2 vTexCoord; +attribute vec3 vNormal; +attribute vec4 aBoneIndices0; +attribute vec2 aBoneIndices1; +attribute vec4 aBoneWeights0; +attribute vec2 aBoneWeights1; + +varying vec2 texCoord; +varying vec4 fragPosLightSpace; +varying vec3 fragNormal; +varying float fogDistance; + +uniform mat4 ProjectionModelViewMatrix; +uniform mat4 ModelViewMatrix; +uniform mat4 uLightFromCamera; +uniform mat4 uBoneMatrices[58]; +uniform vec3 uPlayerEyePos; + +void main() +{ + vec4 skinnedPos = vec4(0.0, 0.0, 0.0, 0.0); + vec3 skinnedNormal = vec3(0.0, 0.0, 0.0); + vec4 originalPos = vec4(vPosition, 1.0); + float totalWeight = 0.0; + + if (aBoneWeights0.x > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices0.x)] * originalPos * aBoneWeights0.x; + skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices0.x)]) * vNormal * aBoneWeights0.x; + totalWeight += aBoneWeights0.x; + } + if (aBoneWeights0.y > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices0.y)] * originalPos * aBoneWeights0.y; + skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices0.y)]) * vNormal * aBoneWeights0.y; + totalWeight += aBoneWeights0.y; + } + if (aBoneWeights0.z > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices0.z)] * originalPos * aBoneWeights0.z; + skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices0.z)]) * vNormal * aBoneWeights0.z; + totalWeight += aBoneWeights0.z; + } + if (aBoneWeights0.w > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices0.w)] * originalPos * aBoneWeights0.w; + skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices0.w)]) * vNormal * aBoneWeights0.w; + totalWeight += aBoneWeights0.w; + } + if (aBoneWeights1.x > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices1.x)] * originalPos * aBoneWeights1.x; + skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices1.x)]) * vNormal * aBoneWeights1.x; + totalWeight += aBoneWeights1.x; + } + if (aBoneWeights1.y > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices1.y)] * originalPos * aBoneWeights1.y; + skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices1.y)]) * vNormal * aBoneWeights1.y; + totalWeight += aBoneWeights1.y; + } + + if (totalWeight < 0.001) { + skinnedPos = originalPos; + skinnedNormal = vNormal; + } + + vec4 eyePos = ModelViewMatrix * skinnedPos; + fogDistance = length(eyePos.xyz - uPlayerEyePos); + gl_Position = ProjectionModelViewMatrix * skinnedPos; + texCoord = vTexCoord; + fragPosLightSpace = uLightFromCamera * eyePos; + fragNormal = mat3(ModelViewMatrix) * skinnedNormal; +} diff --git a/resources/shaders/fog_skinning_web.vertex b/resources/shaders/fog_skinning_web.vertex new file mode 100644 index 0000000..842a9b4 --- /dev/null +++ b/resources/shaders/fog_skinning_web.vertex @@ -0,0 +1,55 @@ +attribute vec3 vPosition; +attribute vec2 vTexCoord; +attribute vec4 aBoneIndices0; +attribute vec2 aBoneIndices1; +attribute vec4 aBoneWeights0; +attribute vec2 aBoneWeights1; + +varying vec2 texCoord; +varying float fogDistance; + +uniform mat4 ProjectionModelViewMatrix; +uniform mat4 ModelViewMatrix; +uniform mat4 uBoneMatrices[58]; +uniform vec3 uPlayerEyePos; + +void main() +{ + vec4 skinnedPos = vec4(0.0, 0.0, 0.0, 0.0); + vec4 originalPos = vec4(vPosition, 1.0); + float totalWeight = 0.0; + + if (aBoneWeights0.x > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices0.x)] * originalPos * aBoneWeights0.x; + totalWeight += aBoneWeights0.x; + } + if (aBoneWeights0.y > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices0.y)] * originalPos * aBoneWeights0.y; + totalWeight += aBoneWeights0.y; + } + if (aBoneWeights0.z > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices0.z)] * originalPos * aBoneWeights0.z; + totalWeight += aBoneWeights0.z; + } + if (aBoneWeights0.w > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices0.w)] * originalPos * aBoneWeights0.w; + totalWeight += aBoneWeights0.w; + } + if (aBoneWeights1.x > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices1.x)] * originalPos * aBoneWeights1.x; + totalWeight += aBoneWeights1.x; + } + if (aBoneWeights1.y > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices1.y)] * originalPos * aBoneWeights1.y; + totalWeight += aBoneWeights1.y; + } + + if (totalWeight < 0.001) { + skinnedPos = originalPos; + } + + vec4 eyePos = ModelViewMatrix * skinnedPos; + fogDistance = length(eyePos.xyz - uPlayerEyePos); + gl_Position = ProjectionModelViewMatrix * skinnedPos; + texCoord = vTexCoord; +} diff --git a/resources/shaders/night_fog_shadow_web.vertex b/resources/shaders/night_fog_shadow_web.vertex new file mode 100644 index 0000000..8452efa --- /dev/null +++ b/resources/shaders/night_fog_shadow_web.vertex @@ -0,0 +1,27 @@ +attribute vec3 vPosition; +attribute vec2 vTexCoord; +attribute vec3 vNormal; + +varying vec2 texCoord; +varying vec4 fragPosLightSpace; +varying vec3 fragNormal; +varying float fogDistance; +varying vec3 fragViewPos; +varying vec2 fragWorldXZ; + +uniform mat4 ProjectionModelViewMatrix; +uniform mat4 ModelViewMatrix; +uniform mat4 uLightFromCamera; +uniform vec3 uPlayerEyePos; + +void main() +{ + vec4 eyePos = ModelViewMatrix * vec4(vPosition, 1.0); + fogDistance = length(eyePos.xyz - uPlayerEyePos); + gl_Position = ProjectionModelViewMatrix * vec4(vPosition, 1.0); + texCoord = vTexCoord; + fragViewPos = eyePos.xyz; + fragNormal = mat3(ModelViewMatrix) * vNormal; + fragPosLightSpace = uLightFromCamera * eyePos; + fragWorldXZ = vPosition.xz; +} diff --git a/resources/shaders/night_fog_skinning_shadow_web.vertex b/resources/shaders/night_fog_skinning_shadow_web.vertex new file mode 100644 index 0000000..19049a6 --- /dev/null +++ b/resources/shaders/night_fog_skinning_shadow_web.vertex @@ -0,0 +1,74 @@ +attribute vec3 vPosition; +attribute vec2 vTexCoord; +attribute vec3 vNormal; +attribute vec4 aBoneIndices0; +attribute vec2 aBoneIndices1; +attribute vec4 aBoneWeights0; +attribute vec2 aBoneWeights1; + +varying vec2 texCoord; +varying vec4 fragPosLightSpace; +varying vec3 fragNormal; +varying float fogDistance; +varying vec3 fragViewPos; +varying vec2 fragWorldXZ; + +uniform mat4 ProjectionModelViewMatrix; +uniform mat4 ModelViewMatrix; +uniform mat4 uLightFromCamera; +uniform mat4 uViewInverse; +uniform mat4 uBoneMatrices[58]; +uniform vec3 uPlayerEyePos; + +void main() +{ + vec4 skinnedPos = vec4(0.0, 0.0, 0.0, 0.0); + vec3 skinnedNormal = vec3(0.0, 0.0, 0.0); + vec4 originalPos = vec4(vPosition, 1.0); + float totalWeight = 0.0; + + if (aBoneWeights0.x > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices0.x)] * originalPos * aBoneWeights0.x; + skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices0.x)]) * vNormal * aBoneWeights0.x; + totalWeight += aBoneWeights0.x; + } + if (aBoneWeights0.y > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices0.y)] * originalPos * aBoneWeights0.y; + skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices0.y)]) * vNormal * aBoneWeights0.y; + totalWeight += aBoneWeights0.y; + } + if (aBoneWeights0.z > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices0.z)] * originalPos * aBoneWeights0.z; + skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices0.z)]) * vNormal * aBoneWeights0.z; + totalWeight += aBoneWeights0.z; + } + if (aBoneWeights0.w > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices0.w)] * originalPos * aBoneWeights0.w; + skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices0.w)]) * vNormal * aBoneWeights0.w; + totalWeight += aBoneWeights0.w; + } + if (aBoneWeights1.x > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices1.x)] * originalPos * aBoneWeights1.x; + skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices1.x)]) * vNormal * aBoneWeights1.x; + totalWeight += aBoneWeights1.x; + } + if (aBoneWeights1.y > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices1.y)] * originalPos * aBoneWeights1.y; + skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices1.y)]) * vNormal * aBoneWeights1.y; + totalWeight += aBoneWeights1.y; + } + + if (totalWeight < 0.001) { + skinnedPos = originalPos; + skinnedNormal = vNormal; + } + + vec4 eyePos = ModelViewMatrix * skinnedPos; + fogDistance = length(eyePos.xyz - uPlayerEyePos); + gl_Position = ProjectionModelViewMatrix * skinnedPos; + texCoord = vTexCoord; + fragViewPos = eyePos.xyz; + fragNormal = mat3(ModelViewMatrix) * skinnedNormal; + fragPosLightSpace = uLightFromCamera * eyePos; + fragWorldXZ = (uViewInverse * eyePos).xz; +} diff --git a/resources/shaders/night_fog_skinning_web.vertex b/resources/shaders/night_fog_skinning_web.vertex new file mode 100644 index 0000000..228c5a1 --- /dev/null +++ b/resources/shaders/night_fog_skinning_web.vertex @@ -0,0 +1,71 @@ +attribute vec3 vPosition; +attribute vec2 vTexCoord; +attribute vec3 vNormal; +attribute vec4 aBoneIndices0; +attribute vec2 aBoneIndices1; +attribute vec4 aBoneWeights0; +attribute vec2 aBoneWeights1; + +varying vec2 texCoord; +varying float fogDistance; +varying vec3 fragViewPos; +varying vec3 fragNormal; +varying vec2 fragWorldXZ; + +uniform mat4 ProjectionModelViewMatrix; +uniform mat4 ModelViewMatrix; +uniform mat4 uViewInverse; +uniform mat4 uBoneMatrices[58]; +uniform vec3 uPlayerEyePos; + +void main() +{ + vec4 skinnedPos = vec4(0.0, 0.0, 0.0, 0.0); + vec3 skinnedNormal = vec3(0.0, 0.0, 0.0); + vec4 originalPos = vec4(vPosition, 1.0); + float totalWeight = 0.0; + + if (aBoneWeights0.x > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices0.x)] * originalPos * aBoneWeights0.x; + skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices0.x)]) * vNormal * aBoneWeights0.x; + totalWeight += aBoneWeights0.x; + } + if (aBoneWeights0.y > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices0.y)] * originalPos * aBoneWeights0.y; + skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices0.y)]) * vNormal * aBoneWeights0.y; + totalWeight += aBoneWeights0.y; + } + if (aBoneWeights0.z > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices0.z)] * originalPos * aBoneWeights0.z; + skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices0.z)]) * vNormal * aBoneWeights0.z; + totalWeight += aBoneWeights0.z; + } + if (aBoneWeights0.w > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices0.w)] * originalPos * aBoneWeights0.w; + skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices0.w)]) * vNormal * aBoneWeights0.w; + totalWeight += aBoneWeights0.w; + } + if (aBoneWeights1.x > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices1.x)] * originalPos * aBoneWeights1.x; + skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices1.x)]) * vNormal * aBoneWeights1.x; + totalWeight += aBoneWeights1.x; + } + if (aBoneWeights1.y > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices1.y)] * originalPos * aBoneWeights1.y; + skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices1.y)]) * vNormal * aBoneWeights1.y; + totalWeight += aBoneWeights1.y; + } + + if (totalWeight < 0.001) { + skinnedPos = originalPos; + skinnedNormal = vNormal; + } + + vec4 eyePos = ModelViewMatrix * skinnedPos; + fogDistance = length(eyePos.xyz - uPlayerEyePos); + gl_Position = ProjectionModelViewMatrix * skinnedPos; + texCoord = vTexCoord; + fragViewPos = eyePos.xyz; + fragNormal = mat3(ModelViewMatrix) * skinnedNormal; + fragWorldXZ = (uViewInverse * eyePos).xz; +} diff --git a/resources/shaders/night_fog_web.vertex b/resources/shaders/night_fog_web.vertex new file mode 100644 index 0000000..8f6e4e3 --- /dev/null +++ b/resources/shaders/night_fog_web.vertex @@ -0,0 +1,24 @@ +attribute vec3 vPosition; +attribute vec2 vTexCoord; +attribute vec3 vNormal; + +varying vec2 texCoord; +varying float fogDistance; +varying vec3 fragViewPos; +varying vec3 fragNormal; +varying vec2 fragWorldXZ; + +uniform mat4 ProjectionModelViewMatrix; +uniform mat4 ModelViewMatrix; +uniform vec3 uPlayerEyePos; + +void main() +{ + vec4 eyePos = ModelViewMatrix * vec4(vPosition.xyz, 1.0); + fogDistance = length(eyePos.xyz - uPlayerEyePos); + gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0); + texCoord = vTexCoord; + fragViewPos = eyePos.xyz; + fragNormal = mat3(ModelViewMatrix) * vNormal; + fragWorldXZ = vPosition.xz; +} diff --git a/resources/shaders/skinning_shadow_web.vertex b/resources/shaders/skinning_shadow_web.vertex new file mode 100644 index 0000000..84d7b2a --- /dev/null +++ b/resources/shaders/skinning_shadow_web.vertex @@ -0,0 +1,65 @@ +attribute vec3 vPosition; +attribute vec2 vTexCoord; +attribute vec3 vNormal; +attribute vec4 aBoneIndices0; +attribute vec2 aBoneIndices1; +attribute vec4 aBoneWeights0; +attribute vec2 aBoneWeights1; + +varying vec2 texCoord; +varying vec4 fragPosLightSpace; +varying vec3 fragNormal; + +uniform mat4 ProjectionModelViewMatrix; +uniform mat4 ModelViewMatrix; +uniform mat4 uLightFromCamera; +uniform mat4 uBoneMatrices[58]; + +void main() +{ + vec4 skinnedPos = vec4(0.0, 0.0, 0.0, 0.0); + vec3 skinnedNormal = vec3(0.0, 0.0, 0.0); + vec4 originalPos = vec4(vPosition, 1.0); + float totalWeight = 0.0; + + if (aBoneWeights0.x > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices0.x)] * originalPos * aBoneWeights0.x; + skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices0.x)]) * vNormal * aBoneWeights0.x; + totalWeight += aBoneWeights0.x; + } + if (aBoneWeights0.y > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices0.y)] * originalPos * aBoneWeights0.y; + skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices0.y)]) * vNormal * aBoneWeights0.y; + totalWeight += aBoneWeights0.y; + } + if (aBoneWeights0.z > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices0.z)] * originalPos * aBoneWeights0.z; + skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices0.z)]) * vNormal * aBoneWeights0.z; + totalWeight += aBoneWeights0.z; + } + if (aBoneWeights0.w > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices0.w)] * originalPos * aBoneWeights0.w; + skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices0.w)]) * vNormal * aBoneWeights0.w; + totalWeight += aBoneWeights0.w; + } + if (aBoneWeights1.x > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices1.x)] * originalPos * aBoneWeights1.x; + skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices1.x)]) * vNormal * aBoneWeights1.x; + totalWeight += aBoneWeights1.x; + } + if (aBoneWeights1.y > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices1.y)] * originalPos * aBoneWeights1.y; + skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices1.y)]) * vNormal * aBoneWeights1.y; + totalWeight += aBoneWeights1.y; + } + + if (totalWeight < 0.001) { + skinnedPos = originalPos; + skinnedNormal = vNormal; + } + + gl_Position = ProjectionModelViewMatrix * skinnedPos; + texCoord = vTexCoord; + fragPosLightSpace = uLightFromCamera * ModelViewMatrix * skinnedPos; + fragNormal = mat3(ModelViewMatrix) * skinnedNormal; +} diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt deleted file mode 100644 index 2880449..0000000 --- a/server/CMakeLists.txt +++ /dev/null @@ -1,49 +0,0 @@ -cmake_minimum_required(VERSION 3.15) -project(SpaceGameServer) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -# Подключаем зависимости нашего движка -include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/ThirdParty.cmake) - -# Настройка флагов для тяжелых шаблонов Boost -if (MSVC) - add_compile_options(/bigobj) -endif() - -# Добавляем скомпилированные компоненты Boost через относительные пути -# CMake сам создаст цели boost_system и др. -add_subdirectory("${BOOST_SRC_DIR}/libs/system" boost-system-build EXCLUDE_FROM_ALL) -add_subdirectory("${BOOST_SRC_DIR}/libs/assert" boost-assert-build EXCLUDE_FROM_ALL) -add_subdirectory("${BOOST_SRC_DIR}/libs/config" boost-config-build EXCLUDE_FROM_ALL) -add_subdirectory("${BOOST_SRC_DIR}/libs/throw_exception" boost-throw_exception-build EXCLUDE_FROM_ALL) -add_subdirectory("${BOOST_SRC_DIR}/libs/variant2" boost-variant2-build EXCLUDE_FROM_ALL) -add_subdirectory("${BOOST_SRC_DIR}/libs/mp11" boost-mp11-build EXCLUDE_FROM_ALL) -add_subdirectory("${BOOST_SRC_DIR}/libs/winapi" boost-winapi-build EXCLUDE_FROM_ALL) -add_subdirectory("${BOOST_SRC_DIR}/libs/predef" boost-predef-build EXCLUDE_FROM_ALL) -# EXCLUDE_FROM_ALL гарантирует, что мы собираем только то, что линкуем - -# Исполняемый файл сервера -add_executable(Server -server.h -server.cpp -../src/network/ClientState.h -../src/network/ClientState.cpp -) - -target_include_directories(Server PRIVATE ${BOOST_SRC_DIR}) - -# Линковка -target_link_libraries(Server - PRIVATE - boost_system # Скомпилированная часть для error_code - eigen_external_lib # Если планируешь использовать математику на сервере -) - -if(WIN32) - target_link_libraries(Server PRIVATE ws2_32 mswsock) -endif() - -# Дополнительный макрос, чтобы Asio знал, что мы работаем без устаревших функций -target_compile_definitions(Server PRIVATE BOOST_ASIO_NO_DEPRECATED) \ No newline at end of file diff --git a/server/server.cpp b/server/server.cpp deleted file mode 100644 index db50b1a..0000000 --- a/server/server.cpp +++ /dev/null @@ -1,957 +0,0 @@ -#include "server.h" -#include -#include -#include -#include -#include -#include -#include - -std::vector split(const std::string& s, char delimiter) { - std::vector tokens; - std::string token; - std::istringstream tokenStream(s); - while (std::getline(tokenStream, token, delimiter)) { - tokens.push_back(token); - } - return tokens; -} - -Session::Session(Server& server, tcp::socket&& socket, int id) - : server_(server) - , ws_(std::move(socket)) - , id_(id) - , lastReceivedTime_(std::chrono::system_clock::now()) { -} - -bool Session::is_timed_out(std::chrono::system_clock::time_point now) const { - auto elapsed = std::chrono::duration_cast(now - lastReceivedTime_).count(); - return elapsed > PLAYER_TIMEOUT_MS; -} - -void Session::force_disconnect() { - beast::error_code ec; - ws_.next_layer().socket().close(ec); -} - -int Session::get_id() const { return id_; } - -bool Session::hasSpawnReserved() const { return hasReservedSpawn_; } -const Eigen::Vector3f& Session::reservedSpawn() const { return reservedSpawn_; } - -bool Session::fetchStateAtTime(std::chrono::system_clock::time_point targetTime, ClientState& outState) const { - if (timedClientStates.canFetchClientStateAtTime(targetTime)) { - outState = timedClientStates.fetchClientStateAtTime(targetTime); - return true; - } - return false; -} - -void Session::send_message(const std::string& msg) { - auto ss = std::make_shared(msg); - { - std::lock_guard lock(writeMutex_); - writeQueue_.push(ss); - } - doWrite(); -} - -void Session::run() { - { - std::lock_guard lock(server_.g_sessions_mutex); - server_.g_sessions.push_back(shared_from_this()); - } - - ws_.async_accept([self = shared_from_this()](beast::error_code ec) { - if (ec) return; - std::cout << "Client " << self->id_ << " connected\n"; - self->init(); - }); -} - -bool Session::IsMessageValid(const std::string& fullMessage) { -#ifdef ENABLE_NETWORK_CHECKSUM - size_t hashPos = fullMessage.find("#hash:"); - if (hashPos == std::string::npos) { - return false; // Хеша нет, хотя он ожидался - } - - std::string originalContent = fullMessage.substr(0, hashPos); - std::string receivedHashStr = fullMessage.substr(hashPos + 6); // 6 — длина "#hash:" - - // Вычисляем ожидаемый хеш от контента - size_t expectedHash = fnv1a_hash(originalContent + NET_SECRET); - - std::stringstream ss; - ss << std::hex << expectedHash; - - return ss.str() == receivedHashStr; -#else - return true; // В режиме отладки пропускаем всё -#endif -} - -void Session::sendBoxesToClient() { - std::lock_guard lock(server_.g_boxes_mutex); - - std::string boxMsg = "BOXES:"; - bool first = true; - - for (size_t i = 0; i < server_.g_serverBoxes.size(); ++i) { - const auto& box = server_.g_serverBoxes[i]; - - if (box.destroyed) continue; - - Eigen::Quaternionf q(box.rotation); - - if (!first) boxMsg += "|"; - first = false; - - boxMsg += std::to_string(i) + ":" + - std::to_string(box.position.x()) + ":" + - std::to_string(box.position.y()) + ":" + - std::to_string(box.position.z()) + ":" + - std::to_string(q.w()) + ":" + - std::to_string(q.x()) + ":" + - std::to_string(q.y()) + ":" + - std::to_string(q.z()) + ":" + - "0"; - } - - send_message(boxMsg); -} - - -void Session::init() -{ - auto timer = std::make_shared(ws_.get_executor()); - timer->expires_after(std::chrono::milliseconds(100)); - timer->async_wait([self = shared_from_this(), timer](const boost::system::error_code& ec) { - if (!ec) { - auto now_tp = std::chrono::system_clock::now(); - uint64_t now_ms = static_cast( - std::chrono::duration_cast(now_tp.time_since_epoch()).count()); - - self->sendBoxesToClient(); - - self->send_message("ID:" + std::to_string(self->id_) + ":" + std::to_string(now_ms)); - self->do_read(); - } - }); -} - -ClientState Session::get_latest_state(std::chrono::system_clock::time_point now) { - if (timedClientStates.timedStates.empty()) { - return {}; - } - ClientState latest = timedClientStates.timedStates.back(); - latest.apply_lag_compensation(now); - - return latest; -} - -void Session::doWrite() { - std::lock_guard lock(writeMutex_); - if (is_writing_ || writeQueue_.empty()) { - return; - } - - is_writing_ = true; - auto message = writeQueue_.front(); - - ws_.async_write(net::buffer(*message), - [self = shared_from_this(), message](beast::error_code ec, std::size_t) { - if (ec) { - std::cerr << "Write error: " << ec.message() << std::endl; - return; - } - { - std::lock_guard lock(self->writeMutex_); - self->writeQueue_.pop(); - self->is_writing_ = false; - } - self->doWrite(); - }); -} - -void Session::do_read() { - ws_.async_read(buffer_, [self = shared_from_this()](beast::error_code ec, std::size_t) { - if (ec) { - if (self->joined_) { - self->server_.broadcastToAllExceptId("PLAYER_LEFT:" + std::to_string(self->id_), self->id_); - std::cout << "Client " << self->id_ << " disconnected, broadcasting PLAYER_LEFT\n"; - } - std::lock_guard lock(self->server_.g_sessions_mutex); - self->server_.g_sessions.erase(std::remove_if(self->server_.g_sessions.begin(), self->server_.g_sessions.end(), - [self](const std::shared_ptr& session) { - return session.get() == self.get(); - }), self->server_.g_sessions.end()); - std::cout << "Client " << self->id_ << " removed from session list\n"; - return; - } - - std::string msg = beast::buffers_to_string(self->buffer_.data()); - self->process_message(msg); - - self->buffer_.consume(self->buffer_.size()); - self->do_read(); - }); -} - -void Session::process_message(const std::string& msg) { - if (!IsMessageValid(msg)) { - std::cout << "[Security] Invalid packet hash. Dropping message: " << msg << std::endl; - return; - } - lastReceivedTime_ = std::chrono::system_clock::now(); - std::string cleanMessage = msg.substr(0, msg.find("#hash:")); - - std::cout << "Received from player " << id_ << ": " << cleanMessage << std::endl; - auto parts = split(cleanMessage, ':'); - - if (parts.empty()) return; - - std::string type = parts[0]; - - if (type == "JOIN") { - std::string nick = "Player"; - int sType = 0; - if (parts.size() >= 2) nick = parts[1]; - if (parts.size() >= 3) { - try { sType = std::stoi(parts[2]); } - catch (...) { sType = 0; } - } - - this->nickname = nick; - this->shipType = sType; - this->joined_ = true; - - auto now_tp = std::chrono::system_clock::now(); - uint64_t now_ms = static_cast( - std::chrono::duration_cast(now_tp.time_since_epoch()).count()); - - Eigen::Vector3f spawnPos = server_.PickSafeSpawnPos(id_); - this->hasReservedSpawn_ = true; - this->reservedSpawn_ = spawnPos; - - ClientState st; - st.id = id_; - st.position = spawnPos; - st.rotation = Eigen::Matrix3f::Identity(); - st.currentAngularVelocity = Eigen::Vector3f::Zero(); - st.velocity = 0.0f; - st.selectedVelocity = 0; - st.discreteMag = 0.0f; - st.discreteAngle = -1; - st.lastUpdateServerTime = now_tp; - st.nickname = this->nickname; - st.shipType = this->shipType; - - timedClientStates.add_state(st); - - this->send_message( - "SPAWN:" + std::to_string(id_) + ":" + std::to_string(now_ms) + ":" + st.formPingMessageContent() - ); - - std::string eventMsg = - "EVENT:" + std::to_string(id_) + ":UPD:" + std::to_string(now_ms) + ":" + st.formPingMessageContent(); - - server_.broadcastToAllExceptId(eventMsg, id_); - - std::cout << "Server: Player " << id_ << " joined as [" << nick << "] shipType=" << sType << std::endl; - - std::string info = "PLAYERINFO:" + std::to_string(id_) + ":" + nick + ":" + std::to_string(sType); - server_.broadcastToAllExceptId(info, id_); - - { - std::lock_guard lock(server_.g_sessions_mutex); - for (auto& session : server_.g_sessions) { - if (session->get_id() == this->id_) continue; - if (!session->joined_) continue; - std::string otherInfo = "PLAYERINFO:" + std::to_string(session->get_id()) + ":" + session->nickname + ":" + std::to_string(session->shipType); - - this->send_message(otherInfo); - } - } - } - else if (type == "UPD") { - if (!joined_) { - std::cout << "Server: Ignoring UPD before JOIN from " << id_ << std::endl; - return; - } - { - std::lock_guard gd(server_.g_dead_mutex); - if (server_.g_dead_players.find(id_) != server_.g_dead_players.end()) { - std::cout << "Server: Ignoring UPD from dead player " << id_ << std::endl; - return; - } - } - - if (parts.size() < 16) return; - uint64_t clientTimestamp = std::stoull(parts[1]); - ClientState receivedState; - receivedState.id = id_; - std::chrono::system_clock::time_point uptime_timepoint{ - std::chrono::milliseconds(clientTimestamp) - }; - receivedState.lastUpdateServerTime = uptime_timepoint; - receivedState.handle_full_sync(parts, 2); - receivedState.nickname = this->nickname; - receivedState.shipType = this->shipType; - timedClientStates.add_state(receivedState); - - } - else if (type == "RESPAWN") { - { - std::lock_guard gd(server_.g_dead_mutex); - server_.g_dead_players.erase(id_); - } - - { - auto now_tp = std::chrono::system_clock::now(); - uint64_t now_ms = static_cast(std::chrono::duration_cast(now_tp.time_since_epoch()).count()); - - ClientState st; - st.id = id_; - - Eigen::Vector3f spawnPos = server_.PickSafeSpawnPos(id_); - st.position = spawnPos; - - this->hasReservedSpawn_ = true; - this->reservedSpawn_ = spawnPos; - - st.rotation = Eigen::Matrix3f::Identity(); - st.currentAngularVelocity = Eigen::Vector3f::Zero(); - st.velocity = 0.0f; - st.selectedVelocity = 0; - st.discreteMag = 0.0f; - st.discreteAngle = -1; - st.lastUpdateServerTime = now_tp; - st.nickname = this->nickname; - st.shipType = this->shipType; - - timedClientStates.add_state(st); - this->send_message( - "SPAWN:" + std::to_string(id_) + ":" + std::to_string(now_ms) + ":" + st.formPingMessageContent() - ); - std::string respawnMsg = "RESPAWN_ACK:" + std::to_string(id_); - server_.broadcastToAll(respawnMsg); - - std::string playerInfo = "PLAYERINFO:" + std::to_string(id_) + ":" + st.nickname + ":" + std::to_string(st.shipType); - server_.broadcastToAll(playerInfo); - - std::string eventMsg = "EVENT:" + std::to_string(id_) + ":UPD:" + std::to_string(now_ms) + ":" + st.formPingMessageContent(); - server_.broadcastToAll(eventMsg); - - std::cout << "Server: Player " << id_ << " respawned, broadcasted RESPAWN_ACK, PLAYERINFO and initial UPD\n"; - } - } - else if (parts[0] == "BOX_PICKUP") { - if (parts.size() < 2) return; - - if (this->shipType != 1) { - std::cout << "Server: Player " << id_ << " tried BOX_PICKUP but is not a cargo ship\n"; - return; - } - - int boxIdx = -1; - try { boxIdx = std::stoi(parts[1]); } catch (...) { return; } - - std::lock_guard bm(server_.g_boxes_mutex); - - if (boxIdx < 0 || boxIdx >= (int)server_.g_serverBoxes.size()) return; - if (server_.g_serverBoxes[boxIdx].destroyed) return; - - if (timedClientStates.timedStates.empty()) return; - const ClientState& playerState = timedClientStates.timedStates.back(); - - Eigen::Vector3f boxWorld = server_.g_serverBoxes[boxIdx].position + kWorldOffset; - float distSq = (playerState.position - boxWorld).squaredNorm(); - if (distSq > BOX_PICKUP_RADIUS * BOX_PICKUP_RADIUS) { - std::cout << "Server: Player " << id_ << " too far to pick up box " << boxIdx << "\n"; - return; - } - - server_.g_serverBoxes[boxIdx].destroyed = true; - - std::string pickedUpMsg = "BOX_PICKED_UP:" + std::to_string(boxIdx) + ":" + std::to_string(id_); - server_.broadcastToAll(pickedUpMsg); - - std::cout << "Server: Box " << boxIdx << " picked up by player " << id_ << "\n"; - - // Respawn box - { - static thread_local std::mt19937 rng{ std::random_device{}() }; - static thread_local std::uniform_real_distribution angleDist(0.f, static_cast(M_PI * 2.0)); - Eigen::Vector3f newPos = server_.PickSafeBoxPos(boxIdx); - Eigen::Vector3f axis = Eigen::Vector3f::Random().normalized(); - Eigen::Matrix3f newRot = Eigen::AngleAxisf(angleDist(rng), axis).toRotationMatrix(); - server_.g_serverBoxes[boxIdx].position = newPos; - server_.g_serverBoxes[boxIdx].rotation = newRot; - server_.g_serverBoxes[boxIdx].destroyed = false; - - Eigen::Quaternionf q(newRot); - std::string respawnMsg = "BOX_RESPAWN:" + - std::to_string(boxIdx) + ":" + - std::to_string(newPos.x()) + ":" + - std::to_string(newPos.y()) + ":" + - std::to_string(newPos.z()) + ":" + - std::to_string(q.w()) + ":" + - std::to_string(q.x()) + ":" + - std::to_string(q.y()) + ":" + - std::to_string(q.z()); - server_.broadcastToAll(respawnMsg); - std::cout << "Server: Box " << boxIdx << " respawned after pickup\n"; - } - } - else if (parts[0] == "FIRE") { - if (parts.size() < 10) return; - - uint64_t clientTime = std::stoull(parts[1]); - Eigen::Vector3f pos{ - std::stof(parts[2]), std::stof(parts[3]), std::stof(parts[4]) - }; - Eigen::Quaternionf dir( - std::stof(parts[5]), std::stof(parts[6]), std::stof(parts[7]), std::stof(parts[8]) - ); - float velocity = std::stof(parts[9]); - - std::string broadcast = "PROJECTILE:" + - std::to_string(id_) + ":" + - std::to_string(clientTime) + ":" + - std::to_string(pos.x()) + ":" + - std::to_string(pos.y()) + ":" + - std::to_string(pos.z()) + ":" + - std::to_string(dir.w()) + ":" + - std::to_string(dir.x()) + ":" + - std::to_string(dir.y()) + ":" + - std::to_string(dir.z()) + ":" + - std::to_string(velocity); - - - server_.broadcastToAllExceptId(broadcast, id_); - - server_.createProjectile(id_, pos, dir, velocity); - } -} - -Eigen::Vector3f Server::PickSafeBoxPos(int skipIdx) -{ - // Assumes g_boxes_mutex is already held by the caller - static thread_local std::mt19937 rng{ std::random_device{}() }; - std::uniform_real_distribution dist(-1000.f, 1000.f); - - for (int attempt = 0; attempt < 500; ++attempt) { - Eigen::Vector3f cand(dist(rng), dist(rng), dist(rng)); - bool safe = true; - for (int i = 0; i < (int)g_serverBoxes.size(); ++i) { - if (i == skipIdx) continue; - if (g_serverBoxes[i].destroyed) continue; - if ((cand - g_serverBoxes[i].position).squaredNorm() < 9.f) { - safe = false; - break; - } - } - if (safe) return cand; - } - return Eigen::Vector3f(dist(rng), dist(rng), dist(rng)); -} - -Eigen::Vector3f Server::PickSafeSpawnPos(int forPlayerId) -{ - static thread_local std::mt19937 rng{ std::random_device{}() }; - - std::scoped_lock lock(g_boxes_mutex, g_sessions_mutex, g_dead_mutex); - - auto isSafe = [&](const Eigen::Vector3f& pWorld) -> bool - { - for (const auto& box : g_serverBoxes) { - if (box.destroyed) continue; - - Eigen::Vector3f boxWorld = box.position + kWorldOffset; - float minDist = kShipRadius + box.collisionRadius + kSpawnBoxMargin; - - if ((pWorld - boxWorld).squaredNorm() < minDist * minDist) - return false; - } - - for (const auto& s : g_sessions) { - int pid = s->get_id(); - if (pid == forPlayerId) continue; - if (g_dead_players.count(pid)) continue; - - Eigen::Vector3f otherPos; - if (!s->timedClientStates.timedStates.empty()) { - otherPos = s->timedClientStates.timedStates.back().position; - } - else if (s->hasSpawnReserved()) { - otherPos = s->reservedSpawn(); - } - else { - continue; - } - - float minDist = (kShipRadius * 2.0f) + kSpawnShipMargin; - if ((pWorld - otherPos).squaredNorm() < minDist * minDist) - return false; - } - - return true; - }; - - const float radii[] = { 150.f, 250.f, 400.f, 650.f, 1000.f, 1600.f }; - - for (float r : radii) { - std::uniform_real_distribution dxy(-r, r); - std::uniform_real_distribution dz(-kSpawnZJitter, kSpawnZJitter); - - for (int attempt = 0; attempt < 250; ++attempt) { - Eigen::Vector3f cand( - dxy(rng), - dxy(rng), - kWorldZOffset + dz(rng) - ); - - if (isSafe(cand)) - return cand; - } - } - - int a = (forPlayerId % 10); - int b = ((forPlayerId / 10) % 10); - return Eigen::Vector3f(600.0f + a * 100.0f, -600.0f + b * 100.0f, kWorldZOffset); -} - -void Server::broadcastToAll(const std::string& message) { - std::lock_guard lock(g_sessions_mutex); - for (const auto& session : g_sessions) { - session->send_message(message); - } -} - -void Server::broadcastToAllExceptId(const std::string& message, int id) -{ - std::lock_guard lock(g_sessions_mutex); - for (auto& session : g_sessions) { - if (session->get_id() == id) continue; - session->send_message(message); - } -} - -void Server::createProjectile(int id, Eigen::Vector3f pos, Eigen::Quaternionf dir, float velocity) -{ - const std::vector localOffsets = { - Eigen::Vector3f(-1.5f, 0.9f - 6.f, 5.0f), - Eigen::Vector3f(1.5f, 0.9f - 6.f, 5.0f) - }; - - uint64_t now_ms = std::chrono::duration_cast(( - std::chrono::system_clock::now().time_since_epoch())).count(); - - std::lock_guard pl(g_projectiles_mutex); - for (int i = 0; i < localOffsets.size(); ++i) { - Projectile pr; - pr.shooterId = id; - pr.spawnMs = now_ms; - Eigen::Vector3f shotPos = pos + dir.toRotationMatrix() * localOffsets[i]; - pr.pos = shotPos; - Eigen::Vector3f localForward(0.0f, 0.0f, -1.0f); - Eigen::Vector3f worldForward = dir.toRotationMatrix() * localForward; - float len = worldForward.norm(); - if (len > 1e-6f) worldForward /= len; - pr.vel = worldForward * velocity; - pr.lifeMs = 15000.0f; - g_projectiles.push_back(pr); - - std::cout << "Server: Created projectile from player " << id - << " at pos (" << shotPos.x() << ", " << shotPos.y() << ", " << shotPos.z() - << ") vel (" << pr.vel.x() << ", " << pr.vel.y() << ", " << pr.vel.z() << ")" << std::endl; - } -} - -void Server::update_world() { - - static auto last_snapshot_time = std::chrono::system_clock::now(); - - auto now = std::chrono::system_clock::now(); - uint64_t now_ms = static_cast( - std::chrono::duration_cast(now.time_since_epoch()).count()); - - // --- Detect and force-disconnect timed-out players --- - { - std::vector> timedOut; - { - std::lock_guard lock(g_sessions_mutex); - for (auto& session : g_sessions) { - if (session->is_timed_out(now)) { - timedOut.push_back(session); - } - } - } - for (auto& session : timedOut) { - std::cout << "Server: Player " << session->get_id() - << " timed out after " << PLAYER_TIMEOUT_MS << "ms, forcing disconnect\n"; - session->force_disconnect(); - } - } - - { - std::lock_guard lock(g_sessions_mutex); - for (auto& sender : g_sessions) { - if (sender->timedClientStates.timedStates.empty()) continue; - - const ClientState& st = sender->timedClientStates.timedStates.back(); - uint64_t stateTime = static_cast( - std::chrono::duration_cast( - st.lastUpdateServerTime.time_since_epoch()).count()); - - std::string event_msg = "EVENT:" + std::to_string(sender->get_id()) + - ":UPD:" + std::to_string(stateTime) + ":" + st.formPingMessageContent(); - - for (auto& receiver : g_sessions) { - if (receiver->get_id() != sender->get_id()) { - receiver->send_message(event_msg); - } - } - } - } - - // --- Tick: projectile movement and hit detection --- - const float dt = 50.0f / 1000.0f; - std::vector deathEvents; - - { - std::lock_guard pl(g_projectiles_mutex); - std::vector indicesToRemove; - - for (size_t i = 0; i < g_projectiles.size(); ++i) { - auto& pr = g_projectiles[i]; - - pr.pos += pr.vel * dt; - - if (now_ms > pr.spawnMs + static_cast(pr.lifeMs)) { - indicesToRemove.push_back(static_cast(i)); - continue; - } - - bool hitDetected = false; - - { - std::lock_guard lm(g_sessions_mutex); - std::lock_guard gd(g_dead_mutex); - - for (auto& session : g_sessions) { - int targetId = session->get_id(); - - if (targetId == pr.shooterId) continue; - if (g_dead_players.find(targetId) != g_dead_players.end()) continue; - - ClientState targetState; - if (!session->fetchStateAtTime(now, targetState)) continue; - - Eigen::Vector3f diff = pr.pos - targetState.position; - float combinedRadius = shipCollisionRadius + projectileHitRadius; - - if (diff.squaredNorm() <= combinedRadius * combinedRadius) { - DeathInfo death; - death.targetId = targetId; - death.serverTime = now_ms; - death.position = pr.pos; - death.killerId = pr.shooterId; - - deathEvents.push_back(death); - g_dead_players.insert(targetId); - indicesToRemove.push_back(static_cast(i)); - hitDetected = true; - - std::cout << "Server: *** HIT DETECTED! ***" << std::endl; - std::cout << "Server: Projectile at (" - << pr.pos.x() << ", " << pr.pos.y() << ", " << pr.pos.z() - << ") hit player " << targetId << std::endl; - break; - } - } - } - - if (hitDetected) continue; - } - - if (!indicesToRemove.empty()) { - std::sort(indicesToRemove.rbegin(), indicesToRemove.rend()); - for (int idx : indicesToRemove) { - if (idx >= 0 && idx < (int)g_projectiles.size()) { - g_projectiles.erase(g_projectiles.begin() + idx); - } - } - } - } - - - - std::vector boxesToRespawn; - - // --- Tick: box-projectile collisions --- - { - std::lock_guard bm(g_boxes_mutex); - - - std::vector> boxProjectileCollisions; - - for (size_t bi = 0; bi < g_serverBoxes.size(); ++bi) { - if (g_serverBoxes[bi].destroyed) continue; - - Eigen::Vector3f boxWorld = g_serverBoxes[bi].position + Eigen::Vector3f(0.0f, 0.0f, 45000.0f); - - for (size_t pi = 0; pi < g_projectiles.size(); ++pi) { - const auto& pr = g_projectiles[pi]; - Eigen::Vector3f diff = pr.pos - boxWorld; - float thresh = boxCollisionRadius + projectileHitRadius; - - if (diff.squaredNorm() <= thresh * thresh) { - boxProjectileCollisions.push_back({ bi, pi }); - } - } - } - - for (const auto& [boxIdx, projIdx] : boxProjectileCollisions) { - if (g_serverBoxes[boxIdx].destroyed) continue; - g_serverBoxes[boxIdx].destroyed = true; - - Eigen::Vector3f boxWorld = g_serverBoxes[boxIdx].position + Eigen::Vector3f(0.0f, 0.0f, 45000.0f); - - BoxDestroyedInfo destruction; - destruction.boxIndex = static_cast(boxIdx); - destruction.serverTime = now_ms; - destruction.position = boxWorld; - destruction.destroyedBy = g_projectiles[projIdx].shooterId; - - { - std::lock_guard dm(g_boxDestructions_mutex); - g_boxDestructions.push_back(destruction); - } - - boxesToRespawn.push_back(static_cast(boxIdx)); - - std::cout << "Server: Box " << boxIdx << " destroyed by projectile from player " - << g_projectiles[projIdx].shooterId << std::endl; - } - } - - // --- Tick: box-ship collisions --- - { - std::lock_guard bm(g_boxes_mutex); - std::lock_guard lm(g_sessions_mutex); - - for (size_t bi = 0; bi < g_serverBoxes.size(); ++bi) { - if (g_serverBoxes[bi].destroyed) continue; - - Eigen::Vector3f boxWorld = g_serverBoxes[bi].position + Eigen::Vector3f(0.0f, 0.0f, 45000.0f); - - for (auto& session : g_sessions) { - { - std::lock_guard gd(g_dead_mutex); - if (g_dead_players.find(session->get_id()) != g_dead_players.end()) { - continue; - } - } - - ClientState shipState; - if (!session->fetchStateAtTime(now, shipState)) continue; - - Eigen::Vector3f diff = shipState.position - boxWorld; - float thresh = shipCollisionRadius + boxCollisionRadius; - - if (diff.squaredNorm() <= thresh * thresh) { - g_serverBoxes[bi].destroyed = true; - - BoxDestroyedInfo destruction; - destruction.boxIndex = static_cast(bi); - destruction.serverTime = now_ms; - destruction.position = boxWorld; - destruction.destroyedBy = session->get_id(); - - { - std::lock_guard dm(g_boxDestructions_mutex); - g_boxDestructions.push_back(destruction); - } - - boxesToRespawn.push_back(static_cast(bi)); - - std::cout << "Server: Box " << bi << " destroyed by ship collision with player " - << session->get_id() << std::endl; - break; - } - } - } - } - - // --- Broadcast deaths --- - for (const auto& death : deathEvents) { - std::string deadMsg = "DEAD:" + - std::to_string(death.serverTime) + ":" + - std::to_string(death.targetId) + ":" + - std::to_string(death.position.x()) + ":" + - std::to_string(death.position.y()) + ":" + - std::to_string(death.position.z()) + ":" + - std::to_string(death.killerId); - - broadcastToAll(deadMsg); - - std::cout << "Server: Sent DEAD event - Player " << death.targetId - << " killed by " << death.killerId << std::endl; - } - - // --- Broadcast box destructions --- - { - std::lock_guard dm(g_boxDestructions_mutex); - for (const auto& destruction : g_boxDestructions) { - std::string boxMsg = "BOX_DESTROYED:" + - std::to_string(destruction.boxIndex) + ":" + - std::to_string(destruction.serverTime) + ":" + - std::to_string(destruction.position.x()) + ":" + - std::to_string(destruction.position.y()) + ":" + - std::to_string(destruction.position.z()) + ":" + - std::to_string(destruction.destroyedBy); - - broadcastToAll(boxMsg); - std::cout << "Server: Broadcasted BOX_DESTROYED for box " << destruction.boxIndex << std::endl; - } - g_boxDestructions.clear(); - } - - // --- Respawn destroyed boxes --- - if (!boxesToRespawn.empty()) { - static thread_local std::mt19937 rng{ std::random_device{}() }; - static thread_local std::uniform_real_distribution angleDist(0.f, static_cast(M_PI * 2.0)); - std::vector respawnMsgs; - { - std::lock_guard bm(g_boxes_mutex); - for (int idx : boxesToRespawn) { - if (idx < 0 || idx >= (int)g_serverBoxes.size()) continue; - Eigen::Vector3f newPos = PickSafeBoxPos(idx); - Eigen::Vector3f axis = Eigen::Vector3f::Random().normalized(); - Eigen::Matrix3f newRot = Eigen::AngleAxisf(angleDist(rng), axis).toRotationMatrix(); - g_serverBoxes[idx].position = newPos; - g_serverBoxes[idx].rotation = newRot; - g_serverBoxes[idx].destroyed = false; - - Eigen::Quaternionf q(newRot); - std::string respawnMsg = "BOX_RESPAWN:" + - std::to_string(idx) + ":" + - std::to_string(newPos.x()) + ":" + - std::to_string(newPos.y()) + ":" + - std::to_string(newPos.z()) + ":" + - std::to_string(q.w()) + ":" + - std::to_string(q.x()) + ":" + - std::to_string(q.y()) + ":" + - std::to_string(q.z()); - respawnMsgs.push_back(respawnMsg); - std::cout << "Server: Box " << idx << " respawned" << std::endl; - } - } - for (const auto& msg : respawnMsgs) { - broadcastToAll(msg); - } - } - - // --- Schedule next tick in 50ms --- - timer.expires_after(std::chrono::milliseconds(50)); - timer.async_wait([this](const boost::system::error_code& ec) { - if (ec) return; - update_world(); - }); -} - -std::vector Server::generateServerBoxes(int count) { - std::vector boxes; - std::random_device rd; - std::mt19937 gen(rd()); - - const float MIN_COORD = -1000.0f; - const float MAX_COORD = 1000.0f; - const float MIN_DISTANCE = 3.0f; - const float MIN_DISTANCE_SQUARED = MIN_DISTANCE * MIN_DISTANCE; - const int MAX_ATTEMPTS = 1000; - - std::uniform_real_distribution<> posDistrib(MIN_COORD, MAX_COORD); - std::uniform_real_distribution<> angleDistrib(0.0, M_PI * 2.0); - - for (int i = 0; i < count; i++) { - bool accepted = false; - int attempts = 0; - - while (!accepted && attempts < MAX_ATTEMPTS) { - ServerBox box; - box.position = Eigen::Vector3f( - (float)posDistrib(gen), - (float)posDistrib(gen), - (float)posDistrib(gen) - ); - - accepted = true; - for (const auto& existingBox : boxes) { - Eigen::Vector3f diff = box.position - existingBox.position; - if (diff.squaredNorm() < MIN_DISTANCE_SQUARED) { - accepted = false; - break; - } - } - - if (accepted) { - float randomAngle = (float)angleDistrib(gen); - Eigen::Vector3f axis = Eigen::Vector3f::Random().normalized(); - box.rotation = Eigen::AngleAxisf(randomAngle, axis).toRotationMatrix(); - boxes.push_back(box); - } - - attempts++; - } - } - - return boxes; -} - -Server::Server(tcp::acceptor& acceptor, net::io_context& ioc) - : acceptor_(acceptor) - , ioc_(ioc) - , timer(ioc_) -{ -} - -void Server::init() -{ - std::lock_guard lock(g_boxes_mutex); - g_serverBoxes = generateServerBoxes(50); - std::cout << "Generated " << g_serverBoxes.size() << " boxes on server\n"; -} - -void Server::accept() -{ - acceptor_.async_accept([&](beast::error_code ec, tcp::socket socket) { - if (!ec) { - std::make_shared(*this, std::move(socket), next_id++)->run(); - } - accept(); - }); -} - -int main() { - try { - net::io_context ioc; - tcp::acceptor acceptor{ ioc, {tcp::v4(), 8081} }; - - Server server(acceptor, ioc); - - server.init(); - server.accept(); - - std::cout << "Server started on port 8081...\n"; - - server.update_world(); - ioc.run(); - } - catch (std::exception const& e) { - std::cerr << "Error: " << e.what() << std::endl; - } - return 0; -} \ No newline at end of file diff --git a/server/server.h b/server/server.h deleted file mode 100644 index a53ee50..0000000 --- a/server/server.h +++ /dev/null @@ -1,142 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../src/network/ClientState.h" -#define _USE_MATH_DEFINES -#include - -namespace beast = boost::beast; -namespace http = beast::http; -namespace websocket = beast::websocket; -namespace net = boost::asio; -using tcp = net::ip::tcp; -static constexpr float kWorldZOffset = 45000.0f; -static const Eigen::Vector3f kWorldOffset(0.0f, 0.0f, kWorldZOffset); - -static constexpr float kShipRadius = 15.0f; -static constexpr float kSpawnShipMargin = 25.0f; -static constexpr float kSpawnBoxMargin = 15.0f; -static constexpr float kSpawnZJitter = 60.0f; - -std::vector split(const std::string& s, char delimiter); - -struct DeathInfo { - int targetId = -1; - uint64_t serverTime = 0; - Eigen::Vector3f position = Eigen::Vector3f::Zero(); - int killerId = -1; -}; - - -struct ServerBox { - Eigen::Vector3f position; - Eigen::Matrix3f rotation; - float collisionRadius = 2.0f; - bool destroyed = false; -}; - -struct Projectile { - int shooterId = -1; - uint64_t spawnMs = 0; - Eigen::Vector3f pos; - Eigen::Vector3f vel; - float lifeMs = PROJECTILE_LIFE; -}; - -struct BoxDestroyedInfo { - int boxIndex = -1; - uint64_t serverTime = 0; - Eigen::Vector3f position = Eigen::Vector3f::Zero(); - int destroyedBy = -1; -}; - -class Server; - -class Session : public std::enable_shared_from_this { - Server& server_; - websocket::stream ws_; - beast::flat_buffer buffer_; - int id_; - bool is_writing_ = false; - std::queue> writeQueue_; - std::mutex writeMutex_; - - -public: - ClientStateInterval timedClientStates; - bool joined_ = false; - std::chrono::system_clock::time_point lastReceivedTime_; - - bool hasReservedSpawn_ = false; - Eigen::Vector3f reservedSpawn_ = Eigen::Vector3f(0.0f, 0.0f, kWorldZOffset); - - std::string nickname = "Player"; - int shipType = 0; - - Session(Server& server, tcp::socket&& socket, int id); - int get_id() const; - bool hasSpawnReserved() const; - const Eigen::Vector3f& reservedSpawn() const; - bool fetchStateAtTime(std::chrono::system_clock::time_point targetTime, ClientState& outState) const; - void send_message(const std::string& msg); - void run(); - bool IsMessageValid(const std::string& fullMessage); - bool is_timed_out(std::chrono::system_clock::time_point now) const; - void force_disconnect(); - -private: - void sendBoxesToClient(); -public: - void init(); - ClientState get_latest_state(std::chrono::system_clock::time_point now); - void doWrite(); -private: - - void do_read(); - void process_message(const std::string& msg); -}; - -class Server -{ -public: - tcp::acceptor& acceptor_; - net::io_context& ioc_; - net::steady_timer timer; - std::vector g_boxDestructions; - std::mutex g_boxDestructions_mutex; - - std::vector g_serverBoxes; - std::mutex g_boxes_mutex; - - std::vector> g_sessions; - std::mutex g_sessions_mutex; - - std::vector g_projectiles; - std::mutex g_projectiles_mutex; - - std::unordered_set g_dead_players; - std::mutex g_dead_mutex; - - int next_id = 1000; - - std::vector generateServerBoxes(int count); -public: - Server(tcp::acceptor& acceptor, net::io_context& ioc); - - void broadcastToAll(const std::string& message); - void broadcastToAllExceptId(const std::string& message, int id); - void createProjectile(int id, Eigen::Vector3f pos, Eigen::Quaternionf dir, float velocity); - void update_world(); - Eigen::Vector3f PickSafeSpawnPos(int forPlayerId); - // Caller must hold g_boxes_mutex - Eigen::Vector3f PickSafeBoxPos(int skipIdx); - void init(); - void accept(); -}; diff --git a/src/AnimatedModel.h b/src/AnimatedModel.h index c11937a..4a57767 100644 --- a/src/AnimatedModel.h +++ b/src/AnimatedModel.h @@ -4,7 +4,7 @@ #include "render/Renderer.h" #include "render/TextureManager.h" -namespace ZL +namespace FRG { struct MeshGroup diff --git a/src/AudioPlayerAsync.cpp b/src/AudioPlayerAsync.cpp index 5a265e4..d865de4 100644 --- a/src/AudioPlayerAsync.cpp +++ b/src/AudioPlayerAsync.cpp @@ -37,7 +37,7 @@ bool AudioPlayerAsync::init() { Mix_AllocateChannels(16); initialized = true; - ZL::logger() << "AudioPlayerAsync initialized with SDL2_mixer" << std::endl; + FRG::logger() << "AudioPlayerAsync initialized with SDL2_mixer" << std::endl; return true; } @@ -61,7 +61,7 @@ void AudioPlayerAsync::shutdown() { Mix_CloseAudio(); SDL_QuitSubSystem(SDL_INIT_AUDIO); initialized = false; - ZL::logger() << "AudioPlayerAsync shutdown" << std::endl; + FRG::logger() << "AudioPlayerAsync shutdown" << std::endl; } void AudioPlayerAsync::playSoundAsync(const std::string& filePath, int loops, int channel) { diff --git a/src/BoneAnimatedModelNew.cpp b/src/BoneAnimatedModelNew.cpp index 473fff1..958af73 100644 --- a/src/BoneAnimatedModelNew.cpp +++ b/src/BoneAnimatedModelNew.cpp @@ -6,7 +6,7 @@ #include #include -namespace ZL +namespace FRG { #ifdef EMSCRIPTEN using std::min; diff --git a/src/BoneAnimatedModelNew.h b/src/BoneAnimatedModelNew.h index 5f5026a..c4b47f9 100644 --- a/src/BoneAnimatedModelNew.h +++ b/src/BoneAnimatedModelNew.h @@ -3,7 +3,7 @@ #include -namespace ZL +namespace FRG { constexpr int MAX_BONE_COUNT = 6; constexpr int MAX_GPU_BONES = 64; diff --git a/src/Character.cpp b/src/Character.cpp index e870430..49c4ee3 100644 --- a/src/Character.cpp +++ b/src/Character.cpp @@ -10,7 +10,7 @@ #include "utils/Utils.h" #include "TextModel.h" -namespace ZL { +namespace FRG { const float ATTACK_COOLDOWN_TIME = 1.6f; extern float x; @@ -193,7 +193,7 @@ void Character::forceReplan() { state.onArrivedCallbackName.clear(); } -void Character::setTexture(std::shared_ptr texture) { +void Character::setTexture(std::shared_ptr texture) { for (auto& animEntry : animations) { for (const auto& name : animEntry.second.model.meshNamesOrdered) { meshTextures[name] = texture; @@ -1354,4 +1354,4 @@ void Character::drawHealthBar(Renderer& renderer, renderer.shaderManager.PopShader(); } -} // namespace ZL +} // namespace FRG diff --git a/src/Character.h b/src/Character.h index 711a7e3..39c0af7 100644 --- a/src/Character.h +++ b/src/Character.h @@ -14,7 +14,7 @@ #include "dialogue/TranslationDatabase.h" #include "AudioPlayerAsync.h" -namespace ZL { +namespace FRG { class TextRenderer; @@ -40,7 +40,7 @@ public: // Assigns a texture to a specific mesh by name. void setTexture(const std::string& meshName, std::shared_ptr texture); // Assigns one texture to every mesh in every loaded animation. Call AFTER loading animations. - void setTexture(std::shared_ptr texture); + void setTexture(std::shared_ptr texture); // Creates a fully-loaded Character from a CharacterState (including its creationInfo). // Loads all animations, textures, and weapon mesh/texture from the paths stored in creationInfo. @@ -158,4 +158,4 @@ private: const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const float* ambientColor, const float* fogColor); }; -} // namespace ZL +} // namespace FRG diff --git a/src/CharacterState.cpp b/src/CharacterState.cpp index 6c88923..a5b505a 100644 --- a/src/CharacterState.cpp +++ b/src/CharacterState.cpp @@ -1,6 +1,6 @@ #include "CharacterState.h" -namespace ZL { +namespace FRG { bool CharacterState::isMoving() const { Eigen::Vector3f toTarget = walkTarget - position; @@ -92,4 +92,4 @@ void CharacterState::load(const nlohmann::json& in) onArrivedCallbackName = in.value("onArrivedCallbackName", std::string()); } -} // namespace ZL +} // namespace FRG diff --git a/src/CharacterState.h b/src/CharacterState.h index db25e3c..ffb55d5 100644 --- a/src/CharacterState.h +++ b/src/CharacterState.h @@ -8,7 +8,7 @@ #include "external/nlohmann/json.hpp" #include "ISaveable.h" -namespace ZL { +namespace FRG { constexpr float VISIBLE_RANGE = 6.f; @@ -141,4 +141,4 @@ public: void load(const nlohmann::json& in) override; }; -} // namespace ZL +} // namespace FRG diff --git a/src/Environment.cpp b/src/Environment.cpp index f01df3c..4bdf8e1 100644 --- a/src/Environment.cpp +++ b/src/Environment.cpp @@ -13,7 +13,7 @@ #include #endif -namespace ZL { +namespace FRG { @@ -92,4 +92,4 @@ void Environment::setFullscreen(bool enable) { #endif } -} // namespace ZL +} // namespace FRG diff --git a/src/Environment.h b/src/Environment.h index 3594aad..816449a 100644 --- a/src/Environment.h +++ b/src/Environment.h @@ -7,7 +7,7 @@ #endif #include -namespace ZL { +namespace FRG { #ifdef EMSCRIPTEN @@ -64,4 +64,4 @@ public: static void computeProjectionDimensions(); }; -} // namespace ZL +} // namespace FRG diff --git a/src/Game.cpp b/src/Game.cpp index 20919cc..79cc94c 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -24,7 +24,7 @@ #include "GameConstants.h" -namespace ZL +namespace FRG { static const float zoomMin = 6.0f; static const float zoomMax = 20.0f; @@ -85,8 +85,8 @@ namespace ZL Environment::height = Environment::CONST_DEFAULT_HEIGHT; Environment::computeProjectionDimensions(); - ZL::BindOpenGlFunctions(); - ZL::CheckGlError(__FILE__, __LINE__); + FRG::BindOpenGlFunctions(); + FRG::CheckGlError(__FILE__, __LINE__); renderer.InitOpenGL(); #if defined(EMSCRIPTEN) @@ -152,7 +152,7 @@ namespace ZL // (e.g. resources/start_dorm.lua) start a dialogue as soon as they're // loaded, so the language needs to be known before that first load. loadSteps.push([this]() { - ZL::loadLanguageSetting(); + FRG::loadLanguageSetting(); }); loadSteps.push([this]() { @@ -165,7 +165,7 @@ namespace ZL renderer.shaderManager.AddShaderFromFiles("spark", "resources/shaders/spark.vertex", "resources/shaders/spark_web.fragment", CONST_ZIP_FILE); renderer.shaderManager.AddShaderFromFiles("skinning", "resources/shaders/skinning.vertex", "resources/shaders/default_web.fragment", CONST_ZIP_FILE); renderer.shaderManager.AddShaderFromFiles("fog", "resources/shaders/fog.vertex", "resources/shaders/fog_web.fragment", CONST_ZIP_FILE); - renderer.shaderManager.AddShaderFromFiles("fog_skinning", "resources/shaders/fog_skinning.vertex", "resources/shaders/fog_web.fragment", CONST_ZIP_FILE); + renderer.shaderManager.AddShaderFromFiles("fog_skinning", "resources/shaders/fog_skinning_web.vertex", "resources/shaders/fog_web.fragment", CONST_ZIP_FILE); renderer.shaderManager.AddShaderFromFiles("darklands_fog", "resources/shaders/darklands_fog.vertex", "resources/shaders/darklands_fog_web.fragment", CONST_ZIP_FILE); renderer.shaderManager.AddShaderFromFiles("darklands_fog_skinning", "resources/shaders/darklands_fog_skinning.vertex", "resources/shaders/darklands_fog_web.fragment", CONST_ZIP_FILE); renderer.shaderManager.AddShaderFromFiles("darklands_flash", "resources/shaders/default.vertex", "resources/shaders/darklands_flash_web.fragment", CONST_ZIP_FILE); @@ -173,15 +173,15 @@ namespace ZL renderer.shaderManager.AddShaderFromFiles("cutsceneBlack", "resources/shaders/default.vertex", "resources/shaders/cutscene_black_web.fragment", CONST_ZIP_FILE); renderer.shaderManager.AddShaderFromFiles("shadow_depth", "resources/shaders/shadow_depth.vertex", "resources/shaders/shadow_depth_web.fragment", CONST_ZIP_FILE); renderer.shaderManager.AddShaderFromFiles("shadow_depth_skinning", "resources/shaders/shadow_depth_skinning.vertex", "resources/shaders/shadow_depth_web.fragment", CONST_ZIP_FILE); - renderer.shaderManager.AddShaderFromFiles("default_shadow", "resources/shaders/default_shadow.vertex", "resources/shaders/default_shadow_web.fragment", CONST_ZIP_FILE); - renderer.shaderManager.AddShaderFromFiles("skinning_shadow", "resources/shaders/skinning_shadow.vertex", "resources/shaders/default_shadow_web.fragment", CONST_ZIP_FILE); - renderer.shaderManager.AddShaderFromFiles("fog_shadow", "resources/shaders/fog_shadow.vertex", "resources/shaders/fog_shadow_web.fragment", CONST_ZIP_FILE); - renderer.shaderManager.AddShaderFromFiles("fog_skinning_shadow", "resources/shaders/fog_skinning_shadow.vertex", "resources/shaders/fog_shadow_web.fragment", CONST_ZIP_FILE); - renderer.shaderManager.AddShaderFromFiles("night_fog", "resources/shaders/night_fog.vertex", "resources/shaders/night_fog_web.fragment", CONST_ZIP_FILE); - renderer.shaderManager.AddShaderFromFiles("night_fog_skinning", "resources/shaders/night_fog_skinning.vertex", "resources/shaders/night_fog_web.fragment", CONST_ZIP_FILE); - renderer.shaderManager.AddShaderFromFiles("night_fog_shadow", "resources/shaders/night_fog_shadow.vertex", "resources/shaders/night_fog_shadow_web.fragment", CONST_ZIP_FILE); - renderer.shaderManager.AddShaderFromFiles("night_fog_skinning_shadow", "resources/shaders/night_fog_skinning_shadow.vertex", "resources/shaders/night_fog_shadow_web.fragment", CONST_ZIP_FILE); -#elif defined(__linux__) + renderer.shaderManager.AddShaderFromFiles("default_shadow", "resources/shaders/default_shadow_web.vertex", "resources/shaders/default_shadow_web.fragment", CONST_ZIP_FILE); + renderer.shaderManager.AddShaderFromFiles("skinning_shadow", "resources/shaders/skinning_shadow_web.vertex", "resources/shaders/default_shadow_web.fragment", CONST_ZIP_FILE); + renderer.shaderManager.AddShaderFromFiles("fog_shadow", "resources/shaders/fog_shadow_web.vertex", "resources/shaders/fog_shadow_web.fragment", CONST_ZIP_FILE); + renderer.shaderManager.AddShaderFromFiles("fog_skinning_shadow", "resources/shaders/fog_skinning_shadow_web.vertex", "resources/shaders/fog_shadow_web.fragment", CONST_ZIP_FILE); + renderer.shaderManager.AddShaderFromFiles("night_fog", "resources/shaders/night_fog_web.vertex", "resources/shaders/night_fog_web.fragment", CONST_ZIP_FILE); + renderer.shaderManager.AddShaderFromFiles("night_fog_skinning", "resources/shaders/night_fog_skinning_web.vertex", "resources/shaders/night_fog_web.fragment", CONST_ZIP_FILE); + renderer.shaderManager.AddShaderFromFiles("night_fog_shadow", "resources/shaders/night_fog_shadow_web.vertex", "resources/shaders/night_fog_shadow_web.fragment", CONST_ZIP_FILE); + renderer.shaderManager.AddShaderFromFiles("night_fog_skinning_shadow", "resources/shaders/night_fog_skinning_shadow_web.vertex", "resources/shaders/night_fog_shadow_web.fragment", CONST_ZIP_FILE); +/*#elif defined(__linux__) renderer.shaderManager.AddShaderFromFiles("env_sky", "resources/shaders/env_sky.vertex", "resources/shaders/env_sky_desktop.fragment", CONST_ZIP_FILE); renderer.shaderManager.AddShaderFromFiles("defaultAtmosphere", "resources/shaders/defaultAtmosphere.vertex", "resources/shaders/defaultAtmosphere_desktop.fragment", CONST_ZIP_FILE); renderer.shaderManager.AddShaderFromFiles("planetBake", "resources/shaders/planet_bake.vertex", "resources/shaders/planet_bake_desktop.fragment", CONST_ZIP_FILE); @@ -207,7 +207,7 @@ namespace ZL renderer.shaderManager.AddShaderFromFiles("night_fog_shadow", "resources/shaders/night_fog_shadow.vertex", "resources/shaders/night_fog_shadow_desktop.fragment", CONST_ZIP_FILE); renderer.shaderManager.AddShaderFromFiles("night_fog_skinning_shadow", "resources/shaders/night_fog_skinning_shadow.vertex", "resources/shaders/night_fog_shadow_desktop.fragment", CONST_ZIP_FILE); - + */ #else renderer.shaderManager.AddShaderFromFiles("env_sky", "resources/shaders/env_sky.vertex", "resources/shaders/env_sky_desktop.fragment", CONST_ZIP_FILE); renderer.shaderManager.AddShaderFromFiles("defaultAtmosphere", "resources/shaders/defaultAtmosphere.vertex", "resources/shaders/defaultAtmosphere_desktop.fragment", CONST_ZIP_FILE); @@ -444,7 +444,7 @@ namespace ZL void Game::performResetToInitialState() { const std::string path = "resources/config/start_state.json"; - const std::string content = ZL::readTextFile(path); + const std::string content = FRG::readTextFile(path); if (!content.empty()) { try { nlohmann::json root = nlohmann::json::parse(content); @@ -1013,11 +1013,11 @@ namespace ZL if (showLoadingProgressBar == false) // Loading language screen { - if (ZL::g_currentLanguage == ZL::Language::English) + if (FRG::g_currentLanguage == FRG::Language::English) { glBindTexture(GL_TEXTURE_2D, menuManager.languageLoadingEn->getTexID()); } - else if (ZL::g_currentLanguage == ZL::Language::Russian) + else if (FRG::g_currentLanguage == FRG::Language::Russian) { glBindTexture(GL_TEXTURE_2D, menuManager.languageLoadingRu->getTexID()); } @@ -1156,7 +1156,7 @@ namespace ZL } void Game::render() { - ZL::CheckGlError(__FILE__, __LINE__); + FRG::CheckGlError(__FILE__, __LINE__); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -1164,7 +1164,7 @@ namespace ZL drawScene(); processTickCount(); - SDL_GL_SwapWindow(ZL::Environment::window); + SDL_GL_SwapWindow(FRG::Environment::window); } void Game::update() { @@ -1178,7 +1178,7 @@ namespace ZL if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED) { const bool wasPortrait = Environment::width < Environment::height; - //ZL::logger() << "Window resized" << std::endl; + //FRG::logger() << "Window resized" << std::endl; if (Environment::isHighDPIEnabled) { // Если High DPI включен, запрашиваем реальное физическое разрешение буфера int drawW, drawH; @@ -1188,8 +1188,8 @@ namespace ZL } else { // Если High DPI выключен, используем логические размеры из события - Environment::width = event.window.data1 / ZL::Environment::customDpiScale; - Environment::height = event.window.data2 / ZL::Environment::customDpiScale; + Environment::width = event.window.data1 / FRG::Environment::customDpiScale; + Environment::height = event.window.data2 / FRG::Environment::customDpiScale; } Environment::computeProjectionDimensions(); @@ -1260,10 +1260,10 @@ namespace ZL int my = static_cast((float)eventY / Environment::height * Environment::projectionHeight); if (event.type == SDL_MOUSEBUTTONDOWN) { - onPointerDown(ZL::UiManager::MOUSE_FINGER_ID, eventX, eventY, mx, my); + onPointerDown(FRG::UiManager::MOUSE_FINGER_ID, eventX, eventY, mx, my); } else { - onPointerUp(ZL::UiManager::MOUSE_FINGER_ID, eventX, eventY, mx, my); + onPointerUp(FRG::UiManager::MOUSE_FINGER_ID, eventX, eventY, mx, my); } } else if (event.button.button == SDL_BUTTON_RIGHT @@ -1278,7 +1278,7 @@ namespace ZL int eventY = event.motion.y; int mx = static_cast((float)eventX / Environment::width * Environment::projectionWidth); int my = static_cast((float)eventY / Environment::height * Environment::projectionHeight); - onPointerMotion(ZL::UiManager::MOUSE_FINGER_ID, eventX, eventY, mx, my); + onPointerMotion(FRG::UiManager::MOUSE_FINGER_ID, eventX, eventY, mx, my); } if (event.type == SDL_MOUSEWHEEL) { @@ -1851,7 +1851,7 @@ namespace ZL SaveSlotInfo Game::readSlotInfo(int slot) const { std::string path = "save_slot" + std::to_string(slot) + ".json"; - std::string content = ZL::readSavedTextFile(path); + std::string content = FRG::readSavedTextFile(path); if (content.empty()) return {}; try { nlohmann::json root = nlohmann::json::parse(content); @@ -1883,7 +1883,7 @@ namespace ZL void Game::loadGame(int slot) { std::string path = "save_slot" + std::to_string(slot) + ".json"; - std::string content = ZL::readSavedTextFile(path); + std::string content = FRG::readSavedTextFile(path); if (content.empty()) { std::cerr << "[save] Save file not found or empty: " << path << std::endl; return; @@ -1915,4 +1915,4 @@ namespace ZL } } -} // namespace ZL \ No newline at end of file +} // namespace FRG \ No newline at end of file diff --git a/src/Game.h b/src/Game.h index b5965a1..87ee8ff 100644 --- a/src/Game.h +++ b/src/Game.h @@ -22,7 +22,7 @@ #include "Location.h" #include "AudioPlayerAsync.h" #include "GameState.h" -namespace ZL { +namespace FRG { struct SaveSlotInfo { std::string locationName; @@ -206,4 +206,4 @@ namespace ZL { }; -} // namespace ZL +} // namespace FRG diff --git a/src/GameConstants.cpp b/src/GameConstants.cpp index 1b617aa..7426160 100644 --- a/src/GameConstants.cpp +++ b/src/GameConstants.cpp @@ -1,6 +1,6 @@ #include "GameConstants.h" -namespace ZL +namespace FRG { const std::string defaultShaderName = "default"; const std::string envShaderName = "env"; diff --git a/src/GameConstants.h b/src/GameConstants.h index 2d5ae0b..d79c764 100644 --- a/src/GameConstants.h +++ b/src/GameConstants.h @@ -1,7 +1,7 @@ #pragma once #include "render/Renderer.h" -namespace ZL +namespace FRG { extern const std::string defaultShaderName; extern const std::string envShaderName; diff --git a/src/GameState.cpp b/src/GameState.cpp index 7bb85bc..409379c 100644 --- a/src/GameState.cpp +++ b/src/GameState.cpp @@ -3,7 +3,7 @@ #include #include -namespace ZL { +namespace FRG { void GameState::save(nlohmann::json& out) const { @@ -158,4 +158,4 @@ void GameState::load(const nlohmann::json& in) taxiIsCalled = in.value("taxiIsCalled", taxiIsCalled); } -} // namespace ZL +} // namespace FRG diff --git a/src/GameState.h b/src/GameState.h index f916a0a..0627645 100644 --- a/src/GameState.h +++ b/src/GameState.h @@ -9,7 +9,7 @@ #include #include -namespace ZL { +namespace FRG { enum class TutorialStep { Step0, // Dialogue hint: "click to advance" @@ -75,4 +75,4 @@ struct GameState : public ISaveable { void load(const nlohmann::json& in) override; }; -} // namespace ZL +} // namespace FRG diff --git a/src/ISaveable.h b/src/ISaveable.h index fb244ff..01e2e6e 100644 --- a/src/ISaveable.h +++ b/src/ISaveable.h @@ -1,7 +1,7 @@ #pragma once #include "external/nlohmann/json.hpp" -namespace ZL { +namespace FRG { struct ISaveable { virtual void save(nlohmann::json& out) const = 0; @@ -9,4 +9,4 @@ struct ISaveable { virtual ~ISaveable() = default; }; -} // namespace ZL +} // namespace FRG diff --git a/src/Localization.cpp b/src/Localization.cpp index 9c55b04..2411fa5 100644 --- a/src/Localization.cpp +++ b/src/Localization.cpp @@ -11,7 +11,7 @@ #include #endif -namespace ZL { +namespace FRG { Language g_currentLanguage = Language::Russian; @@ -119,4 +119,4 @@ Language detectSystemLanguage() { return Language::English; } -} // namespace ZL +} // namespace FRG diff --git a/src/Localization.h b/src/Localization.h index e6cad38..150c0aa 100644 --- a/src/Localization.h +++ b/src/Localization.h @@ -1,7 +1,7 @@ #pragma once #include -namespace ZL { +namespace FRG { enum class Language { Russian, @@ -31,4 +31,4 @@ void loadLanguageSetting(); Language detectSystemLanguage(); -} // namespace ZL +} // namespace FRG diff --git a/src/Location.cpp b/src/Location.cpp index 26366e6..fe47f60 100644 --- a/src/Location.cpp +++ b/src/Location.cpp @@ -16,7 +16,7 @@ #include "external/nlohmann/json.hpp" #include -namespace ZL +namespace FRG { extern const char* CONST_ZIP_FILE; @@ -2232,4 +2232,4 @@ namespace ZL } } -} // namespace ZL +} // namespace FRG diff --git a/src/Location.h b/src/Location.h index 14367a4..e894f1b 100644 --- a/src/Location.h +++ b/src/Location.h @@ -20,7 +20,7 @@ #include #include -namespace ZL +namespace FRG { struct PointLight @@ -214,4 +214,4 @@ namespace ZL std::unordered_map npcBumpsPlayerCooldown; }; -} // namespace ZL +} // namespace FRG diff --git a/src/LocationEditor.cpp b/src/LocationEditor.cpp index 22db74a..81545d9 100644 --- a/src/LocationEditor.cpp +++ b/src/LocationEditor.cpp @@ -12,7 +12,7 @@ #include #include -namespace ZL +namespace FRG { extern const char* CONST_ZIP_FILE; @@ -535,4 +535,4 @@ namespace ZL saveJsonToFile(j, filename); } -} // namespace ZL +} // namespace FRG diff --git a/src/LocationEditor.h b/src/LocationEditor.h index dceda60..6508d5b 100644 --- a/src/LocationEditor.h +++ b/src/LocationEditor.h @@ -7,7 +7,7 @@ #include "items/GameObjectLoader.h" #include -namespace ZL { +namespace FRG { class Location; // forward declaration — LocationEditor.cpp includes Location.h @@ -67,4 +67,4 @@ private: Location& loc; }; -} // namespace ZL +} // namespace FRG diff --git a/src/LocationState.cpp b/src/LocationState.cpp index 42797f1..3de601a 100644 --- a/src/LocationState.cpp +++ b/src/LocationState.cpp @@ -1,6 +1,6 @@ #include "LocationState.h" -namespace ZL { +namespace FRG { void LocationState::save(nlohmann::json& out) const { @@ -223,4 +223,4 @@ void LocationState::load(const nlohmann::json& in) } -} // namespace ZL +} // namespace FRG diff --git a/src/LocationState.h b/src/LocationState.h index 8f5e0d8..e81ba1f 100644 --- a/src/LocationState.h +++ b/src/LocationState.h @@ -3,7 +3,7 @@ #include "ISaveable.h" #include "NpcCar.h" -namespace ZL { +namespace FRG { struct LocationState : public ISaveable { // ---- Camera ---- @@ -41,4 +41,4 @@ struct LocationState : public ISaveable { void load(const nlohmann::json& in) override; }; -} // namespace ZL +} // namespace FRG diff --git a/src/MenuManager.cpp b/src/MenuManager.cpp index 9e2d6db..1a1e1fb 100644 --- a/src/MenuManager.cpp +++ b/src/MenuManager.cpp @@ -10,7 +10,7 @@ #include #include -namespace ZL { +namespace FRG { // Localization static const std::string EMPTY_LANGUAGE_RU = u8"(пусто)"; @@ -669,13 +669,13 @@ namespace ZL { uiManager.setTextButtonCallback("languageRussianButton", [this](const std::string&) { audioPlayer_.playSoundAsync("audio/751089__smallconfusion__mechanical-plastic-click-11.ogg"); - ZL::g_currentLanguage = ZL::Language::Russian; + FRG::g_currentLanguage = FRG::Language::Russian; reloadLocalizedGameContent(); saveSettings(); }); uiManager.setTextButtonCallback("languageEnglishButton", [this](const std::string&) { audioPlayer_.playSoundAsync("audio/751089__smallconfusion__mechanical-plastic-click-11.ogg"); - ZL::g_currentLanguage = ZL::Language::English; + FRG::g_currentLanguage = FRG::Language::English; reloadLocalizedGameContent(); saveSettings(); }); @@ -748,18 +748,18 @@ namespace ZL { SaveSlotInfo info = getSlotInfoFunc(slot); std::string emptyText; - if (ZL::g_currentLanguage == ZL::Language::Russian) + if (FRG::g_currentLanguage == FRG::Language::Russian) { emptyText = EMPTY_LANGUAGE_RU; } - else if (ZL::g_currentLanguage == ZL::Language::English) + else if (FRG::g_currentLanguage == FRG::Language::English) { emptyText = EMPTY_LANGUAGE_EN; } std::string label = info.empty ? emptyText - : localizedLocationName[info.locationName][ZL::g_currentLanguage] + " " + info.savedAt; + : localizedLocationName[info.locationName][FRG::g_currentLanguage] + " " + info.savedAt; uiManager.setTextButtonText(kSlotButtons[i], label); } uiManager.setTextButtonCallback(kSlotButtons[i], [this, slot](const std::string&) { @@ -789,18 +789,18 @@ namespace ZL { SaveSlotInfo info = getSlotInfoFunc(slot); std::string emptyText; - if (ZL::g_currentLanguage == ZL::Language::Russian) + if (FRG::g_currentLanguage == FRG::Language::Russian) { emptyText = EMPTY_LANGUAGE_RU; } - else if (ZL::g_currentLanguage == ZL::Language::English) + else if (FRG::g_currentLanguage == FRG::Language::English) { emptyText = EMPTY_LANGUAGE_EN; } std::string label = info.empty ? emptyText - : localizedLocationName[info.locationName][ZL::g_currentLanguage] + " " + info.savedAt; + : localizedLocationName[info.locationName][FRG::g_currentLanguage] + " " + info.savedAt; uiManager.setTextButtonText(buttonName, label); } uiManager.setTextButtonCallback(buttonName, [this, slot, buttonName](const std::string&) { @@ -809,18 +809,18 @@ namespace ZL { SaveSlotInfo info = getSlotInfoFunc(slot); std::string emptyText; - if (ZL::g_currentLanguage == ZL::Language::Russian) + if (FRG::g_currentLanguage == FRG::Language::Russian) { emptyText = EMPTY_LANGUAGE_RU; } - else if (ZL::g_currentLanguage == ZL::Language::English) + else if (FRG::g_currentLanguage == FRG::Language::English) { emptyText = EMPTY_LANGUAGE_EN; } std::string label = info.empty ? emptyText - : localizedLocationName[info.locationName][ZL::g_currentLanguage] + " " + info.savedAt; + : localizedLocationName[info.locationName][FRG::g_currentLanguage] + " " + info.savedAt; uiManager.setTextButtonText(buttonName, label); audioPlayer_.playSoundAsync("audio/751089__smallconfusion__mechanical-plastic-click-11.ogg"); } @@ -2271,7 +2271,7 @@ namespace ZL { root["musicEnabled"] = audioPlayer_.isMusicEnabled(); root["soundEnabled"] = audioPlayer_.isSoundEnabled(); root["fullscreen"] = Environment::isFullscreen; - root["language"] = ZL::languageToCode(ZL::g_currentLanguage); + root["language"] = FRG::languageToCode(FRG::g_currentLanguage); root["shadow"] = shadowsEnabled; saveJsonToFile(root, "settings.json"); @@ -2282,12 +2282,12 @@ namespace ZL { // directly in the right fullscreen state (see WIN32 main() in main.cpp) to avoid // a windowed -> fullscreen flash. The block below just keeps Environment::isFullscreen // in sync in case this is ever called from a path that didn't pre-apply it. - // Language is loaded separately, even earlier (see ZL::loadLanguageSetting() + // Language is loaded separately, even earlier (see FRG::loadLanguageSetting() // callers), because some location scripts start a dialogue as soon as they're // loaded, before this function ever runs. - ZL::loadLanguageSetting(); + FRG::loadLanguageSetting(); - const std::string content = ZL::readSavedTextFile("settings.json"); + const std::string content = FRG::readSavedTextFile("settings.json"); if (content.empty()) return; try { const nlohmann::json root = nlohmann::json::parse(content); @@ -2427,4 +2427,4 @@ namespace ZL { uiManager.updateAllLayouts(); } -} // namespace ZL +} // namespace FRG diff --git a/src/MenuManager.h b/src/MenuManager.h index 8f2d909..e6caa1e 100644 --- a/src/MenuManager.h +++ b/src/MenuManager.h @@ -13,9 +13,9 @@ #include "render/FrameBuffer.h" // Forward-declared here to avoid pulling Game.h into MenuManager.h. -namespace ZL { struct SaveSlotInfo; } +namespace FRG { struct SaveSlotInfo; } -namespace ZL { +namespace FRG { extern const char* CONST_ZIP_FILE; @@ -343,4 +343,4 @@ namespace ZL { }; -} // namespace ZL +} // namespace FRG diff --git a/src/NpcCar.cpp b/src/NpcCar.cpp index 6a69bba..596e721 100644 --- a/src/NpcCar.cpp +++ b/src/NpcCar.cpp @@ -1,6 +1,6 @@ #include "NpcCar.h" -namespace ZL +namespace FRG { const float NpcCar::acceleration = 10.0f; const float NpcCar::friction = 8.0f; diff --git a/src/NpcCar.h b/src/NpcCar.h index f643c24..3375e3f 100644 --- a/src/NpcCar.h +++ b/src/NpcCar.h @@ -2,7 +2,7 @@ #include "render/Renderer.h" #include "Environment.h" -namespace ZL { +namespace FRG { struct NpcCar { enum class Mode { FOLLOW_WAYPOINTS, NONE }; diff --git a/src/ScriptEngine.cpp b/src/ScriptEngine.cpp index db666d2..b845897 100644 --- a/src/ScriptEngine.cpp +++ b/src/ScriptEngine.cpp @@ -10,7 +10,7 @@ #define SOL_ALL_SAFETIES_ON 1 #include -namespace ZL { +namespace FRG { namespace { @@ -1159,4 +1159,4 @@ namespace ZL { outCallback = wrapLuaCallback(fn); } -} // namespace ZL +} // namespace FRG diff --git a/src/ScriptEngine.h b/src/ScriptEngine.h index f64a436..06a40e2 100644 --- a/src/ScriptEngine.h +++ b/src/ScriptEngine.h @@ -8,7 +8,7 @@ #include "ISaveable.h" #include "AudioPlayerAsync.h" -namespace ZL { +namespace FRG { class Location; class Inventory; @@ -79,4 +79,4 @@ private: std::unique_ptr impl; }; -} // namespace ZL +} // namespace FRG diff --git a/src/SparkEmitter.cpp b/src/SparkEmitter.cpp index 929523e..5565f52 100644 --- a/src/SparkEmitter.cpp +++ b/src/SparkEmitter.cpp @@ -10,7 +10,7 @@ #include "utils/Utils.h" #include "GameConstants.h" -namespace ZL { +namespace FRG { using json = nlohmann::json; @@ -669,4 +669,4 @@ namespace ZL { return true; } -} // namespace ZL \ No newline at end of file +} // namespace FRG \ No newline at end of file diff --git a/src/SparkEmitter.h b/src/SparkEmitter.h index 1388b22..e9714ef 100644 --- a/src/SparkEmitter.h +++ b/src/SparkEmitter.h @@ -6,7 +6,7 @@ #include #include -namespace ZL { +namespace FRG { struct SparkParticle { Vector3f position; @@ -126,4 +126,4 @@ namespace ZL { Vector3f getRandomVelocity(int emitterIndex); }; -} // namespace ZL \ No newline at end of file +} // namespace FRG \ No newline at end of file diff --git a/src/TeleportZone.cpp b/src/TeleportZone.cpp index 3a69a74..920898c 100644 --- a/src/TeleportZone.cpp +++ b/src/TeleportZone.cpp @@ -2,7 +2,7 @@ #include "render/Renderer.h" #include "render/TextureManager.h" -namespace ZL { +namespace FRG { void TeleportZone::initSparks(std::shared_ptr activeTex, std::shared_ptr inactiveTex) { @@ -49,4 +49,4 @@ void TeleportZone::draw(Renderer& renderer, float zoom, int width, int height) if (sparks) sparks->draw(renderer, zoom, width, height); } -} // namespace ZL +} // namespace FRG diff --git a/src/TeleportZone.h b/src/TeleportZone.h index 839762c..312741d 100644 --- a/src/TeleportZone.h +++ b/src/TeleportZone.h @@ -4,7 +4,7 @@ #include #include "SparkEmitter.h" -namespace ZL { +namespace FRG { class Renderer; class Texture; @@ -33,4 +33,4 @@ struct TeleportZone { void draw(Renderer& renderer, float zoom, int width, int height); }; -} // namespace ZL +} // namespace FRG diff --git a/src/TextModel.cpp b/src/TextModel.cpp index 7f5a70c..d0de334 100644 --- a/src/TextModel.cpp +++ b/src/TextModel.cpp @@ -7,7 +7,7 @@ #ifdef __ANDROID__ #include #endif -namespace ZL +namespace FRG { static std::unordered_map s_meshCache; diff --git a/src/TextModel.h b/src/TextModel.h index f1236b5..0ae194f 100644 --- a/src/TextModel.h +++ b/src/TextModel.h @@ -4,7 +4,7 @@ #include -namespace ZL +namespace FRG { VertexDataStruct LoadFromTextFile02(const std::string& fileName, const std::string& ZIPFileName = ""); VertexDataStruct LoadModelFromBinFile(const std::string& fileName, const std::string& ZIPFileName = ""); diff --git a/src/UiManager.cpp b/src/UiManager.cpp index 965e631..9d9fd80 100644 --- a/src/UiManager.cpp +++ b/src/UiManager.cpp @@ -7,7 +7,7 @@ #include #include "GameConstants.h" -namespace ZL { +namespace FRG { using json = nlohmann::json; @@ -2307,4 +2307,4 @@ namespace ZL { chatBubbles.clear(); } -} // namespace ZL \ No newline at end of file +} // namespace FRG \ No newline at end of file diff --git a/src/UiManager.h b/src/UiManager.h index 2ad0a4d..505423a 100644 --- a/src/UiManager.h +++ b/src/UiManager.h @@ -13,7 +13,7 @@ #include #include -namespace ZL { +namespace FRG { using json = nlohmann::json; @@ -565,4 +565,4 @@ namespace ZL { }; -} // namespace ZL \ No newline at end of file +} // namespace FRG \ No newline at end of file diff --git a/src/cutscene/CutsceneDatabase.cpp b/src/cutscene/CutsceneDatabase.cpp index 23fb882..6203223 100644 --- a/src/cutscene/CutsceneDatabase.cpp +++ b/src/cutscene/CutsceneDatabase.cpp @@ -3,12 +3,12 @@ #include "utils/Utils.h" #include -namespace ZL +namespace FRG { extern const char* CONST_ZIP_FILE; } -namespace ZL::Cutscene { +namespace FRG::Cutscene { EasingType CutsceneDatabase::parseEasingType(const std::string& value) { if (value == "EaseInSine") return EasingType::EaseInSine; @@ -92,11 +92,11 @@ bool CutsceneDatabase::loadFromFile(const std::string& path) { std::string raw; try { - if (strlen(ZL::CONST_ZIP_FILE) == 0) { + if (strlen(FRG::CONST_ZIP_FILE) == 0) { raw = readTextFile(path); } else { - auto buf = readFileFromZIP(path, ZL::CONST_ZIP_FILE); + auto buf = readFileFromZIP(path, FRG::CONST_ZIP_FILE); if (buf.empty()) { std::cerr << "[cutscene] Failed to read " << path << " from zip\n"; throw std::runtime_error("Failed to load cutscene file: " + path); @@ -135,4 +135,4 @@ const StaticCutsceneDefinition* CutsceneDatabase::findCutscene(const std::string return (it != cutscenes.end()) ? &it->second : nullptr; } -} // namespace ZL::Cutscene +} // namespace FRG::Cutscene diff --git a/src/cutscene/CutsceneDatabase.h b/src/cutscene/CutsceneDatabase.h index 0f4cf8d..8bddf05 100644 --- a/src/cutscene/CutsceneDatabase.h +++ b/src/cutscene/CutsceneDatabase.h @@ -5,7 +5,7 @@ #include #include -namespace ZL::Cutscene { +namespace FRG::Cutscene { class CutsceneDatabase { public: @@ -26,4 +26,4 @@ private: static StaticCutsceneDefinition parseCutscene(const json& j); }; -} // namespace ZL::Cutscene +} // namespace FRG::Cutscene diff --git a/src/cutscene/CutsceneOverlay.cpp b/src/cutscene/CutsceneOverlay.cpp index 88187c5..69d6c79 100644 --- a/src/cutscene/CutsceneOverlay.cpp +++ b/src/cutscene/CutsceneOverlay.cpp @@ -6,7 +6,7 @@ #include #include -namespace ZL::Cutscene { +namespace FRG::Cutscene { bool CutsceneOverlay::init(Renderer& renderer, const std::string& zipFile) { rendererRef = &renderer; @@ -26,8 +26,8 @@ bool CutsceneOverlay::init(Renderer& renderer, const std::string& zipFile) { choiceRenderer->init(renderer, "resources/fonts/DroidSans.ttf", 22, zipFile); } -void CutsceneOverlay::update(const ZL::Dialogue::PresentationModel& model, int deltaMs) { - if (model.mode != ZL::Dialogue::PresentationMode::Cutscene || !model.cutsceneSkippable) { +void CutsceneOverlay::update(const FRG::Dialogue::PresentationModel& model, int deltaMs) { + if (model.mode != FRG::Dialogue::PresentationMode::Cutscene || !model.cutsceneSkippable) { cutsceneSkipHintVisible = false; cutsceneSkipArmed = false; cutsceneSkipHolding = false; @@ -106,8 +106,8 @@ void CutsceneOverlay::buildImageUV( outBR = { (cx + halfW) / safeImgW, (cy - halfH) / safeImgH }; } -void CutsceneOverlay::draw(Renderer& renderer, const ZL::Dialogue::PresentationModel& model) { - if (model.mode != ZL::Dialogue::PresentationMode::Cutscene) return; +void CutsceneOverlay::draw(Renderer& renderer, const FRG::Dialogue::PresentationModel& model) { + if (model.mode != FRG::Dialogue::PresentationMode::Cutscene) return; const float W = Environment::projectionWidth; const float H = Environment::projectionHeight; @@ -126,7 +126,7 @@ void CutsceneOverlay::draw(Renderer& renderer, const ZL::Dialogue::PresentationM const UiRect screenRect{ 0.0f, 0.0f, W, H }; - for (const ZL::Cutscene::PresentedCutsceneImage& layer : model.cutsceneImages) { + for (const FRG::Cutscene::PresentedCutsceneImage& layer : model.cutsceneImages) { const auto texture = loadTextureCached(layer.path); if (!texture) continue; @@ -224,9 +224,9 @@ bool CutsceneOverlay::consumeSkipRequested() { return result; } -void CutsceneOverlay::handlePointerDown(float x, float y, const ZL::Dialogue::PresentationModel& model) { +void CutsceneOverlay::handlePointerDown(float x, float y, const FRG::Dialogue::PresentationModel& model) { (void)x; (void)y; - if (model.mode != ZL::Dialogue::PresentationMode::Cutscene || !model.cutsceneSkippable) return; + if (model.mode != FRG::Dialogue::PresentationMode::Cutscene || !model.cutsceneSkippable) return; if (!cutsceneSkipArmed) { cutsceneSkipHintVisible = true; @@ -245,11 +245,11 @@ void CutsceneOverlay::handlePointerDown(float x, float y, const ZL::Dialogue::Pr cutsceneSkipHoldElapsedMs = 0; } -void CutsceneOverlay::handlePointerMoved(float /*x*/, float /*y*/, const ZL::Dialogue::PresentationModel& /*model*/) { +void CutsceneOverlay::handlePointerMoved(float /*x*/, float /*y*/, const FRG::Dialogue::PresentationModel& /*model*/) { } -bool CutsceneOverlay::handlePointerReleased(float /*x*/, float /*y*/, const ZL::Dialogue::PresentationModel& model) { - if (model.mode != ZL::Dialogue::PresentationMode::Cutscene) return false; +bool CutsceneOverlay::handlePointerReleased(float /*x*/, float /*y*/, const FRG::Dialogue::PresentationModel& model) { + if (model.mode != FRG::Dialogue::PresentationMode::Cutscene) return false; if (cutsceneSkipHolding && cutsceneSkipHoldElapsedMs < CutsceneSkipHoldDurationMs) { cutsceneSkipHolding = false; cutsceneSkipHoldElapsedMs = 0; @@ -306,4 +306,4 @@ std::string CutsceneOverlay::wrapTextToWidth( return output; } -} // namespace ZL::Cutscene +} // namespace FRG::Cutscene diff --git a/src/cutscene/CutsceneOverlay.h b/src/cutscene/CutsceneOverlay.h index 104a315..e1709a9 100644 --- a/src/cutscene/CutsceneOverlay.h +++ b/src/cutscene/CutsceneOverlay.h @@ -11,17 +11,17 @@ #include #include -namespace ZL::Cutscene { +namespace FRG::Cutscene { class CutsceneOverlay { public: bool init(Renderer& renderer, const std::string& zipFile = ""); - void update(const ZL::Dialogue::PresentationModel& model, int deltaMs); - void draw(Renderer& renderer, const ZL::Dialogue::PresentationModel& model); + void update(const FRG::Dialogue::PresentationModel& model, int deltaMs); + void draw(Renderer& renderer, const FRG::Dialogue::PresentationModel& model); - void handlePointerDown(float x, float y, const ZL::Dialogue::PresentationModel& model); - void handlePointerMoved(float x, float y, const ZL::Dialogue::PresentationModel& model); - bool handlePointerReleased(float x, float y, const ZL::Dialogue::PresentationModel& model); + void handlePointerDown(float x, float y, const FRG::Dialogue::PresentationModel& model); + void handlePointerMoved(float x, float y, const FRG::Dialogue::PresentationModel& model); + bool handlePointerReleased(float x, float y, const FRG::Dialogue::PresentationModel& model); bool consumeSkipRequested(); private: @@ -69,4 +69,4 @@ private: float maxWidthPx, float scale); }; -} // namespace ZL::Cutscene +} // namespace FRG::Cutscene diff --git a/src/cutscene/CutsceneRuntime.cpp b/src/cutscene/CutsceneRuntime.cpp index 5cdd72c..bfd69d4 100644 --- a/src/cutscene/CutsceneRuntime.cpp +++ b/src/cutscene/CutsceneRuntime.cpp @@ -5,18 +5,18 @@ #include #include "utils/Utils.h" -namespace ZL::Cutscene { +namespace FRG::Cutscene { void CutsceneRuntime::setDatabase(const CutsceneDatabase* value) { database = value; } -void CutsceneRuntime::setTranslationDatabase(const ZL::Dialogue::TranslationDatabase* value) { +void CutsceneRuntime::setTranslationDatabase(const FRG::Dialogue::TranslationDatabase* value) { translations = value; } std::string CutsceneRuntime::tr(const std::string& s) const { - return translations ? translations->translate(s, ZL::g_currentLanguage) : s; + return translations ? translations->translate(s, FRG::g_currentLanguage) : s; } void CutsceneRuntime::setOnFinished(std::function cb) { @@ -282,7 +282,7 @@ std::vector CutsceneRuntime::evaluateImages() const { void CutsceneRuntime::refreshPresentation() { if (!activeCutscene) return; - presentation.mode = ZL::Dialogue::PresentationMode::Cutscene; + presentation.mode = FRG::Dialogue::PresentationMode::Cutscene; presentation.cutsceneSkippable = activeCutscene->skippable; presentation.cutsceneImages = evaluateImages(); @@ -381,4 +381,4 @@ int CutsceneRuntime::computeFallbackDurationMs(const std::string& text) { return std::max(minDuration, calculated + linger); } -} // namespace ZL::Cutscene +} // namespace FRG::Cutscene diff --git a/src/cutscene/CutsceneRuntime.h b/src/cutscene/CutsceneRuntime.h index ae1817b..d7a4a9a 100644 --- a/src/cutscene/CutsceneRuntime.h +++ b/src/cutscene/CutsceneRuntime.h @@ -7,12 +7,12 @@ #include #include -namespace ZL::Cutscene { +namespace FRG::Cutscene { class CutsceneRuntime { public: void setDatabase(const CutsceneDatabase* value); - void setTranslationDatabase(const ZL::Dialogue::TranslationDatabase* value); + void setTranslationDatabase(const FRG::Dialogue::TranslationDatabase* value); void setOnFinished(std::function cb); void setOnLineStarted(std::function cb); @@ -26,11 +26,11 @@ public: bool canSkip() const; void skip(); - const ZL::Dialogue::PresentationModel& getPresentation() const { return presentation; } + const FRG::Dialogue::PresentationModel& getPresentation() const { return presentation; } private: const CutsceneDatabase* database = nullptr; - const ZL::Dialogue::TranslationDatabase* translations = nullptr; + const FRG::Dialogue::TranslationDatabase* translations = nullptr; const StaticCutsceneDefinition* activeCutscene = nullptr; std::string activeCutsceneId; @@ -44,7 +44,7 @@ private: int cutsceneTotalDurationMs = 0; int cutsceneContentDurationMs = 0; - ZL::Dialogue::PresentationModel presentation; + FRG::Dialogue::PresentationModel presentation; std::function onFinished; std::function onLineStarted; @@ -62,4 +62,4 @@ private: static int computeFallbackDurationMs(const std::string& text); }; -} // namespace ZL::Cutscene +} // namespace FRG::Cutscene diff --git a/src/cutscene/CutsceneTypes.h b/src/cutscene/CutsceneTypes.h index 63e2813..30f1476 100644 --- a/src/cutscene/CutsceneTypes.h +++ b/src/cutscene/CutsceneTypes.h @@ -3,7 +3,7 @@ #include #include -namespace ZL::Cutscene { +namespace FRG::Cutscene { enum class EasingType { Linear, @@ -75,4 +75,4 @@ struct PresentedCutsceneImage { int height = 0; }; -} // namespace ZL::Cutscene +} // namespace FRG::Cutscene diff --git a/src/dialogue/DialogueDatabase.cpp b/src/dialogue/DialogueDatabase.cpp index 31dd2fc..9624e88 100644 --- a/src/dialogue/DialogueDatabase.cpp +++ b/src/dialogue/DialogueDatabase.cpp @@ -3,12 +3,12 @@ #include "utils/Utils.h" #include -namespace ZL +namespace FRG { extern const char* CONST_ZIP_FILE; } -namespace ZL::Dialogue { +namespace FRG::Dialogue { NodeType DialogueDatabase::parseNodeType(const std::string& value) { if (value == "Choice") return NodeType::Choice; @@ -174,4 +174,4 @@ const DialogueDefinition* DialogueDatabase::findDialogue(const std::string& id) return (it != dialogues.end()) ? &it->second : nullptr; } -} // namespace ZL::Dialogue +} // namespace FRG::Dialogue diff --git a/src/dialogue/DialogueDatabase.h b/src/dialogue/DialogueDatabase.h index 6c6ac22..aa4a5fc 100644 --- a/src/dialogue/DialogueDatabase.h +++ b/src/dialogue/DialogueDatabase.h @@ -5,7 +5,7 @@ #include #include -namespace ZL::Dialogue { +namespace FRG::Dialogue { class DialogueDatabase { public: @@ -29,4 +29,4 @@ private: static DialogueDefinition parseDialogue(const json& j); }; -} // namespace ZL::Dialogue +} // namespace FRG::Dialogue diff --git a/src/dialogue/DialogueOverlay.cpp b/src/dialogue/DialogueOverlay.cpp index a50df86..f4cdde1 100644 --- a/src/dialogue/DialogueOverlay.cpp +++ b/src/dialogue/DialogueOverlay.cpp @@ -6,13 +6,13 @@ #include #include -namespace ZL +namespace FRG { extern float x; extern float y; } -namespace ZL::Dialogue { +namespace FRG::Dialogue { bool DialogueOverlay::init(Renderer& renderer, const std::string& zipFile) { rendererRef = &renderer; @@ -447,4 +447,4 @@ bool DialogueOverlay::rectContains(const UiRect& rect, float x, float y) { return x >= rect.x && x <= rect.x + rect.w && y >= rect.y && y <= rect.y + rect.h; } -} // namespace ZL::Dialogue +} // namespace FRG::Dialogue diff --git a/src/dialogue/DialogueOverlay.h b/src/dialogue/DialogueOverlay.h index 3d2b8bf..e02398d 100644 --- a/src/dialogue/DialogueOverlay.h +++ b/src/dialogue/DialogueOverlay.h @@ -10,7 +10,7 @@ #include #include -namespace ZL::Dialogue { +namespace FRG::Dialogue { class DialogueOverlay { public: @@ -62,4 +62,4 @@ private: void drawPortrait(Renderer& renderer, const PresentationModel& model); }; -} // namespace ZL::Dialogue +} // namespace FRG::Dialogue diff --git a/src/dialogue/DialogueRuntime.cpp b/src/dialogue/DialogueRuntime.cpp index 3d0e408..1ce2429 100644 --- a/src/dialogue/DialogueRuntime.cpp +++ b/src/dialogue/DialogueRuntime.cpp @@ -3,7 +3,7 @@ #include #include -namespace ZL::Dialogue { +namespace FRG::Dialogue { static std::pair splitDot(const std::string& s) { const auto dot = s.find('.'); @@ -414,4 +414,4 @@ void DialogueRuntime::load(const nlohmann::json& in) revealCharacters = static_cast(presentation.fullText.size()); } -} // namespace ZL::Dialogue +} // namespace FRG::Dialogue diff --git a/src/dialogue/DialogueRuntime.h b/src/dialogue/DialogueRuntime.h index c103ccb..8a599e1 100644 --- a/src/dialogue/DialogueRuntime.h +++ b/src/dialogue/DialogueRuntime.h @@ -11,9 +11,9 @@ #include #include -namespace ZL::Dialogue { +namespace FRG::Dialogue { -class DialogueRuntime : public ZL::ISaveable { +class DialogueRuntime : public FRG::ISaveable { public: void setDatabase(const DialogueDatabase* value); void setTranslationDatabase(const TranslationDatabase* value); @@ -92,4 +92,4 @@ private: std::string tr(const std::string& s) const; }; -} // namespace ZL::Dialogue +} // namespace FRG::Dialogue diff --git a/src/dialogue/DialogueSystem.cpp b/src/dialogue/DialogueSystem.cpp index 14edafa..7a3c1bf 100644 --- a/src/dialogue/DialogueSystem.cpp +++ b/src/dialogue/DialogueSystem.cpp @@ -1,6 +1,6 @@ #include "dialogue/DialogueSystem.h" -namespace ZL::Dialogue { +namespace FRG::Dialogue { bool DialogueSystem::init(Renderer& renderer, const std::string& zipFile) { dialogueRuntime.setDatabase(&database); @@ -221,4 +221,4 @@ void DialogueSystem::setOnDialogueAdvanced(std::function cb) { onDialogueAdvancedCallback = std::move(cb); } -} // namespace ZL::Dialogue +} // namespace FRG::Dialogue diff --git a/src/dialogue/DialogueSystem.h b/src/dialogue/DialogueSystem.h index d9a72e3..432d2ca 100644 --- a/src/dialogue/DialogueSystem.h +++ b/src/dialogue/DialogueSystem.h @@ -12,9 +12,9 @@ #include #include -namespace ZL::Dialogue { +namespace FRG::Dialogue { -class DialogueSystem : public ZL::ISaveable { +class DialogueSystem : public FRG::ISaveable { public: bool init(Renderer& renderer, const std::string& zipFile = ""); @@ -71,10 +71,10 @@ private: DialogueRuntime dialogueRuntime; DialogueOverlay dialogueOverlay; - ZL::Cutscene::CutsceneDatabase cutsceneDatabase; + FRG::Cutscene::CutsceneDatabase cutsceneDatabase; TranslationDatabase cutsceneTranslationDatabase; - ZL::Cutscene::CutsceneRuntime cutsceneRuntime; - ZL::Cutscene::CutsceneOverlay cutsceneOverlay; + FRG::Cutscene::CutsceneRuntime cutsceneRuntime; + FRG::Cutscene::CutsceneOverlay cutsceneOverlay; std::function onDialogueAdvancedCallback; std::function onCutsceneStartedCallback; @@ -87,4 +87,4 @@ private: void onCutsceneFinishedInternal(const std::string& id); }; -} // namespace ZL::Dialogue +} // namespace FRG::Dialogue diff --git a/src/dialogue/DialogueTypes.h b/src/dialogue/DialogueTypes.h index 4955af9..70884e0 100644 --- a/src/dialogue/DialogueTypes.h +++ b/src/dialogue/DialogueTypes.h @@ -6,7 +6,7 @@ #include #include -namespace ZL::Dialogue { +namespace FRG::Dialogue { enum class NodeType { Line, @@ -121,9 +121,9 @@ struct PresentationModel { bool showCutsceneSubtitle = false; bool cutsceneSkippable = false; - std::vector cutsceneImages; + std::vector cutsceneImages; float cutsceneGlobalFadeAlpha = 1.0f; float cutsceneBlackAlpha = 0.0f; }; -} // namespace ZL::Dialogue +} // namespace FRG::Dialogue diff --git a/src/dialogue/TranslationDatabase.cpp b/src/dialogue/TranslationDatabase.cpp index 6635b88..822931c 100644 --- a/src/dialogue/TranslationDatabase.cpp +++ b/src/dialogue/TranslationDatabase.cpp @@ -3,12 +3,12 @@ #include "utils/Utils.h" #include -namespace ZL +namespace FRG { extern const char* CONST_ZIP_FILE; } -namespace ZL::Dialogue { +namespace FRG::Dialogue { bool TranslationDatabase::loadFromFile(const std::string& path) { entries.clear(); @@ -94,4 +94,4 @@ const std::string& TranslationDatabase::translateRef(const std::string& key, Lan return key; } -} // namespace ZL::Dialogue +} // namespace FRG::Dialogue diff --git a/src/dialogue/TranslationDatabase.h b/src/dialogue/TranslationDatabase.h index e63b00d..59b22f1 100644 --- a/src/dialogue/TranslationDatabase.h +++ b/src/dialogue/TranslationDatabase.h @@ -5,7 +5,7 @@ #include #include -namespace ZL::Dialogue { +namespace FRG::Dialogue { // Loads a shared translation file mapping dialogue "key" strings (the literal // speaker/text/choice text found in dialogue config files) to per-language text. @@ -24,4 +24,4 @@ private: std::unordered_map> entries; }; -} // namespace ZL::Dialogue +} // namespace FRG::Dialogue diff --git a/src/items/GameObjectLoader.cpp b/src/items/GameObjectLoader.cpp index 83cde29..2045b72 100644 --- a/src/items/GameObjectLoader.cpp +++ b/src/items/GameObjectLoader.cpp @@ -10,7 +10,7 @@ #include -namespace ZL { +namespace FRG { using json = nlohmann::json; @@ -389,4 +389,4 @@ namespace ZL { return npcs; } -} // namespace ZL +} // namespace FRG diff --git a/src/items/GameObjectLoader.h b/src/items/GameObjectLoader.h index 030fc43..b60838a 100644 --- a/src/items/GameObjectLoader.h +++ b/src/items/GameObjectLoader.h @@ -10,7 +10,7 @@ #include "InteractiveObjectState.h" #include "../CharacterState.h" -namespace ZL { +namespace FRG { class Character; @@ -98,7 +98,7 @@ namespace ZL { const std::string& zipPath = "" ); - static std::vector> loadAndCreate_Npcs( + static std::vector> loadAndCreate_Npcs( const std::string& jsonPath, Renderer& renderer, const std::string& zipPath = "" @@ -114,4 +114,4 @@ namespace ZL { static std::vector loadInteractiveFromJson(const std::string& jsonPath, const std::string& zipPath); }; -} // namespace ZL +} // namespace FRG diff --git a/src/items/InteractiveObject.cpp b/src/items/InteractiveObject.cpp index 2bb2df2..c0445df 100644 --- a/src/items/InteractiveObject.cpp +++ b/src/items/InteractiveObject.cpp @@ -7,7 +7,7 @@ #include #include -namespace ZL { +namespace FRG { extern const std::string textureUniformName; #ifdef EMSCRIPTEN @@ -300,4 +300,4 @@ namespace ZL { } } -} // namespace ZL +} // namespace FRG diff --git a/src/items/InteractiveObject.h b/src/items/InteractiveObject.h index 6a75768..8460f90 100644 --- a/src/items/InteractiveObject.h +++ b/src/items/InteractiveObject.h @@ -8,7 +8,7 @@ #include "render/Renderer.h" #include "InteractiveObjectState.h" -namespace ZL { +namespace FRG { class Renderer; @@ -42,4 +42,4 @@ namespace ZL { void drawDarklands(Renderer& renderer) const; }; -} // namespace ZL +} // namespace FRG diff --git a/src/items/InteractiveObjectState.h b/src/items/InteractiveObjectState.h index c56bba2..521fac1 100644 --- a/src/items/InteractiveObjectState.h +++ b/src/items/InteractiveObjectState.h @@ -7,7 +7,7 @@ #include "external/nlohmann/json.hpp" #include "ISaveable.h" -namespace ZL { +namespace FRG { // Animation task for timed position/rotation/scale/alpha transitions. // Moved here from InteractiveObject so InteractiveObjectState can own it. @@ -75,4 +75,4 @@ public: void load(const nlohmann::json& in) override; }; -} // namespace ZL +} // namespace FRG diff --git a/src/items/Item.cpp b/src/items/Item.cpp index ed4833e..3703f8b 100644 --- a/src/items/Item.cpp +++ b/src/items/Item.cpp @@ -5,7 +5,7 @@ #include #include "../utils/Utils.h" -namespace ZL { +namespace FRG { void Inventory::addItem(const std::string& itemId) { itemIds.push_back(itemId); @@ -54,4 +54,4 @@ namespace ZL { } } -} // namespace ZL \ No newline at end of file +} // namespace FRG \ No newline at end of file diff --git a/src/items/Item.h b/src/items/Item.h index 076e594..0c7f489 100644 --- a/src/items/Item.h +++ b/src/items/Item.h @@ -5,7 +5,7 @@ #include #include "ISaveable.h" -namespace ZL { +namespace FRG { struct Item { std::string id; @@ -42,4 +42,4 @@ namespace ZL { std::vector itemIds; }; -} // namespace ZL \ No newline at end of file +} // namespace FRG \ No newline at end of file diff --git a/src/items/ItemRegistry.cpp b/src/items/ItemRegistry.cpp index 5859b98..7684c40 100644 --- a/src/items/ItemRegistry.cpp +++ b/src/items/ItemRegistry.cpp @@ -4,7 +4,7 @@ #include "external/nlohmann/json.hpp" #include -namespace ZL { +namespace FRG { ItemRegistry& ItemRegistry::instance() { static ItemRegistry reg; @@ -56,4 +56,4 @@ const Item* ItemRegistry::findById(const std::string& id) const { return it != items_.end() ? &it->second : nullptr; } -} // namespace ZL +} // namespace FRG diff --git a/src/items/ItemRegistry.h b/src/items/ItemRegistry.h index 2cdd174..4cb6e4c 100644 --- a/src/items/ItemRegistry.h +++ b/src/items/ItemRegistry.h @@ -3,7 +3,7 @@ #include #include "Item.h" -namespace ZL { +namespace FRG { class ItemRegistry { public: @@ -20,4 +20,4 @@ private: std::unordered_map items_; }; -} // namespace ZL +} // namespace FRG diff --git a/src/main.cpp b/src/main.cpp index a3956d4..7885596 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,20 +16,41 @@ #endif +// Единый указатель на объект игры для всех платформ +FRG::Game* g_game = nullptr; + + #if defined(EMSCRIPTEN) static SDL_GLContext glContext_x; +static bool g_isFsLoaded = false; // Флаг готовности + +// Макрос EMSCRIPTEN_KEEPALIVE экспортирует функцию в глобальный объект Module +extern "C" void EMSCRIPTEN_KEEPALIVE onFileSystemLoaded() { + // 1. Файлы загружены. Теперь можно читать настройки и логи + // Если функции readSettings() нет для Emscripten, форсируем логгер: + FRG::Environment::enableLogging = true; + FRG::initLogger(); + + FRG::logger() << "[boot] File system is ready. Setting up game..." << std::endl; + + // 2. Инициализируем игру ТОЛЬКО когда файлы доступны + g_game = new FRG::Game(); + g_game->setup(); + + // 3. Даем отмашку главному циклу + g_isFsLoaded = true; +} #endif -// Единый указатель на объект игры для всех платформ -ZL::Game* g_game = nullptr; - - void MainLoop() { +#if defined(EMSCRIPTEN) + // Крутим цикл вхолостую, пока JS читает IndexedDB + if (!g_isFsLoaded) return; +#endif + g_game->update(); } - - #ifdef EMSCRIPTEN EM_BOOL onWebGLContextLost(int /*eventType*/, const void* /*reserved*/, void* /*userData*/) { @@ -55,8 +76,8 @@ static void applyResize(int logicalW, int logicalH) { // Сообщаем SDL о новом размере. // ВАЖНО: SDL2 в Emscripten ожидает здесь именно физические пиксели // для корректной работы последующих вызовов glViewport. - if (ZL::Environment::window) { - SDL_SetWindowSize(ZL::Environment::window, physicalW, physicalH); + if (FRG::Environment::window) { + SDL_SetWindowSize(FRG::Environment::window, physicalW, physicalH); } // Пушим событие, чтобы движок пересчитал матрицы проекции @@ -67,7 +88,7 @@ static void applyResize(int logicalW, int logicalH) { e.window.data2 = physicalH; SDL_PushEvent(&e); - logger() << "Resized, new size: " << logicalW << "x" << logicalH + FRG::logger() << "Resized, new size: " << logicalW << "x" << logicalH << " (physical: " << physicalW << "x" << physicalH << ", DPR: " << dpr << ")" << std::endl; } @@ -80,7 +101,7 @@ EM_BOOL onWindowResized(int /*eventType*/, const EmscriptenUiEvent* e, void* /*u } EM_BOOL onFullscreenChanged(int /*eventType*/, const EmscriptenFullscreenChangeEvent* e, void* /*userData*/) { - ZL::Environment::isFullscreen = e->isFullscreen; + FRG::Environment::isFullscreen = e->isFullscreen; // Вместо window.innerWidth, попробуйте запросить размер целевого элемента // так как после перехода в FS именно он растягивается на весь экран. @@ -94,43 +115,32 @@ int main(int argc, char* argv[]) { SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); // Для WebGL 2.0 + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); - ZL::Environment::window = SDL_CreateWindow("Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); - glContext_x = SDL_GL_CreateContext(ZL::Environment::window); + FRG::Environment::window = SDL_CreateWindow("Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); + glContext_x = SDL_GL_CreateContext(FRG::Environment::window); - SDL_GL_MakeCurrent(ZL::Environment::window, glContext_x); - - g_game = new ZL::Game(); - g_game->setup(); + SDL_GL_MakeCurrent(FRG::Environment::window, glContext_x); emscripten_set_webglcontextlost_callback("#canvas", nullptr, EM_TRUE, onWebGLContextLost); emscripten_set_webglcontextrestored_callback("#canvas", nullptr, EM_TRUE, onWebGLContextRestored); - // Keep Environment::width/height in sync when the canvas is resized. emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, nullptr, EM_FALSE, onWindowResized); emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, nullptr, EM_FALSE, onFullscreenChanged); - // 2. ИНИЦИАЛИЗАЦИЯ РАЗМЕРОВ: - // Получаем реальные размеры окна браузера на момент запуска int canvasW = EM_ASM_INT({ return window.innerWidth; }); int canvasH = EM_ASM_INT({ return window.innerHeight; }); - - // Вызываем вашу функцию — она сама применит DPR, выставит физический размер - // канваса и отправит SDL_WINDOWEVENT_RESIZED для настройки проекции. applyResize(canvasW, canvasH); - // Prevent mouse clicks from generating fake SDL_FINGERDOWN events (desktop browser) SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0"); - // Prevent touch events from generating fake SDL_MOUSEBUTTONDOWN events (mobile browser), - // since we now handle SDL_FINGERDOWN directly for multi-touch support. SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0"); - ZL::emscriptenInitFileSystem(); + // Запускаем асинхронное монтирование ФС + FRG::emscriptenInitFileSystem(); + // Начинаем крутить пустой цикл. Он активируется, когда отработает onFileSystemLoaded emscripten_set_main_loop(MainLoop, 0, 1); - return 0; } @@ -152,11 +162,11 @@ extern "C" int SDL_main(int argc, char* argv[]) { SDL_Quit(); return 1; } - ZL::Environment::width = displayMode.w; - ZL::Environment::height = displayMode.h; + FRG::Environment::width = displayMode.w; + FRG::Environment::height = displayMode.h; __android_log_print(ANDROID_LOG_INFO, "Game", "Display resolution: %dx%d", - ZL::Environment::width, ZL::Environment::height); + FRG::Environment::width, FRG::Environment::height); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); @@ -169,31 +179,31 @@ extern "C" int SDL_main(int argc, char* argv[]) { SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - ZL::Environment::window = SDL_CreateWindow( + FRG::Environment::window = SDL_CreateWindow( "Shadow Over Bishkek", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - ZL::Environment::width, ZL::Environment::height, + FRG::Environment::width, FRG::Environment::height, SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN ); - if (!ZL::Environment::window) { + if (!FRG::Environment::window) { __android_log_print(ANDROID_LOG_ERROR, "Game", "Failed to create window: %s", SDL_GetError()); SDL_Quit(); return 1; } - SDL_GLContext ctx = SDL_GL_CreateContext(ZL::Environment::window); + SDL_GLContext ctx = SDL_GL_CreateContext(FRG::Environment::window); if (!ctx) { __android_log_print(ANDROID_LOG_ERROR, "Game", "SDL_GL_CreateContext failed: %s", SDL_GetError()); - SDL_DestroyWindow(ZL::Environment::window); + SDL_DestroyWindow(FRG::Environment::window); SDL_Quit(); return 1; } - if (SDL_GL_MakeCurrent(ZL::Environment::window, ctx) != 0) { + if (SDL_GL_MakeCurrent(FRG::Environment::window, ctx) != 0) { __android_log_print(ANDROID_LOG_ERROR, "Game", "SDL_GL_MakeCurrent failed: %s", SDL_GetError()); SDL_GL_DeleteContext(ctx); - SDL_DestroyWindow(ZL::Environment::window); + SDL_DestroyWindow(FRG::Environment::window); SDL_Quit(); return 1; } @@ -232,20 +242,20 @@ extern "C" int SDL_main(int argc, char* argv[]) { void readSettings() { - const std::string settingsContent = ZL::readSavedTextFile("settings.json"); + const std::string settingsContent = FRG::readSavedTextFile("settings.json"); if (!settingsContent.empty()) { try { const nlohmann::json settingsRoot = nlohmann::json::parse(settingsContent); if (settingsRoot.contains("fullscreen")) { - ZL::Environment::isFullscreen = settingsRoot["fullscreen"].get(); + FRG::Environment::isFullscreen = settingsRoot["fullscreen"].get(); } if (settingsRoot.contains("isHighDPIEnabled")) { - ZL::Environment::isHighDPIEnabled = settingsRoot["isHighDPIEnabled"].get(); + FRG::Environment::isHighDPIEnabled = settingsRoot["isHighDPIEnabled"].get(); } if (settingsRoot.contains("enableLogging")) { - ZL::Environment::enableLogging = settingsRoot["enableLogging"].get(); + FRG::Environment::enableLogging = settingsRoot["enableLogging"].get(); } } @@ -262,12 +272,12 @@ int main(int argc, char* argv[]) { try { readSettings(); - if (ZL::Environment::enableLogging) + if (FRG::Environment::enableLogging) { - ZL::initLogger(); + FRG::initLogger(); } - ZL::logger() << "Log started!" << std::endl; + FRG::logger() << "Log started!" << std::endl; #ifdef STEAMSDK // Передаем явный App ID демо-версии @@ -283,11 +293,11 @@ int main(int argc, char* argv[]) { SDL_SetHint(SDL_HINT_WINDOWS_DPI_AWARENESS, "permonitorv2"); - constexpr int CONST_WIDTH = ZL::Environment::CONST_DEFAULT_WIDTH; - constexpr int CONST_HEIGHT = ZL::Environment::CONST_DEFAULT_HEIGHT; + constexpr int CONST_WIDTH = FRG::Environment::CONST_DEFAULT_WIDTH; + constexpr int CONST_HEIGHT = FRG::Environment::CONST_DEFAULT_HEIGHT; - ZL::Environment::width = CONST_WIDTH; - ZL::Environment::height = CONST_HEIGHT; + FRG::Environment::width = CONST_WIDTH; + FRG::Environment::height = CONST_HEIGHT; if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) { SDL_Log("SDL init failed: %s", SDL_GetError()); return 1; @@ -298,53 +308,53 @@ int main(int argc, char* argv[]) { SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); Uint32 windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE; - if (ZL::Environment::isFullscreen) { + if (FRG::Environment::isFullscreen) { windowFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP; } SDL_DisplayMode dm; if (SDL_GetCurrentDisplayMode(0, &dm) == 0) { - ZL::logger() << "Desktop resolution: " << dm.w << "x" << dm.h << " @ " << dm.refresh_rate << "Hz\n"; + FRG::logger() << "Desktop resolution: " << dm.w << "x" << dm.h << " @ " << dm.refresh_rate << "Hz\n"; } else { SDL_Log("SDL_GetCurrentDisplayMode failed: %s", SDL_GetError()); } - int windowWidth = ZL::Environment::width; - int windowHeight = ZL::Environment::height; + int windowWidth = FRG::Environment::width; + int windowHeight = FRG::Environment::height; if (dm.w <= 1280 && dm.h <= 720) { windowWidth = round(dm.w / 1.5); windowHeight = round(dm.h / 1.5); } - ZL::Environment::window = SDL_CreateWindow( + FRG::Environment::window = SDL_CreateWindow( "Shadow Over Bishkek Demo", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowWidth, windowHeight, windowFlags ); - ctx = SDL_GL_CreateContext(ZL::Environment::window); - SDL_GL_MakeCurrent(ZL::Environment::window, ctx); + ctx = SDL_GL_CreateContext(FRG::Environment::window); + SDL_GL_MakeCurrent(FRG::Environment::window, ctx); - if (ZL::Environment::isHighDPIEnabled) { + if (FRG::Environment::isHighDPIEnabled) { int drawW, drawH; - SDL_GL_GetDrawableSize(ZL::Environment::window, &drawW, &drawH); - ZL::Environment::width = drawW; - ZL::Environment::height = drawH; - ZL::logger() << "HiDPI enabled, drawable size: " << drawW << "x" << drawH << std::endl; + SDL_GL_GetDrawableSize(FRG::Environment::window, &drawW, &drawH); + FRG::Environment::width = drawW; + FRG::Environment::height = drawH; + FRG::logger() << "HiDPI enabled, drawable size: " << drawW << "x" << drawH << std::endl; } else { int winW, winH; - SDL_GetWindowSize(ZL::Environment::window, &winW, &winH); - ZL::Environment::width = winW; - ZL::Environment::height = winH; - ZL::logger() << "HiDPI disabled, window size: " << winW << "x" << winH << std::endl; + SDL_GetWindowSize(FRG::Environment::window, &winW, &winH); + FRG::Environment::width = winW; + FRG::Environment::height = winH; + FRG::logger() << "HiDPI disabled, window size: " << winW << "x" << winH << std::endl; } // Динамическое создание объекта игры - g_game = new ZL::Game(); + g_game = new FRG::Game(); g_game->setup(); while (!g_game->shouldExit()) { @@ -356,10 +366,10 @@ int main(int argc, char* argv[]) { #endif } - //ZL::logger() << "Quitting step 1: " << std::endl; + //FRG::logger() << "Quitting step 1: " << std::endl; // Явное уничтожение объекта игры ДО завершения работы Steamworks delete g_game; - //ZL::logger() << "Quitting step 2: " << std::endl; + //FRG::logger() << "Quitting step 2: " << std::endl; g_game = nullptr; } catch (const std::exception& e) @@ -379,31 +389,31 @@ int main(int argc, char* argv[]) { } } - //ZL::logger() << "Quitting step 3: " << std::endl; + //FRG::logger() << "Quitting step 3: " << std::endl; #ifdef STEAMSDK // Деинициализация Steamworks происходит только тогда, когда все объекты игры гарантированно уничтожены SteamAPI_Shutdown(); #endif - //ZL::logger() << "Quitting step 4: " << std::endl; + //FRG::logger() << "Quitting step 4: " << std::endl; // Очистка ресурсов SDL if (ctx) { - //ZL::logger() << "Quitting step 5: " << std::endl; + //FRG::logger() << "Quitting step 5: " << std::endl; SDL_GL_DeleteContext(ctx); } - //ZL::logger() << "Quitting step 6: " << std::endl; - if (ZL::Environment::window) { - //ZL::logger() << "Quitting step 7: " << std::endl; - SDL_DestroyWindow(ZL::Environment::window); + //FRG::logger() << "Quitting step 6: " << std::endl; + if (FRG::Environment::window) { + //FRG::logger() << "Quitting step 7: " << std::endl; + SDL_DestroyWindow(FRG::Environment::window); } - //ZL::logger() << "Quitting step 8: " << std::endl; + //FRG::logger() << "Quitting step 8: " << std::endl; #ifndef EMSCRIPTEN // In Emscripten, SDL must stay alive across context loss/restore cycles // so the window remains valid when the game object is re-created. SDL_Quit(); #endif - //ZL::logger() << "Quitting step 9: " << std::endl; + //FRG::logger() << "Quitting step 9: " << std::endl; return 0; } #endif diff --git a/src/navigation/PathFinder.cpp b/src/navigation/PathFinder.cpp index 770f3a3..c54f8e7 100644 --- a/src/navigation/PathFinder.cpp +++ b/src/navigation/PathFinder.cpp @@ -9,7 +9,7 @@ #include #include -namespace ZL { +namespace FRG { using json = nlohmann::json; @@ -1075,4 +1075,4 @@ bool PathFinder::pointInPolygon(float x, float z, const std::vector #include -namespace ZL { +namespace FRG { class PathFinder { public: @@ -111,4 +111,4 @@ private: const std::vector& walkableGrid) const; }; -} // namespace ZL +} // namespace FRG diff --git a/src/quest/QuestJournal.cpp b/src/quest/QuestJournal.cpp index 76fe7b7..8249aae 100644 --- a/src/quest/QuestJournal.cpp +++ b/src/quest/QuestJournal.cpp @@ -5,7 +5,7 @@ #include #include -namespace ZL::Quest { +namespace FRG::Quest { using json = nlohmann::json; @@ -27,7 +27,7 @@ static QuestStatus parseQuestStatus(const std::string& value) { } bool QuestJournal::loadFromFile(const std::string& path, const std::string& zipFile) { - const std::string content = ZL::readLocalizedConfigFile(path, zipFile); + const std::string content = FRG::readLocalizedConfigFile(path, zipFile); if (content.empty()) { std::cerr << "[quest] Failed to read " << path << std::endl; return false; @@ -260,4 +260,4 @@ void QuestJournal::load(const nlohmann::json& in) { } } -} // namespace ZL::Quest +} // namespace FRG::Quest diff --git a/src/quest/QuestJournal.h b/src/quest/QuestJournal.h index aff62fc..d086325 100644 --- a/src/quest/QuestJournal.h +++ b/src/quest/QuestJournal.h @@ -8,9 +8,9 @@ #include #include -namespace ZL::Quest { +namespace FRG::Quest { -class QuestJournal : public ZL::ISaveable { +class QuestJournal : public FRG::ISaveable { public: bool loadFromFile(const std::string& path, const std::string& zipFile = ""); @@ -49,4 +49,4 @@ private: bool setStatus(const std::string& questId, QuestStatus status); }; -} // namespace ZL::Quest +} // namespace FRG::Quest diff --git a/src/quest/QuestTypes.h b/src/quest/QuestTypes.h index 2d80f69..72d8dfe 100644 --- a/src/quest/QuestTypes.h +++ b/src/quest/QuestTypes.h @@ -3,7 +3,7 @@ #include #include -namespace ZL::Quest { +namespace FRG::Quest { enum class QuestStatus { Hidden, @@ -37,4 +37,4 @@ struct QuestState { const char* toString(QuestStatus status); -} // namespace ZL::Quest +} // namespace FRG::Quest diff --git a/src/render/FrameBuffer.cpp b/src/render/FrameBuffer.cpp index 74d17a1..5cac018 100644 --- a/src/render/FrameBuffer.cpp +++ b/src/render/FrameBuffer.cpp @@ -2,7 +2,7 @@ #include #include "Environment.h" -namespace ZL { +namespace FRG { FrameBuffer::FrameBuffer(int w, int h, bool useMipmaps) : width(w), height(h), useMipmaps(useMipmaps) { @@ -59,4 +59,4 @@ namespace ZL { glViewport(0, 0, Environment::width, Environment::height); } -} // namespace ZL \ No newline at end of file +} // namespace FRG \ No newline at end of file diff --git a/src/render/FrameBuffer.h b/src/render/FrameBuffer.h index 3d53d27..0aebe58 100644 --- a/src/render/FrameBuffer.h +++ b/src/render/FrameBuffer.h @@ -2,7 +2,7 @@ #include "render/OpenGlExtensions.h" #include -namespace ZL { +namespace FRG { class FrameBuffer { private: @@ -28,4 +28,4 @@ namespace ZL { int getHeight() const { return height; } }; -} // namespace ZL \ No newline at end of file +} // namespace FRG \ No newline at end of file diff --git a/src/render/OpenGlExtensions.cpp b/src/render/OpenGlExtensions.cpp index 01fef02..8c205e9 100644 --- a/src/render/OpenGlExtensions.cpp +++ b/src/render/OpenGlExtensions.cpp @@ -117,7 +117,7 @@ PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArray = NULL; #endif -namespace ZL { +namespace FRG { bool BindOpenGlFunctions() { diff --git a/src/render/OpenGlExtensions.h b/src/render/OpenGlExtensions.h index af73844..ddb56c1 100644 --- a/src/render/OpenGlExtensions.h +++ b/src/render/OpenGlExtensions.h @@ -154,7 +154,7 @@ extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArray; #else #endif -namespace ZL { +namespace FRG { diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index af7aead..bfa9e7f 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1,7 +1,7 @@ #include "render/Renderer.h" #include -namespace ZL { +namespace FRG { Matrix4f MakeOrthoMatrix(float width, float height, float zNear, float zFar) { diff --git a/src/render/Renderer.h b/src/render/Renderer.h index 8988db9..f8fde32 100644 --- a/src/render/Renderer.h +++ b/src/render/Renderer.h @@ -8,7 +8,7 @@ #include "TextureManager.h" #include -namespace ZL { +namespace FRG { using Eigen::Vector2f; using Eigen::Vector3f; diff --git a/src/render/ShaderManager.cpp b/src/render/ShaderManager.cpp index 3f6b633..15920a6 100644 --- a/src/render/ShaderManager.cpp +++ b/src/render/ShaderManager.cpp @@ -6,7 +6,7 @@ #include #endif -namespace ZL { +namespace FRG { ShaderResource::ShaderResource(const std::string &vertexCode, const std::string &fragmentCode) { diff --git a/src/render/ShaderManager.h b/src/render/ShaderManager.h index c30b420..9f855c3 100644 --- a/src/render/ShaderManager.h +++ b/src/render/ShaderManager.h @@ -3,7 +3,7 @@ #include "render/OpenGlExtensions.h" #include "utils/Utils.h" -namespace ZL { +namespace FRG { constexpr size_t CONST_MAX_SHADER_STACK_SIZE = 16; diff --git a/src/render/ShadowMap.cpp b/src/render/ShadowMap.cpp index 69b2477..df5e756 100644 --- a/src/render/ShadowMap.cpp +++ b/src/render/ShadowMap.cpp @@ -3,7 +3,7 @@ #include #include -namespace ZL { +namespace FRG { // Build a look-at view matrix (column-major, same convention as the engine). static Eigen::Matrix4f lookAt(const Eigen::Vector3f& eye, @@ -167,4 +167,4 @@ namespace ZL { glViewport(0, 0, Environment::width, Environment::height); } -} // namespace ZL +} // namespace FRG diff --git a/src/render/ShadowMap.h b/src/render/ShadowMap.h index 8259b16..1037618 100644 --- a/src/render/ShadowMap.h +++ b/src/render/ShadowMap.h @@ -2,7 +2,7 @@ #include "render/OpenGlExtensions.h" #include -namespace ZL { +namespace FRG { class ShadowMap { private: @@ -44,4 +44,4 @@ namespace ZL { const Eigen::Vector3f& getLightDirection() const { return lightDirection; } }; -} // namespace ZL +} // namespace FRG diff --git a/src/render/TextRenderer.cpp b/src/render/TextRenderer.cpp index bac8dc5..58644c0 100644 --- a/src/render/TextRenderer.cpp +++ b/src/render/TextRenderer.cpp @@ -10,7 +10,7 @@ #include #include -namespace ZL { +namespace FRG { struct GlyphAtlasData { std::unordered_map glyphs; @@ -71,13 +71,13 @@ bool TextRenderer::init(Renderer& renderer, const std::string& ttfPath, int pixe #endif } - ZL::CheckGlError(__FILE__, __LINE__); + FRG::CheckGlError(__FILE__, __LINE__); if (!loadGlyphs(ttfPath, pixelSize, zipfilename)) return false; - ZL::CheckGlError(__FILE__, __LINE__); + FRG::CheckGlError(__FILE__, __LINE__); textMesh.data.PositionData.resize(6, Eigen::Vector3f(0, 0, 0)); textMesh.RefreshVBO(); - ZL::CheckGlError(__FILE__, __LINE__); + FRG::CheckGlError(__FILE__, __LINE__); return true; } @@ -515,4 +515,4 @@ void TextRenderer::drawText(const std::string& text, float x, float y, float sca // Сброс бинда текстуры не обязателен, но можно для чистоты glBindTexture(GL_TEXTURE_2D, 0); } -} // namespace ZL \ No newline at end of file +} // namespace FRG \ No newline at end of file diff --git a/src/render/TextRenderer.h b/src/render/TextRenderer.h index 29d7d68..43f3d37 100644 --- a/src/render/TextRenderer.h +++ b/src/render/TextRenderer.h @@ -9,7 +9,7 @@ #include -namespace ZL { +namespace FRG { struct GlyphInfo { Eigen::Vector2f uv; // u,v координата левого верхнего угла в атласе (0..1) @@ -62,4 +62,4 @@ private: std::unordered_map cache; }; -} // namespace ZL \ No newline at end of file +} // namespace FRG \ No newline at end of file diff --git a/src/render/TextureManager.cpp b/src/render/TextureManager.cpp index 2af13b7..f7f30cd 100644 --- a/src/render/TextureManager.cpp +++ b/src/render/TextureManager.cpp @@ -5,7 +5,7 @@ #endif #include -namespace ZL +namespace FRG { #ifdef EMSCRIPTEN using std::min; diff --git a/src/render/TextureManager.h b/src/render/TextureManager.h index 5230760..7f641ff 100644 --- a/src/render/TextureManager.h +++ b/src/render/TextureManager.h @@ -9,7 +9,7 @@ #define PNG_ENABLED #endif -namespace ZL +namespace FRG { struct TextureDataStruct { diff --git a/src/render/UiQuad.h b/src/render/UiQuad.h index 7ea5b80..20737d4 100644 --- a/src/render/UiQuad.h +++ b/src/render/UiQuad.h @@ -4,7 +4,7 @@ #include "UiManager.h" #include -namespace ZL +namespace FRG { // Axis-aligned textured quad with cached mesh. Rebuild only when rect changes. struct UiQuad { diff --git a/src/utils/TaskManager.cpp b/src/utils/TaskManager.cpp index 5670795..41b9dc6 100644 --- a/src/utils/TaskManager.cpp +++ b/src/utils/TaskManager.cpp @@ -1,7 +1,7 @@ #include "TaskManager.h" -namespace ZL +namespace FRG { TaskManager::TaskManager(size_t threadCount) { diff --git a/src/utils/TaskManager.h b/src/utils/TaskManager.h index 4ea1f08..daaa162 100644 --- a/src/utils/TaskManager.h +++ b/src/utils/TaskManager.h @@ -11,7 +11,7 @@ #include -namespace ZL { +namespace FRG { class TaskManager { private: @@ -53,4 +53,4 @@ namespace ZL { void processMainThreadTasks(); }; -} // namespace ZL \ No newline at end of file +} // namespace FRG \ No newline at end of file diff --git a/src/utils/Utils.cpp b/src/utils/Utils.cpp index 642a97f..d66376a 100644 --- a/src/utils/Utils.cpp +++ b/src/utils/Utils.cpp @@ -24,7 +24,7 @@ #include #endif -namespace ZL +namespace FRG { std::string readTextFile(const std::string& filename) { #ifdef __ANDROID__ @@ -326,25 +326,25 @@ namespace ZL void emscriptenInitFileSystem() { #if defined(__EMSCRIPTEN__) - // 1. Создаем точку монтирования в памяти + namespace fs = std::filesystem; fs::create_directories("/offline"); - // 2. Монтируем IDBFS в эту точку EM_ASM({ FS.mount(IDBFS, {}, '/offline'); - // 3. Синхронизируем из IndexedDB в VFS (true = из IDB в память) - // Этот вызов асинхронный. Настройки станут доступны только после его завершения. - FS.syncfs(true, function(err) { - if (err) { - console.error("Error loading filesystem from IndexedDB:", err); - } + FS.syncfs(true, function(err) { + if (err) { + console.error("Error loading filesystem from IndexedDB:", err); + } else { - console.log("IndexedDB successfully synced to VFS."); - // Здесь при необходимости можно вызвать коллбэк в C++ - // для отложенной загрузки файла настроек, если это критично. - } - }); + console.log("IndexedDB successfully synced to VFS."); +} + + // Вызываем экспортированную C-функцию + if (Module._onFileSystemLoaded) { + Module._onFileSystemLoaded(); + } + }); }); #endif } @@ -384,12 +384,16 @@ namespace ZL TeeBuffer(std::streambuf* sb1, std::streambuf* sb2) : out1(sb1), out2(sb2) {} }; + // --- Глобальные переменные логгера --- namespace { std::ofstream g_logFile; std::unique_ptr g_teeBuffer; std::unique_ptr g_teeStream; - NullStream g_nullStream; + + // Решение проблемы UB: буфер создается ДО потока + NullBuffer g_nullBuffer; + std::ostream g_nullStream(&g_nullBuffer); } // --- Инициализация логгера --- diff --git a/src/utils/Utils.h b/src/utils/Utils.h index 9a2fbe5..be698cd 100644 --- a/src/utils/Utils.h +++ b/src/utils/Utils.h @@ -15,7 +15,7 @@ #include #include "external/nlohmann/json.hpp" -namespace ZL +namespace FRG { std::string readTextFile(const std::string& filename);