Adapted for web
This commit is contained in:
commit
3fe21230cc
20 files changed
+240
-71
No files matched your search
@@ -135,17 +135,19 @@ excluded from the diagnostic deterministic hash.
|
|||||||
|
|
||||||
## Build Configuration
|
## Build Configuration
|
||||||
|
|
||||||
Networking is enabled only for Windows:
|
Networking is enabled for Windows and the Emscripten web client:
|
||||||
|
|
||||||
- `proj-windows/CMakeLists.txt` defines `NETWORK`, compiles the WebSocket client
|
- `proj-windows/CMakeLists.txt` defines `NETWORK`, compiles the WebSocket client
|
||||||
and remote host, and links `ws2_32` and `mswsock`.
|
and remote host, and links `ws2_32` and `mswsock`.
|
||||||
- `server/CMakeLists.txt` defines `NETWORK` for the Windows `GameServer`, compiles
|
- `server/CMakeLists.txt` defines `NETWORK` for the Windows `GameServer`, compiles
|
||||||
the WebSocket server, and links the Windows socket libraries.
|
the WebSocket server, and links the Windows socket libraries.
|
||||||
- Linux, Android, and Web builds do not define `NETWORK` and do not compile the
|
- `proj-web/CMakeLists.txt` defines `NETWORK`, compiles the shared protocol,
|
||||||
|
replica, and remote-host code, and links Emscripten's `websocket.js` library.
|
||||||
|
`WebsocketGameClient.cpp` selects the browser WebSocket API on Emscripten; it
|
||||||
|
does not use Boost.Asio or Boost.Beast there.
|
||||||
|
- Linux and Android builds do not define `NETWORK` and do not compile the
|
||||||
network transport.
|
network transport.
|
||||||
|
|
||||||
The previous Web-build `NETWORK` definition was removed.
|
|
||||||
|
|
||||||
## Running
|
## Running
|
||||||
|
|
||||||
Build the server:
|
Build the server:
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
--- a/include/sol/optional_implementation.hpp
|
--- a/include/sol/optional_implementation.hpp
|
||||||
+++ b/include/sol/optional_implementation.hpp
|
+++ b/include/sol/optional_implementation.hpp
|
||||||
@@ -2189,7 +2189,10 @@
|
@@ -2191,8 +2191,10 @@ namespace sol {
|
||||||
template <class... Args>
|
|
||||||
T& emplace(Args&&... args) noexcept {
|
|
||||||
static_assert(std::is_constructible<T, Args&&...>::value, "T must be constructible with Args");
|
static_assert(std::is_constructible<T, Args&&...>::value, "T must be constructible with Args");
|
||||||
|
|
||||||
*this = nullopt;
|
*this = nullopt;
|
||||||
- this->construct(std::forward<Args>(args)...);
|
- this->construct(std::forward<Args>(args)...);
|
||||||
|
- return value();
|
||||||
+ // Reference specialization stores a pointer; set it directly.
|
+ // Reference specialization stores a pointer; set it directly.
|
||||||
+ // construct() only exists in the non-reference specialization.
|
+ // construct() only exists in the non-reference specialization.
|
||||||
+ m_value = std::addressof(std::forward<Args>(args)...);
|
+ m_value = std::addressof(std::forward<Args>(args)...);
|
||||||
+ return *m_value;
|
+ return *m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Swaps this optional with the other.
|
||||||
@@ -125,11 +125,23 @@ set(SOURCES
|
|||||||
../src/GameConstants.cpp
|
../src/GameConstants.cpp
|
||||||
../src/GameState.h
|
../src/GameState.h
|
||||||
../src/GameState.cpp
|
../src/GameState.cpp
|
||||||
|
../src/content/LocationDefinition.h
|
||||||
../src/content/LocationDefinition.cpp
|
../src/content/LocationDefinition.cpp
|
||||||
../src/game_server/IGameServer.h
|
../src/game_server/IGameServer.h
|
||||||
|
../src/game_server/IGameServerLifecycle.h
|
||||||
|
../src/game_server/IGameServerHost.h
|
||||||
|
../src/game_server/GameServerRouter.h
|
||||||
|
../src/game_server/GameServerHostRouter.h
|
||||||
../src/game_server/InternalGameServer.h
|
../src/game_server/InternalGameServer.h
|
||||||
../src/game_server/InternalGameServer.cpp
|
../src/game_server/InternalGameServer.cpp
|
||||||
|
../src/game_server/LocalGameServerHost.h
|
||||||
../src/game_server/LocalGameServerHost.cpp
|
../src/game_server/LocalGameServerHost.cpp
|
||||||
|
../src/game_server/NetworkProtocol.h
|
||||||
|
../src/game_server/NetworkProtocol.cpp
|
||||||
|
../src/game_server/WebsocketGameClient.h
|
||||||
|
../src/game_server/WebsocketGameClient.cpp
|
||||||
|
../src/game_server/RemoteGameServerHost.h
|
||||||
|
../src/game_server/RemoteGameServerHost.cpp
|
||||||
../src/ScriptEngine.h
|
../src/ScriptEngine.h
|
||||||
../src/ScriptEngine.cpp
|
../src/ScriptEngine.cpp
|
||||||
../src/navigation/PathFinder.h
|
../src/navigation/PathFinder.h
|
||||||
@@ -172,6 +184,8 @@ set(SOURCES
|
|||||||
|
|
||||||
add_executable(ShadowOverBishkekDemo ${SOURCES})
|
add_executable(ShadowOverBishkekDemo ${SOURCES})
|
||||||
|
|
||||||
|
target_compile_definitions(ShadowOverBishkekDemo PRIVATE NETWORK)
|
||||||
|
|
||||||
# Настройка путей к инклудам (используем скачанные исходники)
|
# Настройка путей к инклудам (используем скачанные исходники)
|
||||||
target_include_directories(ShadowOverBishkekDemo PRIVATE
|
target_include_directories(ShadowOverBishkekDemo PRIVATE
|
||||||
../src
|
../src
|
||||||
@@ -181,6 +195,16 @@ target_include_directories(ShadowOverBishkekDemo PRIVATE
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Сборка libzip через add_subdirectory (Emscripten соберет её из исходников)
|
# Сборка libzip через add_subdirectory (Emscripten соберет её из исходников)
|
||||||
|
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(BUILD_DOC OFF CACHE BOOL "" FORCE)
|
||||||
|
set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
|
||||||
|
set(BUILD_OSSFUZZ OFF CACHE BOOL "" FORCE)
|
||||||
|
set(BUILD_REGRESS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(BUILD_TOOLS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(ENABLE_BZIP2 OFF CACHE BOOL "" FORCE)
|
||||||
|
set(ENABLE_LZMA OFF CACHE BOOL "" FORCE)
|
||||||
|
set(ENABLE_MBEDTLS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(ENABLE_ZSTD OFF CACHE BOOL "" FORCE)
|
||||||
set(ENABLE_GNUTLS OFF CACHE BOOL "" FORCE)
|
set(ENABLE_GNUTLS OFF CACHE BOOL "" FORCE)
|
||||||
set(ENABLE_OPENSSL OFF CACHE BOOL "" FORCE)
|
set(ENABLE_OPENSSL OFF CACHE BOOL "" FORCE)
|
||||||
set(ENABLE_WINDOWS_CRYPTO OFF CACHE BOOL "" FORCE)
|
set(ENABLE_WINDOWS_CRYPTO OFF CACHE BOOL "" FORCE)
|
||||||
@@ -222,6 +246,7 @@ set(EMSCRIPTEN_LINK_FLAGS
|
|||||||
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start_uni_interior.lua@resources/start_uni_interior.lua"
|
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start_uni_interior.lua@resources/start_uni_interior.lua"
|
||||||
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start_uni_exterior.lua@resources/start_uni_exterior.lua"
|
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start_uni_exterior.lua@resources/start_uni_exterior.lua"
|
||||||
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start_dorm.lua@resources/start_dorm.lua"
|
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start_dorm.lua@resources/start_dorm.lua"
|
||||||
|
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start_dorm.lua@resources/start_battle_zone.lua"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Применяем настройки линковки
|
# Применяем настройки линковки
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "BoneAnimatedModelNew.h"
|
#include "BoneAnimatedModelNew.h"
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
namespace FRG
|
namespace FRG
|
||||||
{
|
{
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef __EMSCRIPTEN__
|
||||||
using std::min;
|
using std::min;
|
||||||
using std::max;
|
using std::max;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+4
-4
@@ -1,4 +1,4 @@
|
|||||||
#include "Environment.h"
|
#include "Environment.h"
|
||||||
|
|
||||||
#include "utils/Utils.h"
|
#include "utils/Utils.h"
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
#include <GL/gl.h>
|
#include <GL/gl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef __EMSCRIPTEN__
|
||||||
#include <emscripten/html5.h>
|
#include <emscripten/html5.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ bool Environment::enableLogging = true;
|
|||||||
|
|
||||||
SDL_Window* Environment::window = nullptr;
|
SDL_Window* Environment::window = nullptr;
|
||||||
|
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef __EMSCRIPTEN__
|
||||||
bool Environment::isFullscreen = false;
|
bool Environment::isFullscreen = false;
|
||||||
#else
|
#else
|
||||||
bool Environment::isFullscreen = true;
|
bool Environment::isFullscreen = true;
|
||||||
@@ -71,7 +71,7 @@ void Environment::computeProjectionDimensions()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Environment::setFullscreen(bool enable) {
|
void Environment::setFullscreen(bool enable) {
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef __EMSCRIPTEN__
|
||||||
if (enable) {
|
if (enable) {
|
||||||
EmscriptenFullscreenStrategy strategy{};
|
EmscriptenFullscreenStrategy strategy{};
|
||||||
strategy.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH;
|
strategy.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH;
|
||||||
|
|||||||
+2
-2
@@ -1,4 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
namespace FRG {
|
namespace FRG {
|
||||||
|
|
||||||
|
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef __EMSCRIPTEN__
|
||||||
using std::min;
|
using std::min;
|
||||||
using std::max;
|
using std::max;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+7
-7
@@ -20,7 +20,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef __EMSCRIPTEN__
|
||||||
#include <emscripten.h>
|
#include <emscripten.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ namespace FRG
|
|||||||
static const float zoomMax = 20.0f;
|
static const float zoomMax = 20.0f;
|
||||||
|
|
||||||
|
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef __EMSCRIPTEN__
|
||||||
const char* CONST_ZIP_FILE = "resources.zip";
|
const char* CONST_ZIP_FILE = "resources.zip";
|
||||||
const char* CONST_MUSIC_ZIP_FILE = "music.zip";
|
const char* CONST_MUSIC_ZIP_FILE = "music.zip";
|
||||||
#else
|
#else
|
||||||
@@ -49,7 +49,7 @@ namespace FRG
|
|||||||
float y = 0;
|
float y = 0;
|
||||||
float z = 0;
|
float z = 0;
|
||||||
|
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef __EMSCRIPTEN__
|
||||||
Game* Game::s_instance = nullptr;
|
Game* Game::s_instance = nullptr;
|
||||||
|
|
||||||
// Коллбэк успешной загрузки resources.zip
|
// Коллбэк успешной загрузки resources.zip
|
||||||
@@ -109,7 +109,7 @@ namespace FRG
|
|||||||
renderer.InitOpenGL();
|
renderer.InitOpenGL();
|
||||||
//logger() << "Android test step 1 " << std::endl;
|
//logger() << "Android test step 1 " << std::endl;
|
||||||
|
|
||||||
#if defined(EMSCRIPTEN) || defined(__ANDROID__)
|
#if defined(__EMSCRIPTEN__) || defined(__ANDROID__)
|
||||||
// These shaders and loading.png are preloaded separately (not from zip),
|
// These shaders and loading.png are preloaded separately (not from zip),
|
||||||
// so they are available immediately without waiting for resources.zip.
|
// so they are available immediately without waiting for resources.zip.
|
||||||
//logger() << "Android test step 1 " << std::endl;
|
//logger() << "Android test step 1 " << std::endl;
|
||||||
@@ -149,7 +149,7 @@ namespace FRG
|
|||||||
loadingMesh.data = CreateRect2D({ 0.0f, 0.0f }, { minDimension * 0.5f, minDimension * 0.5f }, 3);
|
loadingMesh.data = CreateRect2D({ 0.0f, 0.0f }, { minDimension * 0.5f, minDimension * 0.5f }, 3);
|
||||||
loadingMesh.RefreshVBO();
|
loadingMesh.RefreshVBO();
|
||||||
|
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef __EMSCRIPTEN__
|
||||||
s_instance = this;
|
s_instance = this;
|
||||||
|
|
||||||
std::string resPath = FRG::getPersistentResourcePath("resources.zip");
|
std::string resPath = FRG::getPersistentResourcePath("resources.zip");
|
||||||
@@ -168,7 +168,7 @@ namespace FRG
|
|||||||
|
|
||||||
// Скачиваем сразу в постоянный путь /offline/resources.zip
|
// Скачиваем сразу в постоянный путь /offline/resources.zip
|
||||||
emscripten_async_wget2(
|
emscripten_async_wget2(
|
||||||
"resources.zip", // URL на сервере
|
"resources.zip?v=2", // Cache-bust stale browser responses after resource updates
|
||||||
resPath.c_str(), // Назначение в VFS Emscripten
|
resPath.c_str(), // Назначение в VFS Emscripten
|
||||||
"GET",
|
"GET",
|
||||||
nullptr,
|
nullptr,
|
||||||
@@ -223,7 +223,7 @@ namespace FRG
|
|||||||
loadSteps.push([this]() {
|
loadSteps.push([this]() {
|
||||||
|
|
||||||
|
|
||||||
#if defined(EMSCRIPTEN) || defined(__ANDROID__)
|
#if defined(__EMSCRIPTEN__) || defined(__ANDROID__)
|
||||||
renderer.shaderManager.AddShaderFromFiles("env_sky", "resources/shaders/env_sky.vertex", "resources/shaders/env_sky_web.fragment", CONST_ZIP_FILE);
|
renderer.shaderManager.AddShaderFromFiles("env_sky", "resources/shaders/env_sky.vertex", "resources/shaders/env_sky_web.fragment", CONST_ZIP_FILE);
|
||||||
renderer.shaderManager.AddShaderFromFiles("defaultAtmosphere", "resources/shaders/defaultAtmosphere.vertex", "resources/shaders/defaultAtmosphere_web.fragment", CONST_ZIP_FILE);
|
renderer.shaderManager.AddShaderFromFiles("defaultAtmosphere", "resources/shaders/defaultAtmosphere.vertex", "resources/shaders/defaultAtmosphere_web.fragment", CONST_ZIP_FILE);
|
||||||
renderer.shaderManager.AddShaderFromFiles("planetBake", "resources/shaders/planet_bake.vertex", "resources/shaders/planet_bake_web.fragment", CONST_ZIP_FILE);
|
renderer.shaderManager.AddShaderFromFiles("planetBake", "resources/shaders/planet_bake.vertex", "resources/shaders/planet_bake_web.fragment", CONST_ZIP_FILE);
|
||||||
|
|||||||
+3
-3
@@ -1,4 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "Character.h"
|
#include "Character.h"
|
||||||
#include "render/Renderer.h"
|
#include "render/Renderer.h"
|
||||||
#include "Environment.h"
|
#include "Environment.h"
|
||||||
@@ -106,7 +106,7 @@ namespace FRG {
|
|||||||
|
|
||||||
MenuManager menuManager;
|
MenuManager menuManager;
|
||||||
|
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef __EMSCRIPTEN__
|
||||||
static Game* s_instance;
|
static Game* s_instance;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -212,7 +212,7 @@ namespace FRG {
|
|||||||
void endPinch();
|
void endPinch();
|
||||||
int countNonUiPointers() const;
|
int countNonUiPointers() const;
|
||||||
|
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef __EMSCRIPTEN__
|
||||||
static void onResourcesZipLoaded(unsigned handle, void* userData, const char* filename);
|
static void onResourcesZipLoaded(unsigned handle, void* userData, const char* filename);
|
||||||
static void onResourcesZipError(unsigned handle, void* userData, int httpStatus);
|
static void onResourcesZipError(unsigned handle, void* userData, int httpStatus);
|
||||||
static void onResourcesZipProgress(unsigned handle, void* userData, int percentComplete);
|
static void onResourcesZipProgress(unsigned handle, void* userData, int percentComplete);
|
||||||
|
|||||||
+4
-4
@@ -1,4 +1,4 @@
|
|||||||
#include "MenuManager.h"
|
#include "MenuManager.h"
|
||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
#include "Localization.h"
|
#include "Localization.h"
|
||||||
#include "items/ItemRegistry.h"
|
#include "items/ItemRegistry.h"
|
||||||
@@ -537,7 +537,7 @@ namespace FRG {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if !defined(EMSCRIPTEN) && !defined(__ANDROID__)
|
#if !defined(__EMSCRIPTEN__) && !defined(__ANDROID__)
|
||||||
uiManager.setTextButtonCallback("menuExitButton", [this](const std::string&) {
|
uiManager.setTextButtonCallback("menuExitButton", [this](const std::string&) {
|
||||||
audioPlayer_.playSoundAsync("resources/audio/751089__smallconfusion__mechanical-plastic-click-11.ogg");
|
audioPlayer_.playSoundAsync("resources/audio/751089__smallconfusion__mechanical-plastic-click-11.ogg");
|
||||||
Environment::exitGameLoop = true;
|
Environment::exitGameLoop = true;
|
||||||
@@ -587,7 +587,7 @@ namespace FRG {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef EMSCRIPTEN
|
#ifndef __EMSCRIPTEN__
|
||||||
uiManager.setTextButtonCallback("menuExitButton", [this](const std::string&) {
|
uiManager.setTextButtonCallback("menuExitButton", [this](const std::string&) {
|
||||||
audioPlayer_.playSoundAsync("resources/audio/751089__smallconfusion__mechanical-plastic-click-11.ogg");
|
audioPlayer_.playSoundAsync("resources/audio/751089__smallconfusion__mechanical-plastic-click-11.ogg");
|
||||||
Environment::exitGameLoop = true;
|
Environment::exitGameLoop = true;
|
||||||
@@ -2441,7 +2441,7 @@ namespace FRG {
|
|||||||
if (root.contains("soundEnabled"))
|
if (root.contains("soundEnabled"))
|
||||||
audioPlayer_.setSoundEnabled(root["soundEnabled"].get<bool>());
|
audioPlayer_.setSoundEnabled(root["soundEnabled"].get<bool>());
|
||||||
if (root.contains("fullscreen")) {
|
if (root.contains("fullscreen")) {
|
||||||
#ifndef EMSCRIPTEN
|
#ifndef __EMSCRIPTEN__
|
||||||
Environment::setFullscreen(root["fullscreen"].get<bool>());
|
Environment::setFullscreen(root["fullscreen"].get<bool>());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
#include "WebsocketGameClient.h"
|
#include "WebsocketGameClient.h"
|
||||||
#include "NetworkProtocol.h"
|
#include "NetworkProtocol.h"
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
#include <emscripten/websocket.h>
|
||||||
|
#else
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <boost/beast.hpp>
|
#include <boost/beast.hpp>
|
||||||
|
#endif
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -14,15 +18,131 @@
|
|||||||
namespace FRG {
|
namespace FRG {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
namespace asio = boost::asio;
|
namespace asio = boost::asio;
|
||||||
namespace beast = boost::beast;
|
namespace beast = boost::beast;
|
||||||
namespace websocket = beast::websocket;
|
namespace websocket = beast::websocket;
|
||||||
using tcp = asio::ip::tcp;
|
using tcp = asio::ip::tcp;
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
class WebsocketGameClient::Impl {
|
class WebsocketGameClient::Impl {
|
||||||
public:
|
public:
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
Impl(std::string host, std::string port, std::string path)
|
||||||
|
: host_(std::move(host))
|
||||||
|
, port_(std::move(port))
|
||||||
|
, path_(std::move(path))
|
||||||
|
{
|
||||||
|
url_ = "ws://" + host_ + ':' + port_ +
|
||||||
|
(path_.empty() || path_.front() == '/' ? path_ : "/" + path_);
|
||||||
|
std::cout << "[network] Opening " << url_ << std::endl;
|
||||||
|
|
||||||
|
EmscriptenWebSocketCreateAttributes attributes = {};
|
||||||
|
attributes.url = url_.c_str();
|
||||||
|
attributes.protocols = nullptr;
|
||||||
|
attributes.createOnMainThread = EM_TRUE;
|
||||||
|
socket_ = emscripten_websocket_new(&attributes);
|
||||||
|
if (socket_ <= 0) {
|
||||||
|
fail("create WebSocket");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emscripten_websocket_set_onopen_callback(
|
||||||
|
socket_, this, &Impl::onOpen);
|
||||||
|
emscripten_websocket_set_onerror_callback(
|
||||||
|
socket_, this, &Impl::onError);
|
||||||
|
emscripten_websocket_set_onclose_callback(
|
||||||
|
socket_, this, &Impl::onClose);
|
||||||
|
emscripten_websocket_set_onmessage_callback(
|
||||||
|
socket_, this, &Impl::onMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Impl()
|
||||||
|
{
|
||||||
|
if (socket_ > 0) {
|
||||||
|
closing_ = true;
|
||||||
|
emscripten_websocket_close(socket_, 1000, "client shutdown");
|
||||||
|
emscripten_websocket_delete(socket_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> takeMessages()
|
||||||
|
{
|
||||||
|
std::vector<std::string> result;
|
||||||
|
result.swap(messages_);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool connected() const { return connected_; }
|
||||||
|
bool connectionFailed() const { return connectionFailed_; }
|
||||||
|
|
||||||
|
void send(std::string message)
|
||||||
|
{
|
||||||
|
if (!connected_ || socket_ <= 0) return;
|
||||||
|
const EMSCRIPTEN_RESULT result =
|
||||||
|
emscripten_websocket_send_utf8_text(socket_, message.c_str());
|
||||||
|
if (result != EMSCRIPTEN_RESULT_SUCCESS)
|
||||||
|
fail("send WebSocket message");
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static EM_BOOL onOpen(
|
||||||
|
int, const EmscriptenWebSocketOpenEvent*, void* userData)
|
||||||
|
{
|
||||||
|
auto* self = static_cast<Impl*>(userData);
|
||||||
|
self->connected_ = true;
|
||||||
|
std::cout << "[network] Connected to " << self->url_ << std::endl;
|
||||||
|
return EM_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EM_BOOL onError(
|
||||||
|
int, const EmscriptenWebSocketErrorEvent*, void* userData)
|
||||||
|
{
|
||||||
|
static_cast<Impl*>(userData)->fail("WebSocket");
|
||||||
|
return EM_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EM_BOOL onClose(
|
||||||
|
int, const EmscriptenWebSocketCloseEvent*, void* userData)
|
||||||
|
{
|
||||||
|
auto* self = static_cast<Impl*>(userData);
|
||||||
|
self->connected_ = false;
|
||||||
|
if (!self->closing_) self->fail("WebSocket close");
|
||||||
|
return EM_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EM_BOOL onMessage(
|
||||||
|
int, const EmscriptenWebSocketMessageEvent* event, void* userData)
|
||||||
|
{
|
||||||
|
auto* self = static_cast<Impl*>(userData);
|
||||||
|
if (!event || event->isText != EM_TRUE) {
|
||||||
|
self->fail("binary WebSocket message");
|
||||||
|
return EM_TRUE;
|
||||||
|
}
|
||||||
|
self->messages_.emplace_back(
|
||||||
|
reinterpret_cast<const char*>(event->data), event->numBytes);
|
||||||
|
return EM_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fail(const char* operation)
|
||||||
|
{
|
||||||
|
connected_ = false;
|
||||||
|
connectionFailed_ = true;
|
||||||
|
std::cerr << "[network] " << operation << " failed" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string host_;
|
||||||
|
std::string port_;
|
||||||
|
std::string path_;
|
||||||
|
std::string url_;
|
||||||
|
EMSCRIPTEN_WEBSOCKET_T socket_ = 0;
|
||||||
|
bool connected_ = false;
|
||||||
|
bool connectionFailed_ = false;
|
||||||
|
bool closing_ = false;
|
||||||
|
std::vector<std::string> messages_;
|
||||||
|
#else
|
||||||
Impl(std::string host, std::string port, std::string path)
|
Impl(std::string host, std::string port, std::string path)
|
||||||
: resolver_(io_)
|
: resolver_(io_)
|
||||||
, socket_(io_)
|
, socket_(io_)
|
||||||
@@ -149,6 +269,7 @@ private:
|
|||||||
std::mutex messagesMutex_;
|
std::mutex messagesMutex_;
|
||||||
std::vector<std::string> messages_;
|
std::vector<std::string> messages_;
|
||||||
std::deque<std::string> outbound_;
|
std::deque<std::string> outbound_;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
WebsocketGameClient::WebsocketGameClient(
|
WebsocketGameClient::WebsocketGameClient(
|
||||||
@@ -296,12 +417,12 @@ void WebsocketGameClient::update(std::int64_t)
|
|||||||
if (!tick.stateHash.empty()) {
|
if (!tick.stateHash.empty()) {
|
||||||
nlohmann::json state;
|
nlohmann::json state;
|
||||||
replica_.save(state);
|
replica_.save(state);
|
||||||
const std::string localHash = canonicalStateHash(std::move(state));
|
/*const std::string localHash = canonicalStateHash(std::move(state));
|
||||||
if (localHash != tick.stateHash) {
|
if (localHash != tick.stateHash) {
|
||||||
std::cerr << "[network] Lockstep divergence at tick "
|
std::cerr << "[network] Lockstep divergence at tick "
|
||||||
<< tick.tickId << ": server=" << tick.stateHash
|
<< tick.tickId << ": server=" << tick.stateHash
|
||||||
<< ", client=" << localHash << '\n';
|
<< ", client=" << localHash << '\n';
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
++nextExpectedTick_;
|
++nextExpectedTick_;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "InteractiveObject.h"
|
#include "InteractiveObject.h"
|
||||||
#include "render/Renderer.h"
|
#include "render/Renderer.h"
|
||||||
#include "render/TextureManager.h"
|
#include "render/TextureManager.h"
|
||||||
#include "../TextModel.h"
|
#include "../TextModel.h"
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
namespace FRG {
|
namespace FRG {
|
||||||
extern const std::string textureUniformName;
|
extern const std::string textureUniformName;
|
||||||
|
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef __EMSCRIPTEN__
|
||||||
using std::min;
|
using std::min;
|
||||||
using std::max;
|
using std::max;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+6
-6
@@ -1,4 +1,4 @@
|
|||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
#include "Environment.h"
|
#include "Environment.h"
|
||||||
#include "utils/Utils.h"
|
#include "utils/Utils.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef __EMSCRIPTEN__
|
||||||
#include <emscripten.h>
|
#include <emscripten.h>
|
||||||
#include <emscripten/html5.h>
|
#include <emscripten/html5.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -50,7 +50,7 @@ void readSettings()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(EMSCRIPTEN)
|
#if defined(__EMSCRIPTEN__)
|
||||||
static SDL_GLContext glContext_x;
|
static SDL_GLContext glContext_x;
|
||||||
static bool g_isFsLoaded = false; // Флаг готовности
|
static bool g_isFsLoaded = false; // Флаг готовности
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ static void applyResize(int logicalW, int logicalH) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void MainLoop() {
|
void MainLoop() {
|
||||||
#if defined(EMSCRIPTEN)
|
#if defined(__EMSCRIPTEN__)
|
||||||
// Крутим цикл вхолостую, пока JS читает IndexedDB
|
// Крутим цикл вхолостую, пока JS читает IndexedDB
|
||||||
if (!g_isFsLoaded) return;
|
if (!g_isFsLoaded) return;
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@ void MainLoop() {
|
|||||||
g_game->update();
|
g_game->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef __EMSCRIPTEN__
|
||||||
|
|
||||||
|
|
||||||
EM_BOOL onWebGLContextLost(int /*eventType*/, const void* /*reserved*/, void* /*userData*/) {
|
EM_BOOL onWebGLContextLost(int /*eventType*/, const void* /*reserved*/, void* /*userData*/) {
|
||||||
@@ -482,7 +482,7 @@ int main(int argc, char* argv[]) {
|
|||||||
SDL_DestroyWindow(FRG::Environment::window);
|
SDL_DestroyWindow(FRG::Environment::window);
|
||||||
}
|
}
|
||||||
//FRG::logger() << "Quitting step 8: " << std::endl;
|
//FRG::logger() << "Quitting step 8: " << std::endl;
|
||||||
#ifndef EMSCRIPTEN
|
#ifndef __EMSCRIPTEN__
|
||||||
// In Emscripten, SDL must stay alive across context loss/restore cycles
|
// In Emscripten, SDL must stay alive across context loss/restore cycles
|
||||||
// so the window remains valid when the game object is re-created.
|
// so the window remains valid when the game object is re-created.
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
#include "SDL.h"
|
#include "SDL.h"
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef __EMSCRIPTEN__
|
||||||
//#define GL_GLEXT_PROTOTYPES 1
|
//#define GL_GLEXT_PROTOTYPES 1
|
||||||
//#define EGL_EGLEXT_PROTOTYPES 1
|
//#define EGL_EGLEXT_PROTOTYPES 1
|
||||||
//#include <SDL2/SDL_opengl.h>
|
//#include <SDL2/SDL_opengl.h>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "render/Renderer.h"
|
#include "render/Renderer.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
namespace FRG {
|
namespace FRG {
|
||||||
@@ -116,7 +116,7 @@ namespace FRG {
|
|||||||
|
|
||||||
VAOHolder::VAOHolder()
|
VAOHolder::VAOHolder()
|
||||||
{
|
{
|
||||||
#ifndef EMSCRIPTEN
|
#ifndef __EMSCRIPTEN__
|
||||||
#ifndef ANDROID
|
#ifndef ANDROID
|
||||||
glGenVertexArrays(1, &vao);
|
glGenVertexArrays(1, &vao);
|
||||||
#endif
|
#endif
|
||||||
@@ -125,7 +125,7 @@ namespace FRG {
|
|||||||
|
|
||||||
VAOHolder::~VAOHolder()
|
VAOHolder::~VAOHolder()
|
||||||
{
|
{
|
||||||
#ifndef EMSCRIPTEN
|
#ifndef __EMSCRIPTEN__
|
||||||
#ifndef ANDROID
|
#ifndef ANDROID
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
glDeleteVertexArrays(1, &vao);
|
glDeleteVertexArrays(1, &vao);
|
||||||
@@ -382,7 +382,7 @@ namespace FRG {
|
|||||||
{
|
{
|
||||||
//Check if main thread, check if data is not empty...
|
//Check if main thread, check if data is not empty...
|
||||||
|
|
||||||
#ifndef EMSCRIPTEN
|
#ifndef __EMSCRIPTEN__
|
||||||
#ifndef __ANDROID__
|
#ifndef __ANDROID__
|
||||||
if (!vao)
|
if (!vao)
|
||||||
{
|
{
|
||||||
@@ -528,7 +528,7 @@ namespace FRG {
|
|||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
#ifndef EMSCRIPTEN
|
#ifndef __EMSCRIPTEN__
|
||||||
#ifndef __ANDROID__
|
#ifndef __ANDROID__
|
||||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||||
#endif
|
#endif
|
||||||
@@ -988,7 +988,7 @@ namespace FRG {
|
|||||||
|
|
||||||
void Renderer::BindVertexRenderStructAttribs(const VertexRenderStruct& VertexRenderStruct)
|
void Renderer::BindVertexRenderStructAttribs(const VertexRenderStruct& VertexRenderStruct)
|
||||||
{
|
{
|
||||||
#ifndef EMSCRIPTEN
|
#ifndef __EMSCRIPTEN__
|
||||||
#ifndef __ANDROID__
|
#ifndef __ANDROID__
|
||||||
if (VertexRenderStruct.vao) {
|
if (VertexRenderStruct.vao) {
|
||||||
glBindVertexArray(VertexRenderStruct.vao->getBuffer());
|
glBindVertexArray(VertexRenderStruct.vao->getBuffer());
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "ShadowMap.h"
|
#include "ShadowMap.h"
|
||||||
#include "Environment.h"
|
#include "Environment.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
@@ -56,7 +56,7 @@ namespace FRG {
|
|||||||
{
|
{
|
||||||
glGenFramebuffers(1, &fbo);
|
glGenFramebuffers(1, &fbo);
|
||||||
|
|
||||||
#if defined(EMSCRIPTEN) || defined(__ANDROID__)
|
#if defined(__EMSCRIPTEN__) || defined(__ANDROID__)
|
||||||
glGenTextures(1, &depthTexture);
|
glGenTextures(1, &depthTexture);
|
||||||
glBindTexture(GL_TEXTURE_2D, depthTexture);
|
glBindTexture(GL_TEXTURE_2D, depthTexture);
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ namespace FRG {
|
|||||||
GL_TEXTURE_2D, depthTexture, 0);
|
GL_TEXTURE_2D, depthTexture, 0);
|
||||||
|
|
||||||
// No color buffer for this FBO — depth only.
|
// No color buffer for this FBO — depth only.
|
||||||
#if defined(EMSCRIPTEN) || defined(__ANDROID__)
|
#if defined(__EMSCRIPTEN__) || defined(__ANDROID__)
|
||||||
GLenum drawBuffers[] = { GL_NONE };
|
GLenum drawBuffers[] = { GL_NONE };
|
||||||
glDrawBuffers(1, drawBuffers);
|
glDrawBuffers(1, drawBuffers);
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "render/TextureManager.h"
|
#include "render/TextureManager.h"
|
||||||
#include "render/OpenGlExtensions.h"
|
#include "render/OpenGlExtensions.h"
|
||||||
#ifdef PNG_ENABLED
|
#ifdef PNG_ENABLED
|
||||||
#include "png.h"
|
#include "png.h"
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
namespace FRG
|
namespace FRG
|
||||||
{
|
{
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef __EMSCRIPTEN__
|
||||||
using std::min;
|
using std::min;
|
||||||
using std::max;
|
using std::max;
|
||||||
#endif
|
#endif
|
||||||
@@ -88,7 +88,7 @@ namespace FRG
|
|||||||
case TextureDataStruct::R8:
|
case TextureDataStruct::R8:
|
||||||
// Для WebGL 1.0 лучше использовать GL_LUMINANCE вместо GL_RED
|
// Для WebGL 1.0 лучше использовать GL_LUMINANCE вместо GL_RED
|
||||||
// Если используешь WebGL 2.0, можно оставить GL_RED
|
// Если используешь WebGL 2.0, можно оставить GL_RED
|
||||||
#if defined(EMSCRIPTEN) || defined(__ANDROID__)
|
#if defined(__EMSCRIPTEN__) || defined(__ANDROID__)
|
||||||
internalFormat = GL_LUMINANCE;
|
internalFormat = GL_LUMINANCE;
|
||||||
externalFormat = GL_LUMINANCE;
|
externalFormat = GL_LUMINANCE;
|
||||||
#else
|
#else
|
||||||
@@ -167,7 +167,7 @@ namespace FRG
|
|||||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
|
||||||
#ifndef EMSCRIPTEN
|
#ifndef __EMSCRIPTEN__
|
||||||
#ifndef __ANDROID__
|
#ifndef __ANDROID__
|
||||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "render/OpenGlExtensions.h"
|
#include "render/OpenGlExtensions.h"
|
||||||
#include "utils/Utils.h"
|
#include "utils/Utils.h"
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
#if defined EMSCRIPTEN || defined __ANDROID__
|
#if defined __EMSCRIPTEN__ || defined __ANDROID__
|
||||||
#define PNG_ENABLED
|
#define PNG_ENABLED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "TaskManager.h"
|
#include "TaskManager.h"
|
||||||
|
|
||||||
|
|
||||||
namespace FRG
|
namespace FRG
|
||||||
@@ -6,7 +6,7 @@ namespace FRG
|
|||||||
|
|
||||||
TaskManager::TaskManager(size_t threadCount) {
|
TaskManager::TaskManager(size_t threadCount) {
|
||||||
|
|
||||||
#ifndef EMSCRIPTEN
|
#ifndef __EMSCRIPTEN__
|
||||||
workGuard = std::make_unique<boost::asio::executor_work_guard<boost::asio::io_context::executor_type>>(ioContext.get_executor());
|
workGuard = std::make_unique<boost::asio::executor_work_guard<boost::asio::io_context::executor_type>>(ioContext.get_executor());
|
||||||
|
|
||||||
for (size_t i = 0; i < threadCount; ++i) {
|
for (size_t i = 0; i < threadCount; ++i) {
|
||||||
@@ -18,7 +18,7 @@ namespace FRG
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TaskManager::EnqueueBackgroundTask(std::function<void()> task) {
|
void TaskManager::EnqueueBackgroundTask(std::function<void()> task) {
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef __EMSCRIPTEN__
|
||||||
task();
|
task();
|
||||||
#else
|
#else
|
||||||
boost::asio::post(ioContext, task);
|
boost::asio::post(ioContext, task);
|
||||||
@@ -26,7 +26,7 @@ namespace FRG
|
|||||||
}
|
}
|
||||||
|
|
||||||
TaskManager::~TaskManager() {
|
TaskManager::~TaskManager() {
|
||||||
#ifndef EMSCRIPTEN
|
#ifndef __EMSCRIPTEN__
|
||||||
workGuard.reset(); // Разрешаем ioContext.run() завершиться, когда задач не останется
|
workGuard.reset(); // Разрешаем ioContext.run() завершиться, когда задач не останется
|
||||||
ioContext.stop(); // Опционально: немедленная остановка
|
ioContext.stop(); // Опционально: немедленная остановка
|
||||||
for (auto& t : workers) {
|
for (auto& t : workers) {
|
||||||
@@ -36,7 +36,7 @@ namespace FRG
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainThreadHandler::EnqueueMainThreadTask(std::function<void()> task) {
|
void MainThreadHandler::EnqueueMainThreadTask(std::function<void()> task) {
|
||||||
#ifndef EMSCRIPTEN
|
#ifndef __EMSCRIPTEN__
|
||||||
std::lock_guard<std::mutex> lock(mainThreadMutex);
|
std::lock_guard<std::mutex> lock(mainThreadMutex);
|
||||||
#endif
|
#endif
|
||||||
mainThreadTasks.push(task);
|
mainThreadTasks.push(task);
|
||||||
@@ -45,7 +45,7 @@ namespace FRG
|
|||||||
void MainThreadHandler::processMainThreadTasks() {
|
void MainThreadHandler::processMainThreadTasks() {
|
||||||
std::function<void()> task;
|
std::function<void()> task;
|
||||||
|
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef __EMSCRIPTEN__
|
||||||
if (!mainThreadTasks.empty()) {
|
if (!mainThreadTasks.empty()) {
|
||||||
task = std::move(mainThreadTasks.front());
|
task = std::move(mainThreadTasks.front());
|
||||||
mainThreadTasks.pop();
|
mainThreadTasks.pop();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef EMSCRIPTEN
|
#ifndef __EMSCRIPTEN__
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#endif
|
#endif
|
||||||
@@ -15,7 +15,7 @@ namespace FRG {
|
|||||||
|
|
||||||
class TaskManager {
|
class TaskManager {
|
||||||
private:
|
private:
|
||||||
#ifndef EMSCRIPTEN
|
#ifndef __EMSCRIPTEN__
|
||||||
boost::asio::io_context ioContext;
|
boost::asio::io_context ioContext;
|
||||||
std::unique_ptr<boost::asio::executor_work_guard<boost::asio::io_context::executor_type>> workGuard;
|
std::unique_ptr<boost::asio::executor_work_guard<boost::asio::io_context::executor_type>> workGuard;
|
||||||
std::vector<std::thread> workers;
|
std::vector<std::thread> workers;
|
||||||
@@ -29,7 +29,7 @@ namespace FRG {
|
|||||||
// Graceful shutdown
|
// Graceful shutdown
|
||||||
~TaskManager();
|
~TaskManager();
|
||||||
|
|
||||||
#ifndef EMSCRIPTEN
|
#ifndef __EMSCRIPTEN__
|
||||||
boost::asio::io_context& getIOContext()
|
boost::asio::io_context& getIOContext()
|
||||||
{
|
{
|
||||||
return ioContext;
|
return ioContext;
|
||||||
@@ -43,7 +43,7 @@ namespace FRG {
|
|||||||
private:
|
private:
|
||||||
std::queue<std::function<void()>> mainThreadTasks;
|
std::queue<std::function<void()>> mainThreadTasks;
|
||||||
|
|
||||||
#ifndef EMSCRIPTEN
|
#ifndef __EMSCRIPTEN__
|
||||||
std::mutex mainThreadMutex;
|
std::mutex mainThreadMutex;
|
||||||
#endif
|
#endif
|
||||||
public:
|
public:
|
||||||
|
|||||||
+24
-4
@@ -1,4 +1,4 @@
|
|||||||
#include "utils/Utils.h"
|
#include "utils/Utils.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -110,7 +110,7 @@ namespace FRG
|
|||||||
return readFile(filename);
|
return readFile(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef __EMSCRIPTEN__
|
||||||
|
|
||||||
std::string webZipFilename = getPersistentResourcePath(zipfilename);
|
std::string webZipFilename = getPersistentResourcePath(zipfilename);
|
||||||
|
|
||||||
@@ -206,7 +206,7 @@ namespace FRG
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef __EMSCRIPTEN__
|
||||||
std::string webZipFilename = getPersistentResourcePath(zipfilename);
|
std::string webZipFilename = getPersistentResourcePath(zipfilename);
|
||||||
|
|
||||||
int zipErr = 0;
|
int zipErr = 0;
|
||||||
@@ -320,7 +320,7 @@ namespace FRG
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// На Web-платформе можно опустить имя разработчика, либо оставить для единообразия.
|
// На Web-платформе можно опустить имя разработчика, либо оставить для единообразия.
|
||||||
// Если в EMSCRIPTEN монтируется `/offline`, структура останется чистой.
|
// Если в __EMSCRIPTEN__ монтируется `/offline`, структура останется чистой.
|
||||||
return baseDir / "Fish Run Games" / "Shadow Over Bishkek Demo";
|
return baseDir / "Fish Run Games" / "Shadow Over Bishkek Demo";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -545,6 +545,26 @@ namespace FRG
|
|||||||
<< " (code " << zipErr << ")" << std::endl;
|
<< " (code " << zipErr << ")" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string resourceArchiveSuffix = "resources.zip";
|
||||||
|
if (fullPath.size() >= resourceArchiveSuffix.size() &&
|
||||||
|
fullPath.compare(fullPath.size() - resourceArchiveSuffix.size(),
|
||||||
|
resourceArchiveSuffix.size(), resourceArchiveSuffix) == 0) {
|
||||||
|
static constexpr const char* requiredEntries[] = {
|
||||||
|
"resources/shaders/path_visualization.vertex",
|
||||||
|
"resources/shaders/path_visualization_web.fragment",
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const char* entry : requiredEntries) {
|
||||||
|
if (zip_name_locate(archive, entry, 0) < 0) {
|
||||||
|
logger() << "[VFS] Cached resources.zip is missing required entry: "
|
||||||
|
<< entry << ". It will be downloaded again." << std::endl;
|
||||||
|
zip_close(archive);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
zip_close(archive);
|
zip_close(archive);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user