diff --git a/proj-web/CMakeLists.txt b/proj-web/CMakeLists.txt
index 8b02c39..0f353b1 100644
--- a/proj-web/CMakeLists.txt
+++ b/proj-web/CMakeLists.txt
@@ -63,8 +63,6 @@ set(SOURCES
../src/network/LocalClient.cpp
../src/network/ClientState.h
../src/network/ClientState.cpp
- ../src/network/WebSocketClient.h
- ../src/network/WebSocketClient.cpp
../src/network/WebSocketClientBase.h
../src/network/WebSocketClientBase.cpp
../src/network/WebSocketClientEmscripten.h
@@ -95,10 +93,7 @@ set(ENABLE_COMMONCRYPTO OFF CACHE BOOL "" FORCE)
add_subdirectory("../thirdparty/libzip-1.11.4" libzip-build)
-# Линковка:
-# 'zip' берется из add_subdirectory
-# 'z' - это системный zlib Emscripten-а (флаг -sUSE_ZLIB=1 добавим ниже)
-target_link_libraries(space-game001 PRIVATE zip z websocket)
+target_link_libraries(space-game001 PRIVATE zip z websocket.js)
# Эмскриптен-флаги
set(EMSCRIPTEN_FLAGS
@@ -107,8 +102,8 @@ set(EMSCRIPTEN_FLAGS
"-sUSE_LIBPNG=1"
"-sUSE_ZLIB=1"
"-sUSE_SDL_TTF=2"
- "-pthread"
- "-sUSE_PTHREADS=1"
+ #"-pthread"
+ #"-sUSE_PTHREADS=1"
"-fexceptions"
"-DNETWORK"
)
@@ -120,8 +115,9 @@ target_compile_options(space-game001 PRIVATE ${EMSCRIPTEN_FLAGS} "-O2")
set(EMSCRIPTEN_LINK_FLAGS
${EMSCRIPTEN_FLAGS}
"-O2"
- "-sPTHREAD_POOL_SIZE=4"
+ #"-sPTHREAD_POOL_SIZE=4"
"-sALLOW_MEMORY_GROWTH=1"
+ "-sFULL_ES3=1"
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/loading.png@resources/loading.png"
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/shaders@resources/shaders"
)
diff --git a/proj-web/space-game001.html b/proj-web/space-game001.html
new file mode 100644
index 0000000..710f6f4
--- /dev/null
+++ b/proj-web/space-game001.html
@@ -0,0 +1,2 @@
+
Emscripten-Generated Code
+![]()
Downloading...
Resize canvas Lock/hide mouse pointer
\ No newline at end of file
diff --git a/src/Game.cpp b/src/Game.cpp
index 210d181..e833928 100644
--- a/src/Game.cpp
+++ b/src/Game.cpp
@@ -57,9 +57,9 @@ namespace ZL
#endif
Game::Game()
- : window(nullptr)
+ : /*window(nullptr)
, glContext(nullptr)
- , newTickCount(0)
+ , */newTickCount(0)
, lastTickCount(0)
, menuManager(renderer)
, space(renderer, taskManager, mainThreadHandler, networkClient, menuManager)
@@ -67,12 +67,13 @@ namespace ZL
}
Game::~Game() {
+ /*
if (glContext) {
SDL_GL_DeleteContext(glContext);
}
if (window) {
SDL_DestroyWindow(window);
- }
+ }*/
#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.
@@ -81,14 +82,15 @@ namespace ZL
}
void Game::setup() {
- glContext = SDL_GL_CreateContext(ZL::Environment::window);
+ //glContext = SDL_GL_CreateContext(ZL::Environment::window);
+ //glContext = in_glContext;
Environment::computeProjectionDimensions();
ZL::BindOpenGlFunctions();
ZL::CheckGlError();
renderer.InitOpenGL();
-
+
#ifdef EMSCRIPTEN
// These shaders and loading.png are preloaded separately (not from zip),
// so they are available immediately without waiting for resources.zip.
@@ -101,19 +103,23 @@ namespace ZL
loadingTexture = std::make_unique(CreateTextureDataFromPng("resources/loading.png", CONST_ZIP_FILE));
#endif
- loadingMesh.data = CreateRect2D({ Environment::projectionWidth * 0.5f, Environment::projectionHeight * 0.5f }, { Environment::projectionWidth * 0.5f, Environment::projectionHeight * 0.5f }, 3);
+ loadingMesh.data = CreateRect2D({ 0.5f, 0.5f }, { 0.5f, 0.5f }, 3);
loadingMesh.RefreshVBO();
-
+
#ifdef EMSCRIPTEN
// Asynchronously download resources.zip; setupPart2() is called on completion.
// The loading screen stays visible until the download finishes.
s_instance = this;
+ std::cout << "Load resurces step 1" << std::endl;
emscripten_async_wget("resources.zip", "resources.zip", onResourcesZipLoaded, onResourcesZipError);
#else
mainThreadHandler.EnqueueMainThreadTask([this]() {
+ std::cout << "Load resurces step 2" << std::endl;
this->setupPart2();
+ std::cout << "Load resurces step 3" << std::endl;
});
#endif
+
}
@@ -164,10 +170,10 @@ namespace ZL
networkClient = std::make_unique();
networkClient->Connect("localhost", 8081);
#else
- networkClient = std::make_unique(taskManager.getIOContext());
- networkClient->Connect("localhost", 8081);
+ //networkClient = std::make_unique(taskManager.getIOContext());
+ //networkClient->Connect("localhost", 8081);
#endif
-
+
if (networkClient) {
std::string joinMsg = std::string("JOIN:") + nickname + ":" + std::to_string(shipType);
networkClient->Send(joinMsg);
@@ -249,12 +255,12 @@ namespace ZL
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vTexCoordName);
- float width = Environment::projectionWidth;
- float height = Environment::projectionHeight;
+ //float width = Environment::projectionWidth;
+ //float height = Environment::projectionHeight;
renderer.PushProjectionMatrix(
- 0, width,
- 0, height,
+ 0, 1,
+ 0, 1,
-10, 10);
renderer.PushMatrix();
@@ -275,8 +281,7 @@ namespace ZL
int64_t Game::getSyncTimeMs() {
int64_t localNow = std::chrono::duration_cast(
std::chrono::system_clock::now().time_since_epoch()).count();
- // Добавляем смещение, полученное от сервера
- if (networkClient)
+ if(networkClient)
{
return localNow + networkClient->getTimeOffset();
}
@@ -317,10 +322,10 @@ namespace ZL
}
void Game::render() {
- SDL_GL_MakeCurrent(ZL::Environment::window, glContext);
+ //SDL_GL_MakeCurrent(ZL::Environment::window, glContext);
ZL::CheckGlError();
- glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+ glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawScene();
@@ -438,7 +443,7 @@ namespace ZL
#endif
}
render();
-
+
if (networkClient) {
#ifndef NETWORK
auto localClient = dynamic_cast(networkClient.get());
diff --git a/src/Game.h b/src/Game.h
index ab4ab9f..208fa1e 100644
--- a/src/Game.h
+++ b/src/Game.h
@@ -60,8 +60,8 @@ namespace ZL {
static void onResourcesZipError(const char* filename);
#endif
- SDL_Window* window;
- SDL_GLContext glContext;
+ //SDL_Window* window;
+ //SDL_GLContext glContext;
int64_t newTickCount;
int64_t lastTickCount;
diff --git a/src/main.cpp b/src/main.cpp
index 6b62092..bc9aa54 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -16,37 +16,46 @@
// For Android and Desktop a plain global value is used (no context loss).
#ifdef EMSCRIPTEN
ZL::Game* g_game = nullptr;
+//static SDL_Window* win_x = nullptr;
+static SDL_GLContext glContext_x; // Не указатель, а сам объект (который суть void*)
+
#else
ZL::Game game;
#endif
-void MainLoop() {
#ifdef EMSCRIPTEN
- if (g_game) g_game->update();
-#else
- game.update();
-#endif
+void MainLoop() {
+ // SDL_GL_MakeCurrent тут не нужен каждый раз
+ /*glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ SDL_GL_SwapWindow(ZL::Environment::window);*/
+ g_game->update();
}
+#else
+void MainLoop() {
+ game.update();
+}
+#endif
#ifdef EMSCRIPTEN
EM_BOOL onWebGLContextLost(int /*eventType*/, const void* /*reserved*/, void* /*userData*/) {
- delete g_game;
- g_game = nullptr;
+ //delete g_game;
+ //g_game = nullptr;
return EM_TRUE;
}
EM_BOOL onWebGLContextRestored(int /*eventType*/, const void* /*reserved*/, void* /*userData*/) {
- g_game = new ZL::Game();
- g_game->setup();
+ //g_game = new ZL::Game();
+ //g_game->setup();
return EM_TRUE;
}
static void applyResize(int logicalW, int logicalH) {
// Получаем коэффициент плотности пикселей (например, 2.625 на Pixel или 3.0 на Samsung)
- double dpr = emscripten_get_device_pixel_ratio();
+ /*double dpr = emscripten_get_device_pixel_ratio();
// Вычисляем реальные физические пиксели
int physicalW = static_cast(logicalW * dpr);
@@ -72,7 +81,7 @@ static void applyResize(int logicalW, int logicalH) {
e.window.event = SDL_WINDOWEVENT_RESIZED;
e.window.data1 = physicalW;
e.window.data2 = physicalH;
- SDL_PushEvent(&e);
+ SDL_PushEvent(&e);*/
}
EM_BOOL onWindowResized(int /*eventType*/, const EmscriptenUiEvent* e, void* /*userData*/) {
@@ -91,6 +100,44 @@ EM_BOOL onFullscreenChanged(int /*eventType*/, const EmscriptenFullscreenChangeE
return EM_FALSE;
}
+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
+
+ 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);
+
+ SDL_GL_MakeCurrent(ZL::Environment::window, glContext_x);
+
+ g_game = new ZL::Game();
+ g_game->setup();
+
+ 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);
+
+ SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
+
+ emscripten_set_main_loop(MainLoop, 0, 1);
+
+
+ return 0;
+}
+
#endif
@@ -178,7 +225,9 @@ extern "C" int SDL_main(int argc, char* argv[]) {
}
-#else
+#endif
+
+#ifdef WIN32_LEAN_AND_MEAN
int main(int argc, char *argv[]) {
try
@@ -192,7 +241,7 @@ int main(int argc, char *argv[]) {
ZL::Environment::height = CONST_HEIGHT;
-#ifdef EMSCRIPTEN
+/*#ifdef EMSCRIPTEN
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
std::cerr << "SDL_Init failed: " << SDL_GetError() << std::endl;
return 1;
@@ -251,7 +300,7 @@ int main(int argc, char *argv[]) {
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
emscripten_set_main_loop(MainLoop, 0, 1);
-#else
+#else*/
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) {
SDL_Log("SDL init failed: %s", SDL_GetError());
return 1;
@@ -277,7 +326,7 @@ int main(int argc, char *argv[]) {
game.update();
SDL_Delay(2);
}
-#endif
+//#endif
}
catch (const std::exception& e)
diff --git a/src/network/WebSocketClientEmscripten.cpp b/src/network/WebSocketClientEmscripten.cpp
index 9534cf0..3d598e8 100644
--- a/src/network/WebSocketClientEmscripten.cpp
+++ b/src/network/WebSocketClientEmscripten.cpp
@@ -7,8 +7,8 @@
namespace ZL {
void WebSocketClientEmscripten::Connect(const std::string& host, uint16_t port) {
// Формируем URL. Обратите внимание, что в Web часто лучше использовать ws://localhost
- std::string url = "ws://" + host + ":" + std::to_string(port);
- //std::string url = "wss://api.spacegame.fishrungames.com";
+ //std::string url = "ws://" + host + ":" + std::to_string(port);
+ std::string url = "wss://api.spacegame.fishrungames.com";
EmscriptenWebSocketCreateAttributes attr = {
url.c_str(),
@@ -36,11 +36,8 @@ namespace ZL {
// Локальная очередь для минимизации времени блокировки мьютекса
std::queue localQueue;
- {
- std::lock_guard lock(queueMutex);
- if (messageQueue.empty()) return;
- std::swap(localQueue, messageQueue);
- }
+ if (messageQueue.empty()) return;
+ std::swap(localQueue, messageQueue);
while (!localQueue.empty()) {
const std::string& msg = localQueue.front();
@@ -67,7 +64,6 @@ namespace ZL {
auto* self = static_cast(userData);
if (e->isText && e->data) {
std::string msg(reinterpret_cast(e->data), e->numBytes);
- std::lock_guard lock(self->queueMutex);
self->messageQueue.push(msg);
}
return EM_TRUE;
diff --git a/src/network/WebSocketClientEmscripten.h b/src/network/WebSocketClientEmscripten.h
index 2aac059..10a7a49 100644
--- a/src/network/WebSocketClientEmscripten.h
+++ b/src/network/WebSocketClientEmscripten.h
@@ -18,7 +18,6 @@ namespace ZL {
// Очередь для хранения сырых строк от браузера
std::queue messageQueue;
- std::mutex queueMutex;
public:
WebSocketClientEmscripten() = default;
diff --git a/src/utils/TaskManager.cpp b/src/utils/TaskManager.cpp
index aef62a1..c4fe7f1 100644
--- a/src/utils/TaskManager.cpp
+++ b/src/utils/TaskManager.cpp
@@ -5,35 +5,52 @@ namespace ZL
{
TaskManager::TaskManager(size_t threadCount) {
- workGuard = std::make_unique>(ioContext.get_executor());
+
+#ifndef EMSCRIPTEN
+ workGuard = std::make_unique>(ioContext.get_executor());
for (size_t i = 0; i < threadCount; ++i) {
workers.emplace_back([this]() {
ioContext.run();
});
}
+#endif
}
void TaskManager::EnqueueBackgroundTask(std::function task) {
+#ifdef EMSCRIPTEN
+ task();
+#else
boost::asio::post(ioContext, task);
+#endif
}
TaskManager::~TaskManager() {
+#ifndef EMSCRIPTEN
workGuard.reset(); // ioContext.run() ,
ioContext.stop(); // :
for (auto& t : workers) {
if (t.joinable()) t.join();
}
+#endif
}
void MainThreadHandler::EnqueueMainThreadTask(std::function task) {
+#ifndef EMSCRIPTEN
std::lock_guard lock(mainThreadMutex);
+#endif
mainThreadTasks.push(task);
}
void MainThreadHandler::processMainThreadTasks() {
std::function task;
+#ifdef EMSCRIPTEN
+ if (!mainThreadTasks.empty()) {
+ task = std::move(mainThreadTasks.front());
+ mainThreadTasks.pop();
+ }
+#else
// , update
{
std::lock_guard lock(mainThreadMutex);
@@ -42,6 +59,7 @@ namespace ZL
mainThreadTasks.pop();
}
}
+#endif
if (task) {
task(); // RefreshVBO
diff --git a/src/utils/TaskManager.h b/src/utils/TaskManager.h
index 66423f8..afb18df 100644
--- a/src/utils/TaskManager.h
+++ b/src/utils/TaskManager.h
@@ -1,8 +1,12 @@
#pragma once
+
+#ifndef EMSCRIPTEN
#include
+#include
+#endif
+
#include
#include
-#include
#include
#include
@@ -11,12 +15,12 @@ namespace ZL {
class TaskManager {
private:
+#ifndef EMSCRIPTEN
boost::asio::io_context ioContext;
std::unique_ptr> workGuard;
std::vector workers;
-
+#endif
public:
- //TaskManager(size_t threadCount = std::thread::hardware_concurrency());
TaskManager(size_t threadCount = 2);
//
@@ -24,11 +28,13 @@ namespace ZL {
// Graceful shutdown
~TaskManager();
-
+
+#ifndef EMSCRIPTEN
boost::asio::io_context& getIOContext()
{
return ioContext;
}
+#endif
};
@@ -36,8 +42,10 @@ namespace ZL {
{
private:
std::queue> mainThreadTasks;
- std::mutex mainThreadMutex;
+#ifndef EMSCRIPTEN
+ std::mutex mainThreadMutex;
+#endif
public:
void EnqueueMainThreadTask(std::function task);