From f668ff6b7a5a52013ab6da2f63c39fb866b665c2 Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Wed, 25 Jun 2025 14:28:35 -0400 Subject: [PATCH] First round of cleanup. dnd_loot. --- dinkyecs.hpp | 2 - gui/dnd_loot.cpp | 87 ++++++++++++++++++++------------- gui/dnd_loot.hpp | 2 + meson.build | 3 ++ scratchpad/corostate.cpp | 97 +++++++++++++++++++++++++++++++++++++ scripts/coverage_report.ps1 | 2 +- tests/components.cpp | 2 + tests/config.cpp | 8 +++ tests/config_test.json | 4 ++ 9 files changed, 169 insertions(+), 38 deletions(-) create mode 100644 scratchpad/corostate.cpp create mode 100644 tests/config_test.json diff --git a/dinkyecs.hpp b/dinkyecs.hpp index 34b4869..d2e2f71 100644 --- a/dinkyecs.hpp +++ b/dinkyecs.hpp @@ -62,12 +62,10 @@ namespace DinkyECS } void make_constant(DinkyECS::Entity entity) { - fmt::println(">>> Entity {} is now constant", entity); $constants.try_emplace(entity, true); } void not_constant(DinkyECS::Entity entity) { - fmt::println("<<< Entity {} is NOT constant", entity); $constants.erase(entity); } diff --git a/gui/dnd_loot.cpp b/gui/dnd_loot.cpp index edce61c..4f37164 100644 --- a/gui/dnd_loot.cpp +++ b/gui/dnd_loot.cpp @@ -29,8 +29,9 @@ namespace gui { } void DNDLoot::START(Event ev) { - dbc::check(ev == Event::STARTED, "START not given a STARTED event."); - END(Event::CLOSE); + using enum Event; + dbc::check(ev == STARTED, "START not given a STARTED event."); + END(CLOSE); } void DNDLoot::LOOTING(Event ev, std::any data) { @@ -38,7 +39,7 @@ namespace gui { switch(ev) { case LOOT_OPEN: - END(Event::CLOSE); + END(CLOSE); break; case LOOT_SELECT: $grab_source = start_grab($loot_ui.$gui, data); @@ -49,7 +50,7 @@ namespace gui { if($grab_source) state(DNDState::INV_GRAB); break; default: - state(DNDState::LOOTING); + break; // ignore } } @@ -58,7 +59,7 @@ namespace gui { switch(ev) { case LOOT_OPEN: - END(Event::CLOSE); + END(CLOSE); break; case LOOT_SELECT: commit_move($loot_ui.$gui, $grab_source, data); @@ -81,7 +82,7 @@ namespace gui { switch(ev) { case LOOT_OPEN: - END(Event::CLOSE); + END(CLOSE); break; case LOOT_SELECT: if(commit_drop($status_ui.$gui, @@ -107,12 +108,12 @@ namespace gui { case AIM_CLICK: { bool worked = throw_on_floor(); dbc::check(worked, "Need to fix this, should be able to abort."); - END(Event::CLOSE); + END(CLOSE); } break; case INV_SELECT: // BUG: should I do a bool here and not transition? commit_move($status_ui.$gui, $grab_source, data); - END(Event::CLOSE); + END(CLOSE); break; default: handle_mouse(ev, $status_ui.$gui); @@ -126,13 +127,17 @@ namespace gui { case INV_SELECT: if(commit_drop($loot_ui.$gui, $status_ui.$gui, $grab_source, data)) { - END(Event::CLOSE); + END(CLOSE); } break; - case LOOT_ITEM: + case AIM_CLICK: + // BUG: because I put things into fake loot containers it's actually + // hard to put things back. It's probably a System::remove from the + // loot container combined with a System::drop_item + dbc::log("Put it back?"); break; default: - handle_mouse(ev, $loot_ui.$gui); + handle_mouse(ev, $loot_ui.$gui); } } @@ -140,30 +145,14 @@ namespace gui { using enum Event; switch(ev) { - case LOOT_ITEM: { - // NOTE: if > 1 items, go to LOOT_OPEN instead - auto gui_id = $loot_ui.$gui.entity("item_0"); - $grab_source = start_grab($loot_ui.$gui, gui_id); - - if($grab_source) { - auto& source = $loot_ui.$gui.get(*$grab_source); - $grab_sprite = source.sprite; - // call this once to properly position the sprite - handle_mouse(Event::MOUSE_MOVE, $loot_ui.$gui); - state(DNDState::ITEM_PICKUP); - } - } break; - case INV_SELECT: { - $grab_source = start_grab($status_ui.$gui, data); - - if($grab_source) { - auto& source = $status_ui.$gui.get(*$grab_source); - $grab_sprite = source.sprite; - state(DNDState::INV_PICKUP); - } else { - dbc::log("inv slot empty"); - } - } break; + case LOOT_ITEM: + hold_world_item(); + state(DNDState::ITEM_PICKUP); + break; + case INV_SELECT: + hold_inv_item(data); + state(DNDState::INV_PICKUP); + break; case LOOT_OPEN: open(); state(DNDState::LOOTING); @@ -268,14 +257,42 @@ namespace gui { // Or, maybe save the commit? } + void DNDLoot::hold_world_item() { + // NOTE: if > 1 items, go to LOOT_OPEN instead + auto gui_id = $loot_ui.$gui.entity("item_0"); + $grab_source = start_grab($loot_ui.$gui, gui_id); + + if($grab_source) { + auto& source = $loot_ui.$gui.get(*$grab_source); + $grab_sprite = source.sprite; + // call this once to properly position the sprite + handle_mouse(Event::MOUSE_MOVE, $loot_ui.$gui); + } + } + + void DNDLoot::hold_inv_item(std::any& data) { + $grab_source = start_grab($status_ui.$gui, data); + + if($grab_source) { + auto& source = $status_ui.$gui.get(*$grab_source); + $grab_sprite = source.sprite; + } else { + dbc::log("inv slot empty"); + } + } + /* * Dropping on the ground is only possible from the * status_ui for now. */ bool DNDLoot::throw_on_floor() { dbc::check($grab_source != std::nullopt, "attempt to commit_drop but no grab_source set"); + dbc::check($status_ui.$gui.has(*$grab_source), + "StatusUI doesn't actually have that GrabSource in the gui."); + auto& grab = $status_ui.$gui.get(*$grab_source); grab.commit(); + bool result = $status_ui.drop_item(grab.world_entity); clear_grab(); return result; diff --git a/gui/dnd_loot.hpp b/gui/dnd_loot.hpp index 7e211ae..c2d6b8e 100644 --- a/gui/dnd_loot.hpp +++ b/gui/dnd_loot.hpp @@ -52,6 +52,8 @@ namespace gui { void commit_move(guecs::UI& gui, std::optional source_id, std::any data); + void hold_world_item(); + void hold_inv_item(std::any& data); bool throw_on_floor(); void clear_grab(); diff --git a/meson.build b/meson.build index c4b211d..0fa9017 100644 --- a/meson.build +++ b/meson.build @@ -159,6 +159,9 @@ executable('runtests', sources + [ override_options: exe_defaults, dependencies: dependencies + [catch2]) +executable('corostate', + ['scratchpad/corostate.cpp'], + dependencies: [fmt]) executable('zedcaster', sources + [ 'main.cpp' ], diff --git a/scratchpad/corostate.cpp b/scratchpad/corostate.cpp new file mode 100644 index 0000000..a11662c --- /dev/null +++ b/scratchpad/corostate.cpp @@ -0,0 +1,97 @@ +#include +#include +#include +#include + + +template +struct Generator { + struct promise_type; + using handle_type = std::coroutine_handle; + + struct promise_type { + T value_; + std::exception_ptr exception_; + + Generator get_return_object() { + return Generator(handle_type::from_promise(*this)); + } + std::suspend_always initial_suspend() { return {}; } + std::suspend_always final_suspend() noexcept { return {}; } + void unhandled_exception() { exception_ = std::current_exception(); } + + template From> + std::suspend_always yield_value(From&& from) { + value_ = std::forward(from); + return {}; + } + void return_void() {} + }; + + handle_type h_; + + Generator(handle_type h) : h_(h) {} + ~Generator() { h_.destroy(); } + explicit operator bool() { + fill(); + return !h_.done(); + } + + T operator()() { + fill(); + full_ = false; + return std::move(h_.promise().value_); + } + +private: + bool full_ = false; + + void fill() { + if(!full_) { + h_(); + if(h_.promise().exception_) { + std::rethrow_exception(h_.promise().exception_); + } + + full_ = true; + } + } +}; + +Generator +fib(unsigned n) { + if(n == 0) co_return; + if(n > 94) { + throw std::runtime_error("Too big"); + } + + if(n == 1) co_return; + + co_yield 1; + + if(n == 2) co_return; + + std::uint64_t a = 0; + std::uint64_t b = 1; + for(unsigned i = 2; i < n; ++i) { + std::uint64_t s = a + b; + co_yield s; + a = b; + b = s; + } +} + +int main() { + try { + auto gen = fib(50); + for(int j = 0; gen; ++j) { + fmt::println("fib({})={}", j, gen()); + } + } catch(const std::exception& ex) { + fmt::println("Exception: {}", ex.what()); + } catch(...) { + fmt::println("Unknown exception"); + } + + return 0; +} diff --git a/scripts/coverage_report.ps1 b/scripts/coverage_report.ps1 index 79e38de..f31b229 100644 --- a/scripts/coverage_report.ps1 +++ b/scripts/coverage_report.ps1 @@ -6,7 +6,7 @@ cp *.cpp,*.hpp,*.rl builddir rm -recurse -force coverage cp scripts\gcovr_patched_coverage.py .venv\Lib\site-packages\gcovr\coverage.py -gcovr -o coverage/ --html --html-details --html-theme github.dark-blue --gcov-ignore-errors all --gcov-ignore-parse-errors negative_hits.warn_once_per_file -e builddir/subprojects -e builddir -e subprojects -j 10 . +gcovr -o coverage/ --html --html-details --html-theme github.dark-blue --gcov-ignore-errors all --gcov-ignore-parse-errors negative_hits.warn_once_per_file -e builddir/subprojects -e builddir -e subprojects -e scratchpad -e tools -j 10 . rm *.gcov.json.gz diff --git a/tests/components.cpp b/tests/components.cpp index 538dc8b..bafb750 100644 --- a/tests/components.cpp +++ b/tests/components.cpp @@ -24,6 +24,8 @@ TEST_CASE("confirm component loading works", "[components]") { fmt::println("TEST COMPONENT: {} from file {}", key, test_data); auto ent = world.entity(); components::configure_entity(world, ent, components); + auto tile = components::get(components[0]); + REQUIRE(tile.display != L' '); } } } diff --git a/tests/config.cpp b/tests/config.cpp index f7b41e6..4b49d72 100644 --- a/tests/config.cpp +++ b/tests/config.cpp @@ -3,6 +3,7 @@ #include TEST_CASE("confirm basic config loader ops", "[config]") { + Config::set_base_dir("./"); Config config("assets/devices.json"); auto data_list = config.json(); auto the_keys = config.keys(); @@ -17,4 +18,11 @@ TEST_CASE("confirm basic config loader ops", "[config]") { REQUIRE(comp_data.contains("_type")); } } + + Config indexed("tests/config_test.json"); + auto& test_0 = indexed[0]; + REQUIRE(test_0["test"] == 0); + + auto& test_1 = indexed[1]; + REQUIRE(test_1["test"] == 1); } diff --git a/tests/config_test.json b/tests/config_test.json new file mode 100644 index 0000000..2b58790 --- /dev/null +++ b/tests/config_test.json @@ -0,0 +1,4 @@ +[ + {"test": 0}, + {"test": 1} +]