From e878aa4db6f12e6c1c239410777a7943d1e1e154 Mon Sep 17 00:00:00 2001 From: sergeypdev Date: Sat, 19 Jul 2025 18:17:02 +0400 Subject: [PATCH] Try to get web working again --- builder/builder.odin | 65 ++++++++------ game/assets/assets.odin | 3 +- game/assets/watcher.odin | 135 ---------------------------- game/assets/watcher_desktop.odin | 145 +++++++++++++++++++++++++++++++ game/assets/watcher_js.odin | 24 +++++ main_web/main_web.odin | 2 +- 6 files changed, 209 insertions(+), 165 deletions(-) create mode 100644 game/assets/watcher_desktop.odin create mode 100644 game/assets/watcher_js.odin diff --git a/builder/builder.odin b/builder/builder.odin index 3e624df..0d4b519 100644 --- a/builder/builder.odin +++ b/builder/builder.odin @@ -68,35 +68,46 @@ build_deps :: proc(opts: Options) -> []string { // Raylib { - cwd := "./libs/raylib" - out_dir := shared ? "zig-out-shared" : "zig-out-static" - remove_all(fmt.tprintf("./libs/raylib/%s", out_dir)) - if force { - remove_all("./libs/raylib/.zig-cache") - } - target := opts.variant == .Web ? "wasm32-emscripten" : "native" + if opts.variant == .Web { + cwd := "./libs/raylib/src" - run_cmd( - { - "zig", - "build", - "-p", - out_dir, - fmt.tprintf("-Dshared=%v", shared), - fmt.tprintf("-Dtarget=%s", target), - }, - cwd, - ) + if force { + run_cmd({"make", "clean", "PLATFORM=PLATFORM_WEB"}, cwd) + } - if shared { - append( - &out_libs, - temp_path_join( - "./libs/raylib/zig-out-shared/lib", - LIB_PREFIX + "raylib" + DLL_EXT, - ), + run_cmd({"make", "PLATFORM=PLATFORM_WEB", "-j8"}, cwd) + } else { + cwd := "./libs/raylib" + out_dir := shared ? "zig-out-shared" : "zig-out-static" + remove_all(fmt.tprintf("./libs/raylib/%s", out_dir)) + if force { + remove_all("./libs/raylib/.zig-cache") + } + + target := "native" + + run_cmd( + { + "zig", + "build", + "-p", + out_dir, + fmt.tprintf("-Dshared=%v", shared), + fmt.tprintf("-Dtarget=%s", target), + }, + cwd, ) + + if shared { + append( + &out_libs, + temp_path_join( + "./libs/raylib/zig-out-shared/lib", + LIB_PREFIX + "raylib" + DLL_EXT, + ), + ) + } } } @@ -330,7 +341,7 @@ main :: proc() { "main_web", "-target:js_wasm32", "-build-mode:obj", - "-out:bin/web/game", + "-out:bin/web/game.wasm.o", }, COMMON_FLAGS, debug_flag, @@ -348,7 +359,7 @@ main :: proc() { "-o", "bin/web/index.html", "bin/web/game.wasm.o", - "libs/raylib/zig-out-static/lib/libraylib.a", + "libs/raylib/src/libraylib.web.a", "libs/physfs/build/libphysfs.a", "-sUSE_GLFW=3", "-sWASM_BIGINT", diff --git a/game/assets/assets.odin b/game/assets/assets.odin index 6a828bc..d5a1d4e 100644 --- a/game/assets/assets.odin +++ b/game/assets/assets.odin @@ -5,7 +5,6 @@ import "common:name" import "core:log" import "core:math" import lg "core:math/linalg" -import "core:sync/chan" import "game:physics/bvh" import "game:physics/collision" import "libs:physfs" @@ -528,7 +527,7 @@ assetman_init :: proc(assetman: ^Asset_Manager) { assetman_tick :: proc(assetman: ^Asset_Manager) { tracy.Zone() - for asset in chan.try_recv(assetman.watcher.modified_assets) { + for asset in modtime_watcher_next(&assetman.watcher) { key := Asset_Key { path = asset.path, type = asset.type, diff --git a/game/assets/watcher.odin b/game/assets/watcher.odin index 036deba..5f10472 100644 --- a/game/assets/watcher.odin +++ b/game/assets/watcher.odin @@ -1,145 +1,10 @@ package assets -import "base:runtime" import "common:name" -import "core:log" -import "core:sync/chan" -import "core:thread" import "libs:physfs" -ASSET_WATCHER_OPS_BUFFER :: 256 - -// Add asset to watch list -Asset_Watcher_Op_Add :: struct { - type: Asset_Type, - path: name.Name, - modtime: physfs.sint64, -} -// Remove asset from watch list -Asset_Watcher_Op_Remove :: struct { - type: Asset_Type, - path: name.Name, -} - -Asset_Watcher_Op :: union #no_nil { - Asset_Watcher_Op_Add, - Asset_Watcher_Op_Remove, -} - Watcher_Asset :: struct { type: Asset_Type, path: name.Name, modtime: physfs.sint64, } - -Asset_Modtime_Watcher :: struct { - ops: chan.Chan(Asset_Watcher_Op), - modified_assets: chan.Chan(Watcher_Asset), - loaded_assets: [dynamic]Watcher_Asset, - thread: ^thread.Thread, -} - -modtime_watcher_init :: proc(watcher: ^Asset_Modtime_Watcher, allocator := context.allocator) { - err: runtime.Allocator_Error - watcher.ops, err = chan.create_buffered( - chan.Chan(Asset_Watcher_Op), - ASSET_WATCHER_OPS_BUFFER, - allocator, - ) - assert(err == nil) - watcher.modified_assets, err = chan.create_buffered( - chan.Chan(Watcher_Asset), - ASSET_WATCHER_OPS_BUFFER, - allocator, - ) - watcher.loaded_assets = make_dynamic_array([dynamic]Watcher_Asset, allocator) - - watcher.thread = thread.create(modtime_watcher_thread_proc) - watcher.thread.data = watcher - watcher_context := runtime.default_context() - watcher_context.logger = context.logger - watcher_context.allocator = context.allocator - watcher.thread.init_context = watcher_context - thread.start(watcher.thread) -} - -modtime_watcher_deinit :: proc(watcher: ^Asset_Modtime_Watcher) { - if !chan.is_closed(&watcher.ops) { - chan.close(&watcher.ops) - thread.join(watcher.thread) - watcher.thread = nil - } - - chan.destroy(&watcher.ops) - chan.close(&watcher.modified_assets) - chan.destroy(&watcher.modified_assets) - delete(watcher.loaded_assets) -} - -@(private = "file") -modtime_watcher_thread_proc :: proc(t: ^thread.Thread) { - watcher := cast(^Asset_Modtime_Watcher)t.data - - log.debugf("watcher thread") - - for !chan.is_closed(&watcher.ops) { - for recv_op in chan.try_recv(watcher.ops) { - switch op in recv_op { - case Asset_Watcher_Op_Add: - log.debugf("add [{}] {}", op.type, name.to_string(op.path)) - append( - &watcher.loaded_assets, - Watcher_Asset{type = op.type, path = op.path, modtime = op.modtime}, - ) - case Asset_Watcher_Op_Remove: - log.debugf("remove [{}] {}", op.type, name.to_string(op.path)) - i := 0 - for i < len(watcher.loaded_assets) { - if op.path == watcher.loaded_assets[i].path && - op.type == watcher.loaded_assets[i].type { - unordered_remove(&watcher.loaded_assets, i) - } else { - i += 1 - } - } - } - } - - for &asset in watcher.loaded_assets { - modtime := physfs.getLastModTime(name.to_cstring(asset.path)) - - if asset.modtime != modtime { - log.debugf("change [{}] {}", asset.type, name.to_string(asset.path)) - ok := chan.send( - watcher.modified_assets, - Watcher_Asset{type = asset.type, path = asset.path, modtime = modtime}, - ) - assert(ok) - } - asset.modtime = modtime - } - - // To avoid busy loop just in case - thread.yield() - } -} - -modtime_watcher_add_asset :: proc( - watcher: ^Asset_Modtime_Watcher, - type: Asset_Type, - path: name.Name, - modtime: physfs.sint64, -) -> bool { - return chan.send( - watcher.ops, - Asset_Watcher_Op_Add{type = type, path = path, modtime = modtime}, - ) -} - -modtime_watcher_remove_asset :: proc( - watcher: ^Asset_Modtime_Watcher, - type: Asset_Type, - path: name.Name, -) -> bool { - return chan.send(watcher.ops, Asset_Watcher_Op_Remove{type = type, path = path}) -} diff --git a/game/assets/watcher_desktop.odin b/game/assets/watcher_desktop.odin new file mode 100644 index 0000000..82b03e4 --- /dev/null +++ b/game/assets/watcher_desktop.odin @@ -0,0 +1,145 @@ +#+build !js + +package assets + +import "base:runtime" +import "common:name" +import "core:log" +import "core:sync/chan" +import "core:thread" +import "libs:physfs" + +ASSET_WATCHER_OPS_BUFFER :: 256 + +// Add asset to watch list +Asset_Watcher_Op_Add :: struct { + type: Asset_Type, + path: name.Name, + modtime: physfs.sint64, +} +// Remove asset from watch list +Asset_Watcher_Op_Remove :: struct { + type: Asset_Type, + path: name.Name, +} + +Asset_Watcher_Op :: union #no_nil { + Asset_Watcher_Op_Add, + Asset_Watcher_Op_Remove, +} + +Asset_Modtime_Watcher :: struct { + ops: chan.Chan(Asset_Watcher_Op), + modified_assets: chan.Chan(Watcher_Asset), + loaded_assets: [dynamic]Watcher_Asset, + thread: ^thread.Thread, +} + +modtime_watcher_init :: proc(watcher: ^Asset_Modtime_Watcher, allocator := context.allocator) { + err: runtime.Allocator_Error + watcher.ops, err = chan.create_buffered( + chan.Chan(Asset_Watcher_Op), + ASSET_WATCHER_OPS_BUFFER, + allocator, + ) + assert(err == nil) + watcher.modified_assets, err = chan.create_buffered( + chan.Chan(Watcher_Asset), + ASSET_WATCHER_OPS_BUFFER, + allocator, + ) + watcher.loaded_assets = make_dynamic_array([dynamic]Watcher_Asset, allocator) + + watcher.thread = thread.create(modtime_watcher_thread_proc) + watcher.thread.data = watcher + watcher_context := runtime.default_context() + watcher_context.logger = context.logger + watcher_context.allocator = context.allocator + watcher.thread.init_context = watcher_context + thread.start(watcher.thread) +} + +modtime_watcher_deinit :: proc(watcher: ^Asset_Modtime_Watcher) { + if !chan.is_closed(&watcher.ops) { + chan.close(&watcher.ops) + thread.join(watcher.thread) + watcher.thread = nil + } + + chan.destroy(&watcher.ops) + chan.close(&watcher.modified_assets) + chan.destroy(&watcher.modified_assets) + delete(watcher.loaded_assets) +} + +modtime_watcher_next :: proc(watcher: ^Asset_Modtime_Watcher) -> (asset: Watcher_Asset, ok: bool) { + return chan.try_recv(watcher.modified_assets) +} + +@(private = "file") +modtime_watcher_thread_proc :: proc(t: ^thread.Thread) { + watcher := cast(^Asset_Modtime_Watcher)t.data + + log.debugf("watcher thread") + + for !chan.is_closed(&watcher.ops) { + for recv_op in chan.try_recv(watcher.ops) { + switch op in recv_op { + case Asset_Watcher_Op_Add: + log.debugf("add [{}] {}", op.type, name.to_string(op.path)) + append( + &watcher.loaded_assets, + Watcher_Asset{type = op.type, path = op.path, modtime = op.modtime}, + ) + case Asset_Watcher_Op_Remove: + log.debugf("remove [{}] {}", op.type, name.to_string(op.path)) + i := 0 + for i < len(watcher.loaded_assets) { + if op.path == watcher.loaded_assets[i].path && + op.type == watcher.loaded_assets[i].type { + unordered_remove(&watcher.loaded_assets, i) + } else { + i += 1 + } + } + } + } + + for &asset in watcher.loaded_assets { + modtime := physfs.getLastModTime(name.to_cstring(asset.path)) + + if asset.modtime != modtime { + log.debugf("change [{}] {}", asset.type, name.to_string(asset.path)) + ok := chan.send( + watcher.modified_assets, + Watcher_Asset{type = asset.type, path = asset.path, modtime = modtime}, + ) + assert(ok) + } + asset.modtime = modtime + } + + // To avoid busy loop just in case + thread.yield() + } +} + +modtime_watcher_add_asset :: proc( + watcher: ^Asset_Modtime_Watcher, + type: Asset_Type, + path: name.Name, + modtime: physfs.sint64, +) -> bool { + return chan.send( + watcher.ops, + Asset_Watcher_Op_Add{type = type, path = path, modtime = modtime}, + ) +} + +modtime_watcher_remove_asset :: proc( + watcher: ^Asset_Modtime_Watcher, + type: Asset_Type, + path: name.Name, +) -> bool { + return chan.send(watcher.ops, Asset_Watcher_Op_Remove{type = type, path = path}) +} diff --git a/game/assets/watcher_js.odin b/game/assets/watcher_js.odin new file mode 100644 index 0000000..bfc6144 --- /dev/null +++ b/game/assets/watcher_js.odin @@ -0,0 +1,24 @@ +#+build js +package assets + +import "common:name" +import "libs:physfs" + +Asset_Modtime_Watcher :: struct {} + +modtime_watcher_init :: proc(watcher: ^Asset_Modtime_Watcher) {} + +modtime_watcher_next :: proc(watcher: ^Asset_Modtime_Watcher) -> (asset: Watcher_Asset, ok: bool) { + return {}, false +} + +modtime_watcher_add_asset :: proc( + watcher: ^Asset_Modtime_Watcher, + type: Asset_Type, + path: name.Name, + modtime: physfs.sint64, +) -> bool { + return true +} + +modtime_watcher_deinit :: proc(watcher: ^Asset_Modtime_Watcher) {} diff --git a/main_web/main_web.odin b/main_web/main_web.odin index 318d90d..10d5c54 100644 --- a/main_web/main_web.odin +++ b/main_web/main_web.odin @@ -25,7 +25,7 @@ main_start :: proc "c" () { // Since we now use js_wasm32 we should be able to remove this and use // context.logger = log.create_console_logger(). However, that one produces // extra newlines on web. So it's a bug in that core lib. - context.logger = create_emscripten_logger() + // context.logger = create_emscripten_logger() web_context = context