From 0d481a5ab7caeb1a8d0890f2f07af205d821fa91 Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Sat, 7 Feb 2026 13:05:24 -0500 Subject: [PATCH] Animator won't crash anymore when there's an error, and instead displays an error message. --- Makefile | 5 +++- animate2.cpp | 7 ++++++ animate2.hpp | 1 + tests/animate2.cpp | 13 ++++++---- tools/animator.cpp | 63 ++++++++++++++++++++++++++++++++++++++-------- tools/animator.hpp | 5 +++- 6 files changed, 76 insertions(+), 18 deletions(-) diff --git a/Makefile b/Makefile index a30e660..dfbae2d 100644 --- a/Makefile +++ b/Makefile @@ -77,5 +77,8 @@ arena: story: gdb --nx -x .gdbinit --batch --ex run --ex bt --ex q --args ./builddir/storyboard -animator: +debug_animator: gdb --nx -x .gdbinit --batch --ex run --ex bt --ex q --args ./builddir/animator.exe -s "rat_king_boss" -a "rat_king_boss" -b "test_background" + +animator: + ./builddir/animator.exe -s "rat_king_boss" -a "rat_king_boss" -b "test_background" diff --git a/animate2.cpp b/animate2.cpp index fa4a621..70f8ecc 100644 --- a/animate2.cpp +++ b/animate2.cpp @@ -51,6 +51,7 @@ namespace animate2 { } void Animate2::play_sound() { + // BUG: this can be optimized way better if(sounds.contains(form_name)) { fmt::println("Playing sound for {}", form_name); for(auto& [at_frame, sound_name] : sounds.at(form_name)) { @@ -58,6 +59,8 @@ namespace animate2 { sound::play(sound_name); } } + } else { + fmt::println("Animation has not sound {}", form_name); } } @@ -169,6 +172,10 @@ namespace animate2 { // scale_out.x, scale_out.y); } + bool Animate2::has_form(const std::string& as_form) { + return forms.contains(as_form); + } + void Animate2::set_form(const std::string& as_form) { dbc::check(forms.contains(as_form), fmt::format("form {} does not exist in animation", as_form)); diff --git a/animate2.hpp b/animate2.hpp index 6cdd8c2..52f93b8 100644 --- a/animate2.hpp +++ b/animate2.hpp @@ -113,6 +113,7 @@ namespace animate2 { void play(); void play_sound(); void stop(); + bool has_form(const std::string& as_form); void set_form(const std::string& form); void apply(sf::Sprite& sprite); void update_frame(); diff --git a/tests/animate2.cpp b/tests/animate2.cpp index 2f185bd..882af6f 100644 --- a/tests/animate2.cpp +++ b/tests/animate2.cpp @@ -9,6 +9,8 @@ #include #include "rand.hpp" #include "animate2.hpp" +#include "sound.hpp" + using namespace components; using namespace textures; @@ -53,6 +55,8 @@ void PLAY_TEST(Animate2 &anim) { */ TEST_CASE("new animation system", "[animation-new]") { textures::init(); + sound::init(); + sound::mute(true); auto anim = load_animation("rat_king_boss"); PLAY_TEST(anim); @@ -96,6 +100,8 @@ TEST_CASE("new animation system", "[animation-new]") { TEST_CASE("confirm frame sequencing works", "[animation-new]") { textures::init(); animation::init(); + sound::init(); + sound::mute(true); auto anim = load_animation("rat_king_boss"); @@ -109,8 +115,6 @@ TEST_CASE("confirm frame sequencing works", "[animation-new]") { anim.onLoop = [&](auto& seq, auto& tr) -> bool { seq.current = 0; loop_ran = true; - - REQUIRE(boss.sprite->getTextureRect() != init_rect); return false; }; @@ -125,14 +129,13 @@ TEST_CASE("confirm frame sequencing works", "[animation-new]") { REQUIRE(loop_ran == true); REQUIRE(anim.playing == false); - - // this confirms it went back to the first frame - REQUIRE(boss.sprite->getTextureRect() == init_rect); } TEST_CASE("confirm transition changes work", "[animation-new]") { textures::init(); animation::init(); + sound::init(); + sound::mute(true); auto sprite = *textures::get_sprite("rat_king_boss").sprite; sf::Vector2f pos{100,100}; diff --git a/tools/animator.cpp b/tools/animator.cpp index 8f0a909..e094256 100644 --- a/tools/animator.cpp +++ b/tools/animator.cpp @@ -104,10 +104,13 @@ namespace animator { } void FSM::change_form(int direction) { - dbc::check($anim.forms.size() > 0, "you can't use an empty animation.forms idiot."); + if($anim.forms.size() == 0) { + $ui.show_error("NO FORMS!"); + return; + } $cur_form_i = std::clamp($cur_form_i + direction, 0, int($anim.forms.size()) - 1); - dbc::check($cur_form_i >= 0, "you fucked up, Zed"); + dbc::check($cur_form_i >= 0, "CATASTROPHE! cur_form_i went below 0. How?"); // this is the dumbest shit ever auto key_view = std::views::keys($anim.forms); @@ -157,12 +160,34 @@ namespace animator { } void FSM::reload() { - $anim = animate2::load("assets/animate2.json", $anim_name); + animate2::Animate2 new_anim; - // BUG: this will throw the index off after reloads, oh well - $anim.set_form($cur_form); - $last_mod_time = std::filesystem::last_write_time("assets/animate2.json"); + try { + new_anim = animate2::load("assets/animate2.json", $anim_name); + } catch(...) { + $ui.show_error("Failed to load JSON"); + return; + } + if(!new_anim.has_form($cur_form)) { + $ui.show_error(fmt::format("No form {}", $cur_form)); + $cur_form = "idle"; + $cur_form_i = 0; + } + + new_anim.set_form($cur_form); + + try { + $last_mod_time = std::filesystem::last_write_time("assets/animate2.json"); + } catch(...) { + $ui.show_error("Filesystem error"); + } + + if($anim.form_name == new_anim.form_name) { + $ui.clear_error(); + } + + $anim = new_anim; $anim.play(); } @@ -233,6 +258,8 @@ namespace animator { "[error]"); $overlay.init(); + + $initialized_this_sucks_ass = true; } void UI::render(sf::RenderWindow& window, bool debug) { @@ -255,13 +282,27 @@ namespace animator { $overlay.show_text("transform", guecs::to_wstring(anim.transform_name)); } + void UI::show_error(const std::string& message) { + if($initialized_this_sucks_ass) { + $overlay.show_text("error", guecs::to_wstring(message)); + } else { + dbc::log(message); + } + } + + void UI::clear_error() { + if($initialized_this_sucks_ass) { + $overlay.show_text("error", L""); + } + } + std::shared_ptr UI::get_sprite() { auto viewer = $ui.entity("viewer"); return $ui.get(viewer).sprite; } } -int error() { +int error_usage() { fmt::println("USAGE: animator -h -b -s -a "); return 1; } @@ -291,21 +332,21 @@ int main(int argc, char* argv[]) { anim_name = optarg; break; case 'h': // fallthrough - error(); + error_usage(); break; default: - return error(); + return error_usage(); break; } } if(sprite_name == "") { - return error(); + return error_usage(); } else if(anim_name == "") { anim_name = sprite_name; // default to the same } - sound::mute(false); + sound::mute(true); animator::FSM main; main.init(sprite_name, anim_name, background); diff --git a/tools/animator.hpp b/tools/animator.hpp index ff1aff1..0765974 100644 --- a/tools/animator.hpp +++ b/tools/animator.hpp @@ -26,6 +26,7 @@ namespace animator { struct UI { guecs::UI $ui; guecs::UI $overlay; + bool $initialized_this_sucks_ass = false; void button(const std::string& name, std::function cb); void init(const std::string& sprite_name, const std::string& background, int width, int height); @@ -33,6 +34,8 @@ namespace animator { bool mouse(float x, float y, guecs::Modifiers mods); void update_status(animate2::Animate2& anim); std::shared_ptr get_sprite(); + void show_error(const std::string& message); + void clear_error(); }; struct FSM : public DeadSimpleFSM { @@ -50,7 +53,7 @@ namespace animator { sf::Clock $timer; std::string $cur_form = "idle"; int $cur_form_i = 0; - bool $mute = false; + bool $mute = true; void init(const std::string &sprite_name, const std::string& background, const std::string &anim_name); void event(Event ev, std::any data={});