From 2c5ee0618bcfaf0f2e03abf904fb4ddd5066d044 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Mon, 6 Jan 2025 12:28:16 +0800 Subject: [PATCH] Fixed issues. [skip CI] * Improved logging by adding additional ImGui error messages. * Fixed potential crash issues with C++ callbacks invoked in WASM. --- Source/3rdParty/imgui/imconfig.h | 2 + Source/Common/Debug.cpp | 10 +++-- Source/Common/Debug.h | 6 +-- Source/Common/Utils.cpp | 32 ++++++++++++++++ Source/Common/Utils.h | 2 + Source/Wasm/Dora/BodyWasm.hpp | 2 +- Source/Wasm/Dora/ContentWasm.hpp | 4 +- Source/Wasm/Dora/DirectorWasm.hpp | 4 +- Source/Wasm/Dora/EntityGroupWasm.hpp | 2 +- Source/Wasm/Dora/HttpClientWasm.hpp | 2 +- Source/Wasm/Dora/ModelWasm.hpp | 2 +- Source/Wasm/Dora/NodeWasm.hpp | 10 ++--- Source/Wasm/Dora/PhysicsWorldWasm.hpp | 4 +- .../Dora/Platformer/Behavior/LeafWasm.hpp | 2 +- .../Dora/Platformer/Decision/LeafWasm.hpp | 4 +- Source/Wasm/Dora/Platformer/FaceWasm.hpp | 2 +- .../Wasm/Dora/Platformer/UnitActionWasm.hpp | 4 +- .../Dora/Platformer/WasmActionUpdateWasm.hpp | 2 +- Source/Wasm/WasmRuntime.cpp | 14 ++++++- Source/Wasm/WasmRuntime.h | 1 + Tools/WasmGen/Dora.h | 38 +++++++++---------- Tools/WasmGen/gen.yue | 25 +++++++++--- Tools/dora-wa/src/exceltest.wa | 2 +- 23 files changed, 120 insertions(+), 56 deletions(-) diff --git a/Source/3rdParty/imgui/imconfig.h b/Source/3rdParty/imgui/imconfig.h index bec081906..48d18724f 100644 --- a/Source/3rdParty/imgui/imconfig.h +++ b/Source/3rdParty/imgui/imconfig.h @@ -176,3 +176,5 @@ namespace ImGui #define IMGUI_DISABLE_OBSOLETE_KEYIO #define IMGUI_DEFINE_MATH_OPERATORS + +#define IMGUI_DEBUG_PRINTF(_FMT,...) Dora::LogErrorThreaded(Dora::sprintf(_FMT, __VA_ARGS__)) diff --git a/Source/Common/Debug.cpp b/Source/Common/Debug.cpp index 058a07841..05a5e9793 100644 --- a/Source/Common/Debug.cpp +++ b/Source/Common/Debug.cpp @@ -110,15 +110,17 @@ class Logger : public NonCopyable { } void log(spdlog::level::level_enum level, const std::string& msg) { - _logger->log(level, msg); + auto m = Slice(msg).trimSpace().toString(); + _logger->log(level, m); } void logAsync(spdlog::level::level_enum level, const std::string& msg) { + auto m = Slice(msg).trimSpace().toString(); if (Singleton::isDisposed()) { - _logger->log(level, msg); + _logger->log(level, m); } else { - _thread->run([this, level, msg]() { - _logger->log(level, msg); + _thread->run([this, level, m]() { + _logger->log(level, m); }); } } diff --git a/Source/Common/Debug.h b/Source/Common/Debug.h index d61a9a731..50952cc60 100644 --- a/Source/Common/Debug.h +++ b/Source/Common/Debug.h @@ -43,9 +43,9 @@ bool IsInLuaOrWasm(); #define WarnIf(...) DORA_DUMMY #define ErrorIf(...) DORA_DUMMY #else -#define Info(...) LogInfoThreaded(fmt::format(__VA_ARGS__)) -#define Warn(...) LogWarnThreaded(fmt::format(__VA_ARGS__)) -#define Error(...) LogErrorThreaded(fmt::format(__VA_ARGS__)) +#define Info(...) Dora::LogInfoThreaded(fmt::format(__VA_ARGS__)) +#define Warn(...) Dora::LogWarnThreaded(fmt::format(__VA_ARGS__)) +#define Error(...) Dora::LogErrorThreaded(fmt::format(__VA_ARGS__)) #define InfoIf(cond, ...) \ if (cond) { \ Info(__VA_ARGS__); \ diff --git a/Source/Common/Utils.cpp b/Source/Common/Utils.cpp index a9d93967f..80776cadd 100644 --- a/Source/Common/Utils.cpp +++ b/Source/Common/Utils.cpp @@ -195,4 +195,36 @@ void threadLoop(const std::function& work) { SharedDirector.getScheduler()->schedule(loop(work)); } +std::string sprintf(const char* fmt, ...) { + int size = 1024; + std::vector buffer(size); + + va_list args; + va_start(args, fmt); + int n = vsnprintf(buffer.data(), size, fmt, args); + va_end(args); + + if (n < 0) { + // vsnprintf 失败 + return ""; + } else if (n < size) { + // 格式化后的字符串已成功放入缓冲区 + return std::string(buffer.data(), n); + } else { + // 缓冲区不足,需要重新分配 + size = n + 1; + buffer.resize(size); + + va_start(args, fmt); + n = vsnprintf(buffer.data(), size, fmt, args); + va_end(args); + + if (n < 0 || n >= size) { + return ""; + } + + return std::string(buffer.data(), n); + } +} + NS_DORA_END diff --git a/Source/Common/Utils.h b/Source/Common/Utils.h index dda5e9945..0b1cdd5e2 100644 --- a/Source/Common/Utils.h +++ b/Source/Common/Utils.h @@ -532,4 +532,6 @@ std::function loop(const std::function& work); void thread(const std::function& work); void threadLoop(const std::function& work); +std::string sprintf(const char* fmt, ...); + NS_DORA_END diff --git a/Source/Wasm/Dora/BodyWasm.hpp b/Source/Wasm/Dora/BodyWasm.hpp index 62fdaebd3..ecbb4a67a 100644 --- a/Source/Wasm/Dora/BodyWasm.hpp +++ b/Source/Wasm/Dora/BodyWasm.hpp @@ -107,7 +107,7 @@ void body_on_contact_filter(int64_t self, int32_t func0, int64_t stack0) { args0->clear(); args0->push(body); SharedWasmRuntime.invoke(func0); - return std::get(args0->pop()); + return args0->pop_bool_or(false); }); } int64_t body_new(int64_t def, int64_t world, int64_t pos, float rot) { diff --git a/Source/Wasm/Dora/ContentWasm.hpp b/Source/Wasm/Dora/ContentWasm.hpp index d44f0752e..fa23d7ef1 100644 --- a/Source/Wasm/Dora/ContentWasm.hpp +++ b/Source/Wasm/Dora/ContentWasm.hpp @@ -114,7 +114,7 @@ void content_zip_async(int64_t folder_path, int64_t zip_file, int32_t func0, int args0->clear(); args0->push(file); SharedWasmRuntime.invoke(func0); - return std::get(args0->pop()); + return args0->pop_bool_or(false); }, [func1, args1, deref1](bool success) { args1->clear(); args1->push(success); @@ -134,7 +134,7 @@ void content_unzip_async(int64_t zip_file, int64_t folder_path, int32_t func0, i args0->clear(); args0->push(file); SharedWasmRuntime.invoke(func0); - return std::get(args0->pop()); + return args0->pop_bool_or(false); }, [func1, args1, deref1](bool success) { args1->clear(); args1->push(success); diff --git a/Source/Wasm/Dora/DirectorWasm.hpp b/Source/Wasm/Dora/DirectorWasm.hpp index 328ce68eb..49a9ed927 100644 --- a/Source/Wasm/Dora/DirectorWasm.hpp +++ b/Source/Wasm/Dora/DirectorWasm.hpp @@ -44,7 +44,7 @@ void director_schedule(int32_t func0, int64_t stack0) { args0->clear(); args0->push(deltaTime); SharedWasmRuntime.invoke(func0); - return std::get(args0->pop()); + return args0->pop_bool_or(true); }); } void director_schedule_posted(int32_t func0, int64_t stack0) { @@ -56,7 +56,7 @@ void director_schedule_posted(int32_t func0, int64_t stack0) { args0->clear(); args0->push(deltaTime); SharedWasmRuntime.invoke(func0); - return std::get(args0->pop()); + return args0->pop_bool_or(true); }); } void director_push_camera(int64_t camera) { diff --git a/Source/Wasm/Dora/EntityGroupWasm.hpp b/Source/Wasm/Dora/EntityGroupWasm.hpp index 238f2b6b1..8371dde0f 100644 --- a/Source/Wasm/Dora/EntityGroupWasm.hpp +++ b/Source/Wasm/Dora/EntityGroupWasm.hpp @@ -26,7 +26,7 @@ int64_t entitygroup_find(int64_t self, int32_t func0, int64_t stack0) { args0->clear(); args0->push(e); SharedWasmRuntime.invoke(func0); - return std::get(args0->pop()); + return args0->pop_bool_or(false); })); } int64_t entitygroup_new(int64_t components) { diff --git a/Source/Wasm/Dora/HttpClientWasm.hpp b/Source/Wasm/Dora/HttpClientWasm.hpp index bc1affc0d..f987a0322 100644 --- a/Source/Wasm/Dora/HttpClientWasm.hpp +++ b/Source/Wasm/Dora/HttpClientWasm.hpp @@ -52,7 +52,7 @@ void httpclient_download_async(int64_t url, int64_t full_path, float timeout, in args0->push(current); args0->push(total); SharedWasmRuntime.invoke(func0); - return std::get(args0->pop()); + return args0->pop_bool_or(true); }); } } // extern "C" diff --git a/Source/Wasm/Dora/ModelWasm.hpp b/Source/Wasm/Dora/ModelWasm.hpp index bbc1769fb..4e1b15bce 100644 --- a/Source/Wasm/Dora/ModelWasm.hpp +++ b/Source/Wasm/Dora/ModelWasm.hpp @@ -56,7 +56,7 @@ int32_t model_each_node(int64_t self, int32_t func0, int64_t stack0) { args0->clear(); args0->push(node); SharedWasmRuntime.invoke(func0); - return std::get(args0->pop()); + return args0->pop_bool_or(false); }) ? 1 : 0; } int64_t model_new(int64_t filename) { diff --git a/Source/Wasm/Dora/NodeWasm.hpp b/Source/Wasm/Dora/NodeWasm.hpp index 949e684e4..5fc7c5076 100644 --- a/Source/Wasm/Dora/NodeWasm.hpp +++ b/Source/Wasm/Dora/NodeWasm.hpp @@ -275,7 +275,7 @@ void node_schedule(int64_t self, int32_t func0, int64_t stack0) { args0->clear(); args0->push(deltaTime); SharedWasmRuntime.invoke(func0); - return std::get(args0->pop()); + return args0->pop_bool_or(true); }); } void node_unschedule(int64_t self) { @@ -307,7 +307,7 @@ int32_t node_each_child(int64_t self, int32_t func0, int64_t stack0) { args0->clear(); args0->push(child); SharedWasmRuntime.invoke(func0); - return std::get(args0->pop()); + return args0->pop_bool_or(true); }) ? 1 : 0; } int32_t node_traverse(int64_t self, int32_t func0, int64_t stack0) { @@ -319,7 +319,7 @@ int32_t node_traverse(int64_t self, int32_t func0, int64_t stack0) { args0->clear(); args0->push(child); SharedWasmRuntime.invoke(func0); - return std::get(args0->pop()); + return args0->pop_bool_or(true); }) ? 1 : 0; } int32_t node_traverse_all(int64_t self, int32_t func0, int64_t stack0) { @@ -331,7 +331,7 @@ int32_t node_traverse_all(int64_t self, int32_t func0, int64_t stack0) { args0->clear(); args0->push(child); SharedWasmRuntime.invoke(func0); - return std::get(args0->pop()); + return args0->pop_bool_or(true); }) ? 1 : 0; } float node_run_action_def(int64_t self, int64_t def, int32_t looped) { @@ -425,7 +425,7 @@ void node_on_update(int64_t self, int32_t func0, int64_t stack0) { args0->clear(); args0->push(deltaTime); SharedWasmRuntime.invoke(func0); - return std::get(args0->pop()); + return args0->pop_bool_or(true); }); } int64_t node_new() { diff --git a/Source/Wasm/Dora/PhysicsWorldWasm.hpp b/Source/Wasm/Dora/PhysicsWorldWasm.hpp index 73a099ed9..8f3c7dab7 100644 --- a/Source/Wasm/Dora/PhysicsWorldWasm.hpp +++ b/Source/Wasm/Dora/PhysicsWorldWasm.hpp @@ -20,7 +20,7 @@ int32_t physicsworld_query(int64_t self, int64_t rect, int32_t func0, int64_t st args0->clear(); args0->push(body); SharedWasmRuntime.invoke(func0); - return std::get(args0->pop()); + return args0->pop_bool_or(false); }) ? 1 : 0; } int32_t physicsworld_raycast(int64_t self, int64_t start, int64_t stop, int32_t closest, int32_t func0, int64_t stack0) { @@ -34,7 +34,7 @@ int32_t physicsworld_raycast(int64_t self, int64_t start, int64_t stop, int32_t args0->push(point); args0->push(normal); SharedWasmRuntime.invoke(func0); - return std::get(args0->pop()); + return args0->pop_bool_or(false); }) ? 1 : 0; } void physicsworld_set_iterations(int64_t self, int32_t velocity_iter, int32_t position_iter) { diff --git a/Source/Wasm/Dora/Platformer/Behavior/LeafWasm.hpp b/Source/Wasm/Dora/Platformer/Behavior/LeafWasm.hpp index e19d2f5ac..29b6a853c 100644 --- a/Source/Wasm/Dora/Platformer/Behavior/LeafWasm.hpp +++ b/Source/Wasm/Dora/Platformer/Behavior/LeafWasm.hpp @@ -26,7 +26,7 @@ int64_t platformer_behavior_leaf_con(int64_t name, int32_t func0, int64_t stack0 args0->clear(); args0->push(r_cast(blackboard)); SharedWasmRuntime.invoke(func0); - return std::get(args0->pop()); + return args0->pop_bool_or(false); })); } int64_t platformer_behavior_leaf_act(int64_t action_name) { diff --git a/Source/Wasm/Dora/Platformer/Decision/LeafWasm.hpp b/Source/Wasm/Dora/Platformer/Decision/LeafWasm.hpp index ed86ebf4a..6bac1cbcd 100644 --- a/Source/Wasm/Dora/Platformer/Decision/LeafWasm.hpp +++ b/Source/Wasm/Dora/Platformer/Decision/LeafWasm.hpp @@ -26,7 +26,7 @@ int64_t platformer_decision_leaf_con(int64_t name, int32_t func0, int64_t stack0 args0->clear(); args0->push(unit); SharedWasmRuntime.invoke(func0); - return std::get(args0->pop()); + return args0->pop_bool_or(false); })); } int64_t platformer_decision_leaf_act(int64_t action_name) { @@ -41,7 +41,7 @@ int64_t platformer_decision_leaf_act_dynamic(int32_t func0, int64_t stack0) { args0->clear(); args0->push(unit); SharedWasmRuntime.invoke(func0); - return std::get(args0->pop()); + return args0->empty() ? ""s : std::get(args0->pop()); })); } int64_t platformer_decision_leaf_accept() { diff --git a/Source/Wasm/Dora/Platformer/FaceWasm.hpp b/Source/Wasm/Dora/Platformer/FaceWasm.hpp index aabf76881..06aa4414b 100644 --- a/Source/Wasm/Dora/Platformer/FaceWasm.hpp +++ b/Source/Wasm/Dora/Platformer/FaceWasm.hpp @@ -28,7 +28,7 @@ int64_t platformer_face_with_func(int32_t func0, int64_t stack0, int64_t point, return Object_From(Platformer::Face::create([func0, args0, deref0]() { args0->clear(); SharedWasmRuntime.invoke(func0); - return s_cast(std::get(args0->pop())); + return args0->empty() ? Node::create() : s_cast(std::get(args0->pop())); }, Vec2_From(point), scale, angle)); } } // extern "C" diff --git a/Source/Wasm/Dora/Platformer/UnitActionWasm.hpp b/Source/Wasm/Dora/Platformer/UnitActionWasm.hpp index 4ed141ca1..75df2191a 100644 --- a/Source/Wasm/Dora/Platformer/UnitActionWasm.hpp +++ b/Source/Wasm/Dora/Platformer/UnitActionWasm.hpp @@ -53,13 +53,13 @@ void platformer_unitaction_add(int64_t name, int32_t priority, float reaction, f args0->push(owner); args0->push(r_cast(action)); SharedWasmRuntime.invoke(func0); - return std::get(args0->pop()); + return args0->pop_bool_or(false); }, [func1, args1, deref1](Platformer::Unit* owner, Platformer::UnitAction* action) { args1->clear(); args1->push(owner); args1->push(r_cast(action)); SharedWasmRuntime.invoke(func1); - return s_cast(std::get(args1->pop())); + return args1->empty()? Platformer::WasmActionUpdate::create([](Platformer::Unit*, Platformer::UnitAction*, float) { return true; }) : s_cast(std::get(args1->pop())); }, [func2, args2, deref2](Platformer::Unit* owner, Platformer::UnitAction* action) { args2->clear(); args2->push(owner); diff --git a/Source/Wasm/Dora/Platformer/WasmActionUpdateWasm.hpp b/Source/Wasm/Dora/Platformer/WasmActionUpdateWasm.hpp index 15d6c7db3..0f78f1139 100644 --- a/Source/Wasm/Dora/Platformer/WasmActionUpdateWasm.hpp +++ b/Source/Wasm/Dora/Platformer/WasmActionUpdateWasm.hpp @@ -22,7 +22,7 @@ int64_t platformer_wasmactionupdate_new(int32_t func0, int64_t stack0) { args0->push(r_cast(action)); args0->push(deltaTime); SharedWasmRuntime.invoke(func0); - return std::get(args0->pop()); + return args0->pop_bool_or(true); })); } } // extern "C" diff --git a/Source/Wasm/WasmRuntime.cpp b/Source/Wasm/WasmRuntime.cpp index ea220b0b1..9ab5d1c49 100644 --- a/Source/Wasm/WasmRuntime.cpp +++ b/Source/Wasm/WasmRuntime.cpp @@ -225,6 +225,18 @@ dora_val_t CallStack::pop() { return var; } +bool CallStack::pop_bool_or(bool def) { + if (_stack.empty()) { + return def; + } + auto var = _stack.front(); + _stack.pop_front(); + if (std::holds_alternative(var)) { + return std::get(var); + } + return def; +} + dora_val_t& CallStack::front() { return _stack.front(); } @@ -1939,7 +1951,7 @@ void WasmRuntime::invoke(int32_t funcId) { DEFER(_callFromWasm--); _callFunc->call(funcId); } catch (std::runtime_error& e) { - Error("failed to execute wasm module due to: {}{}", e.what(), _runtime->get_error_message() == Slice::Empty ? Slice::Empty : ": "s + _runtime->get_error_message()); + Error("failed to execute wasm callback due to: {}{}", e.what(), _runtime->get_error_message() == Slice::Empty ? Slice::Empty : ": "s + _runtime->get_error_message()); } } diff --git a/Source/Wasm/WasmRuntime.h b/Source/Wasm/WasmRuntime.h index f29a68508..c50440ddd 100644 --- a/Source/Wasm/WasmRuntime.h +++ b/Source/Wasm/WasmRuntime.h @@ -49,6 +49,7 @@ class CallStack { bool empty() const; dora_val_t pop(); dora_val_t& front(); + bool pop_bool_or(bool def); void clear(); private: diff --git a/Tools/WasmGen/Dora.h b/Tools/WasmGen/Dora.h index 34d3b8b92..dc80219e9 100644 --- a/Tools/WasmGen/Dora.h +++ b/Tools/WasmGen/Dora.h @@ -265,7 +265,7 @@ object class EntityGroup @ Group /// # Returns /// /// * `Option` - The first entity that satisfies the predicate, or None if no entity does. - optional Entity* find(function predicate) const; + optional Entity* find(function predicate) const; /// A method that creates a new group with the specified component names. /// /// # Arguments @@ -625,7 +625,7 @@ singleton class Content /// # Returns /// /// * `bool` - `true` if the folder was compressed successfully, `false` otherwise. - void zipAsync(string folderPath, string zipFile, function filter, function callback); + void zipAsync(string folderPath, string zipFile, function filter, function callback); /// Asynchronously decompresses a ZIP archive to the specified folder. /// /// # Arguments @@ -638,7 +638,7 @@ singleton class Content /// # Returns /// /// * `bool` - `true` if the folder was decompressed successfully, `false` otherwise. - void unzipAsync(string zipFile, string folderPath, function filter, function callback); + void unzipAsync(string zipFile, string folderPath, function filter, function callback); outside WorkBook content_wasm_load_excel @ load_excel(string filename); }; @@ -838,13 +838,13 @@ singleton class Director /// # Arguments /// /// * `updateFunc` - The function to call every frame. - outside void Director_Schedule @ schedule(function updateFunc); + outside void Director_Schedule @ schedule(function updateFunc); /// Schedule a function to be called every frame for processing post game logic. /// /// # Arguments /// /// * `func` - The function to call every frame. - outside void Director_SchedulePosted @ schedulePosted(function updateFunc); + outside void Director_SchedulePosted @ schedulePosted(function updateFunc); /// Adds a new camera to Director's camera stack and sets it to the current camera. /// /// # Arguments @@ -1313,7 +1313,7 @@ interface object class Node /// # Arguments /// /// * `updateFunc` - The function to be called. If the function returns `true`, it will not be called again. - void schedule(function updateFunc); + void schedule(function updateFunc); /// Unschedules the current node's scheduled main function. void unschedule(); /// Converts a point from world space to node space. @@ -1356,7 +1356,7 @@ interface object class Node /// # Returns /// /// * `bool` - `false` if all children have been visited, `true` if the iteration was interrupted by the function. - bool eachChild(function visitorFunc); + bool eachChild(function visitorFunc); /// Traverses the node hierarchy starting from this node and calls the given function for each visited node. The nodes without `TraverseEnabled` flag are not visited. /// /// # Arguments @@ -1366,7 +1366,7 @@ interface object class Node /// # Returns /// /// * `bool` - `false` if all nodes have been visited, `true` if the traversal was interrupted by the function. - bool traverse(function visitorFunc); + bool traverse(function visitorFunc); /// Traverses the entire node hierarchy starting from this node and calls the given function for each visited node. /// /// # Arguments @@ -1376,7 +1376,7 @@ interface object class Node /// # Returns /// /// * `bool` - `false` if all nodes have been visited, `true` if the traversal was interrupted by the function. - bool traverseAll(function visitorFunc); + bool traverseAll(function visitorFunc); /// Runs an action defined by the given action definition on this node. /// /// # Arguments @@ -1550,7 +1550,7 @@ interface object class Node /// # Arguments /// /// * `updateFunc` - The function to run every frame. If the function returns `true`, it will not be called again. - void onUpdate(function updateFunc); + void onUpdate(function updateFunc); /// Creates a new instance of the `Node` struct. static Node* create(); }; @@ -2174,7 +2174,7 @@ object class Model : public IPlayable /// # Returns /// /// * `bool` - Whether the function was called for all nodes or not. - bool eachNode(function visitorFunc); + bool eachNode(function visitorFunc); /// Creates a new instance of 'Model' from the specified model file. /// /// # Arguments @@ -2517,7 +2517,7 @@ interface object class PhysicsWorld : public INode /// # Returns /// /// * `bool` - Whether the query was interrupted. `true` means interrupted, `false` otherwise. - bool query(Rect rect, function handler); + bool query(Rect rect, function handler); /// Casts a ray through the physics world and finds the first body that intersects with the ray. /// /// # Arguments @@ -2530,7 +2530,7 @@ interface object class PhysicsWorld : public INode /// # Returns /// /// * `bool` - Whether the raycast was interrupted. `true` means interrupted, `false` otherwise. - bool raycast(Vec2 start, Vec2 stop, bool closest, function handler); + bool raycast(Vec2 start, Vec2 stop, bool closest, function handler); /// Sets the number of velocity and position iterations to perform in the physics world. /// /// # Arguments @@ -3003,7 +3003,7 @@ interface object class Body : public INode /// # Arguments /// /// * `filter` - The filter function to set. - void onContactFilter(function filter); + void onContactFilter(function filter); /// Creates a new instance of `Body`. /// /// # Arguments @@ -4047,7 +4047,7 @@ singleton class HttpClient /// * `timeout` - The timeout in seconds for the request. /// * `progress` - A callback function that is called periodically to report the download progress. /// The function receives three parameters: `interrupted` (a boolean value indicating whether the download was interrupted), `current` (the number of bytes downloaded so far) and `total` (the total number of bytes to be downloaded). - void downloadAsync(string url, string fullPath, float timeout, function progress); + void downloadAsync(string url, string fullPath, float timeout, function progress); }; namespace Platformer { @@ -4276,7 +4276,7 @@ object class Leaf @ Tree /// # Returns /// /// * `Leaf` - A new condition node. - static outside Platformer::Behavior::Leaf* BCon @ con(string name, function handler); + static outside Platformer::Behavior::Leaf* BCon @ con(string name, function handler); /// Creates a new action node that executes an action when executed. /// This node will block the execution until the action finishes. /// @@ -4416,7 +4416,7 @@ object class Leaf @ Tree /// # Returns /// /// * A `Leaf` node that represents a condition check. - static outside Platformer::Decision::Leaf* DCon @ con(string name, function handler); + static outside Platformer::Decision::Leaf* DCon @ con(string name, function handler); /// Creates an action node with the specified action name. /// /// # Arguments @@ -4531,7 +4531,7 @@ singleton class AI object class WasmActionUpdate @ ActionUpdate { - static WasmActionUpdate* create(function update); + static WasmActionUpdate* create(function update); }; /// A struct that represents an action that can be performed by a "Unit". @@ -4567,7 +4567,7 @@ class UnitAction /// * `stop` - A function that takes a `Unit` object and a `UnitAction` object and stops the "UnitAction". static outside void Platformer_UnitAction_Add @ add( string name, int priority, float reaction, float recovery, bool queued, - function available, + function available, function create, function stop); }; diff --git a/Tools/WasmGen/gen.yue b/Tools/WasmGen/gen.yue index 557b24690..bfafcddde 100755 --- a/Tools/WasmGen/gen.yue +++ b/Tools/WasmGen/gen.yue @@ -958,6 +958,8 @@ FieldLabel = C(P"static")^-1 * White * C(P"optional")^-1 * White * C(P"readonly" MethodLabel = C(P"static")^-1 * White * C(P"outside")^-1 * White * C(P"optional")^-1 +FuncLabel = C(P"def_true" + P"def_false" + P"")^-1 + Type = C (Indent * White * P"::" * White)^0 * Indent * (White * P"*")^-1 Doc = C P"///" * (-Newline * P(1))^0 @@ -969,7 +971,7 @@ mark = (name) -> (...) -> {name, ...} Param = P { "Param" Param: V"Func" * White * Name / mark"callback" + Type * White * Name / mark"variable" - Func: Ct P"function<" * White * Type * White * Ct P"(" * White * (V"Param" * (White * P"," * White * V"Param")^0 * White)^-1 * P")" * White * P">" + Func: Ct P"function<" * White * FuncLabel * White * Type * White * Ct P"(" * White * (V"Param" * (White * P"," * White * V"Param")^0 * White)^-1 * P")" * White * P">" } Method = Docs * Ct(White * MethodLabel) * White * Type * White * (C(P"operator==") + Name) * White * (P"@" * White * Name + Cc false) * White * Ct(P"(" * White * (Param * (White * P"," * White * Param)^0 * White)^-1 * P")") * White * C(P"const")^-1 * White * P";" / mark"method" @@ -1490,7 +1492,7 @@ func #{waNewName}.GetRaw() => i64 { fnArgId = tostring funcArgCount [_, func, fname] = arg fname = toSnakeCase fname - [freturnType, fargs] = func + [flabel, freturnType, fargs] = func items = for farg in *fargs [fargKind, fargType, fargName] = farg if fargKind ~= "variable" @@ -1563,12 +1565,23 @@ func #{waNewName}.GetRaw() => i64 { if frCppType := cppTypes[frt] callbackReturn = switch freturnType when "Node" - "\t\treturn s_cast(std::get(args#{fnArgId}->pop()));\n" + "\t\treturn args#{fnArgId}->empty() ? Node::create() : s_cast(std::get(args#{fnArgId}->pop()));\n" when "string" - "\t\treturn std::get(args#{fnArgId}->pop());\n" + "\t\treturn args#{fnArgId}->empty() ? \"\"s : std::get(args#{fnArgId}->pop());\n" when "Platformer::WasmActionUpdate" - "\t\treturn s_cast(std::get(args#{fnArgId}->pop()));\n" + defItem = "Platformer::WasmActionUpdate::create([](Platformer::Unit*, Platformer::UnitAction*, float) { return true; })" + "\t\treturn args#{fnArgId}->empty()? #{defItem} : s_cast(std::get(args#{fnArgId}->pop()));\n" + when "bool" + switch flabel + when "def_true" + "\t\treturn args#{fnArgId}->pop_bool_or(true);\n" + when "def_false" + "\t\treturn args#{fnArgId}->pop_bool_or(false);\n" + else + print "missing [def_true|def_false] for callback return in #{funcNewName}" + "\t\treturn args#{fnArgId}->pop_bool_or(false);\n" else + print "callback return type \"#{freturnType}\" not handled in #{funcNewName}" "\t\treturn std::get<#{freturnType}>(args#{fnArgId}->pop());\n" callback = "let result = #{callback};\n\t\t\t#{frPush 'result', fnArgId}" argPassed = true @@ -1707,7 +1720,7 @@ func #{waNewName}.GetRaw() => i64 { fnArgId = tostring funcArgCount [_, func, fname] = arg fname = toSnakeCase fname - [freturnType, fargs] = func + [flabel, freturnType, fargs] = func freturnTypeName = freturnType\match "[^ \t*]+" freturnName = nameMap[freturnTypeName] or freturnTypeName rtpObj = getWaType freturnType, freturnName diff --git a/Tools/dora-wa/src/exceltest.wa b/Tools/dora-wa/src/exceltest.wa index 014933eab..cd5c3eee1 100644 --- a/Tools/dora-wa/src/exceltest.wa +++ b/Tools/dora-wa/src/exceltest.wa @@ -387,7 +387,7 @@ func test_excel_test() { observer := dora.NewObserver(dora.EntityEventRemove, &[]string{"body"}) observer.Watch(func(stack: dora.CallStack) => bool { entity := *dora.ObjectAsEntity(*stack.PopObject()) - body_val := entity.Get("body") + body_val := entity.GetOld("body") if body_val == nil { return false }