~zanneth/BishiTAS

bd47d965ead30d4ad3dce70c4174ac3d94e27f4d — Charles Magahern 5 years ago 97f1f5e
libafp verbose logging
M include/button.h => include/button.h +13 -0
@@ 10,3 10,16 @@ public:

    static constexpr const char *class_name = "BUTTON";
};

class Checkbox : public Window<Checkbox>
{
public:
    Checkbox(HINSTANCE instance, const std::string &name, Rect2DI rect, HWND parent);
    virtual ~Checkbox() = default;

    static constexpr const char *class_name = "BUTTON";

    bool checked() const;
    void set_checked(bool checked);
    void toggle();
};

M include/gamecontroller.h => include/gamecontroller.h +4 -0
@@ 56,6 56,7 @@ private: // functions
                                void **out_orig_funcptr);

    SharedState* _shared_state() const;
    const LDR_DATA_TABLE_ENTRY* _libafp_module();

    DWORD _patched_game_tick(void *p);
    void _patched_acio_hbhi_get_csb(void *p);


@@ 81,6 82,9 @@ private: // variables
    SharedMemory            _shared_memory;
    SavedState              _saved_state;
    std::vector<AVSHeap>    _avs_heaps;
    bool                    _afp_logging_enabled;

    LDR_DATA_TABLE_ENTRY   *_cached_afp_module;

    void                   *_afp_bss_ptr;
    size_t                  _afp_bss_size;

M include/gameprocess.h => include/gameprocess.h +5 -0
@@ 24,8 24,13 @@ public:
    void advance_frame() const;
    void pause() const;
    void resume() const;

    void save_state() const;
    void restore_state() const;

    bool verbose_log_enabled() const;
    void set_verbose_log_enabled(bool enabled);

    size_t frame_count() const;

private:

M include/mainwindow.h => include/mainwindow.h +2 -0
@@ 25,6 25,7 @@ private:
    void _handle_adv_frame_button_cmd();
    void _handle_save_state_button_cmd();
    void _handle_restore_state_button_cmd();
    void _handle_verbose_log_checkbox_cmd();
    void _reload_ui_state();

    void _start_update_timer();


@@ 40,6 41,7 @@ private:
    Button                         _adv_frame_button;
    Button                         _save_state_button;
    Button                         _restore_state_button;
    Checkbox                       _verbose_log_checkbox;
    std::unique_ptr<GameProcess>   _game_proc;
    HANDLE                         _update_timer;
};

M include/sharedstate.h => include/sharedstate.h +1 -0
@@ 10,5 10,6 @@ struct SharedState
    bool continue_next_frame = false;
    bool save_state = false;
    bool restore_state = false;
    bool verbose_logging = false;
    size_t frame_count = 0;
};

M src/button.cpp => src/button.cpp +27 -0
@@ 11,3 11,30 @@ Button::Button(HINSTANCE instance, const std::string &name, Rect2DI rect, HWND p
    // set default font on the button
    SendMessage(_handle, WM_SETFONT, (LPARAM)GetStockObject(DEFAULT_GUI_FONT), true);
}

Checkbox::Checkbox(HINSTANCE instance, const std::string &name, Rect2DI rect, HWND parent)
    : Window<Checkbox>(instance,
                       name,
                       WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_CHECKBOX,
                       0,
                       rect,
                       parent)
{
    // set default font for the checkbox
    SendMessage(_handle, WM_SETFONT, (LPARAM)GetStockObject(DEFAULT_GUI_FONT), true);
}

bool Checkbox::checked() const
{
    return (SendMessage(_handle, BM_GETCHECK, 0, 0) == BST_CHECKED);
}

void Checkbox::set_checked(bool checked)
{
    SendMessage(_handle, BM_SETCHECK, (checked ? BST_CHECKED : BST_UNCHECKED), 0);
}

void Checkbox::toggle()
{
    set_checked(!checked());
}

M src/gamecontroller.cpp => src/gamecontroller.cpp +33 -2
@@ 19,6 19,7 @@ namespace
    constexpr uint32_t ACIO_HBHI_GET_CSB_OFFSET = 0x00001490;
    constexpr uint32_t AVS_STDBOOT_HEAP_BOOT_CALL_OFFSET = 0x000291BA;
    constexpr uint32_t AVS_PBOOT_HEAP_BOOT_CALL_OFFSET = 0x0003D900;
    constexpr uint32_t AFP_LOGGING_FLAGS_OFFSET = 0x00081148;

    constexpr const char *ACIO_MODULE_NAME = "libacio.dll";
    constexpr const char *ACIO_HBHI_GET_CSB_SYM_NAME = "ac_io_hbhi_get_control_status_buffer";


@@ 38,6 39,8 @@ GameController& GameController::instance()

GameController::GameController()
    : _shared_memory(sizeof(SharedState), SharedMemory::Mode::OPEN, SHMEM_MAPPING_NAME),
      _afp_logging_enabled(false),
      _cached_afp_module(nullptr),
      _afp_bss_ptr(nullptr),
      _afp_bss_size(0)
{}


@@ 150,6 153,20 @@ SharedState* GameController::_shared_state() const
    return (SharedState *)_shared_memory.data();
}

const LDR_DATA_TABLE_ENTRY* GameController::_libafp_module()
{
    if (!_cached_afp_module) {
        const ProcessModuleTable modtable;
        _cached_afp_module = modtable.entry_named(AFP_MODULE_NAME);

        if (!_cached_afp_module) {
            throw std::runtime_error("Failed to load libafp module.");
        }
    }

    return _cached_afp_module;
}

DWORD GameController::_patched_game_tick(void *p)
{
    DWORD result = 0;


@@ 169,6 186,21 @@ DWORD GameController::_patched_game_tick(void *p)
        state->continue_next_frame = false;
    }

    if (state->verbose_logging != _afp_logging_enabled) {
        const LDR_DATA_TABLE_ENTRY *afp_module = _libafp_module();
        uint32_t *logging_flags = (uint32_t *)((uintptr_t)afp_module->DllBase + AFP_LOGGING_FLAGS_OFFSET);

        if (state->verbose_logging) {
            DEBUG_LOG("Enabling verbose logging.\n");
            *logging_flags |= 0xff;
        } else {
            DEBUG_LOG("Disabling verbose logging.\n");
            *logging_flags ^= 0xff;
        }

        _afp_logging_enabled = state->verbose_logging;
    }

    return result;
}



@@ 336,8 368,7 @@ void GameController::_save_state()
    }

    if (!_afp_bss_ptr) {
        const ProcessModuleTable modtable;
        const LDR_DATA_TABLE_ENTRY *afp_module = modtable.entry_named(L"libafp-win32");
        const LDR_DATA_TABLE_ENTRY *afp_module = _libafp_module();
        const void *afp_known_bss_addr = ((uint8_t *)afp_module->DllBase + 0x8334c);
        const MEMORY_BASIC_INFORMATION afp_bss_region = mem_region(afp_known_bss_addr);


M src/gameprocess.cpp => src/gameprocess.cpp +10 -0
@@ 148,6 148,16 @@ void GameProcess::restore_state() const
    _shared_state()->restore_state = true;
}

bool GameProcess::verbose_log_enabled() const
{
    return _shared_state()->verbose_logging;
}

void GameProcess::set_verbose_log_enabled(bool enabled)
{
    _shared_state()->verbose_logging = enabled;
}

size_t GameProcess::frame_count() const
{
    return _shared_state()->frame_count;

M src/mainwindow.cpp => src/mainwindow.cpp +48 -20
@@ 7,8 7,8 @@

namespace
{
    constexpr const int BUTTONS_HMARGIN = 10;
    constexpr const int BUTTONS_VMARGIN = 10;
    constexpr const int VIEWS_HMARGIN = 10;
    constexpr const int VIEWS_VMARGIN = 10;
}

MainWindow::MainWindow(HINSTANCE instance)


@@ 26,6 26,7 @@ MainWindow::MainWindow(HINSTANCE instance)
      _adv_frame_button(instance, "Next Frame", Rect2DI { Point2DI::zero(), Size2DI { 70, 25 } }, _handle),
      _save_state_button(instance, "Save", Rect2DI { Point2DI::zero(), Size2DI { 70, 25 } }, _handle),
      _restore_state_button(instance, "Restore", Rect2DI { Point2DI::zero(), Size2DI { 70, 25 } }, _handle),
      _verbose_log_checkbox(instance, "Verbose Logging", Rect2DI { Point2DI::zero(), Size2DI { 100, 20 } }, _handle),
      _update_timer(INVALID_HANDLE_VALUE)
{
    _frame_counter_label.set_font((HFONT)GetStockObject(SYSTEM_FIXED_FONT));


@@ 55,6 56,8 @@ LRESULT MainWindow::proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
            _handle_save_state_button_cmd();
        } else if (lparam == (LPARAM)_restore_state_button.handle()) {
            _handle_restore_state_button_cmd();
        } else if (lparam == (LPARAM)_verbose_log_checkbox.handle()) {
            _handle_verbose_log_checkbox_cmd();
        }

        break;


@@ 77,57 80,69 @@ void MainWindow::_layout_controls()
    Rect2DI adv_frame_btn_rect = _adv_frame_button.rect();
    Rect2DI save_state_btn_rect = _save_state_button.rect();
    Rect2DI restore_state_btn_rect = _restore_state_button.rect();
    const int row1_btns_width = (
    Rect2DI verbose_log_checkbox_rect = _verbose_log_checkbox.rect();
    const int row1_wnds_width = (
        start_btn_rect.size.width +
        BUTTONS_HMARGIN +
        VIEWS_HMARGIN +
        pause_btn_rect.size.width +
        BUTTONS_HMARGIN +
        VIEWS_HMARGIN +
        adv_frame_btn_rect.size.width
    );

    const int btns_total_height = (
    const int wnds_total_height = (
        start_btn_rect.size.height +
        BUTTONS_VMARGIN +
        save_state_btn_rect.size.height
        VIEWS_VMARGIN +
        save_state_btn_rect.size.height +
        VIEWS_VMARGIN +
        verbose_log_checkbox_rect.size.height
    );
    const int row1_btn_y = bounds.size.height / 2 - btns_total_height / 2;
    const int row2_btn_y = row1_btn_y + start_btn_rect.size.height + BUTTONS_VMARGIN;
    const int row1_wnd_y = bounds.size.height / 2 - wnds_total_height / 2;
    const int row2_wnd_y = row1_wnd_y + start_btn_rect.size.height + VIEWS_VMARGIN;
    const int row3_wnd_y = row2_wnd_y + save_state_btn_rect.size.height + VIEWS_VMARGIN;

    start_btn_rect.origin = Point2DI {
        bounds.size.width / 2 - row1_btns_width / 2,
        row1_btn_y
        bounds.size.width / 2 - row1_wnds_width / 2,
        row1_wnd_y
    };
    _start_button.set_rect(start_btn_rect);

    pause_btn_rect.origin =  Point2DI {
        start_btn_rect.max_x() + BUTTONS_HMARGIN,
        row1_btn_y
        start_btn_rect.max_x() + VIEWS_HMARGIN,
        row1_wnd_y
    };
    _pause_button.set_rect(pause_btn_rect);

    adv_frame_btn_rect.origin = Point2DI {
        pause_btn_rect.max_x() + BUTTONS_HMARGIN,
        row1_btn_y
        pause_btn_rect.max_x() + VIEWS_HMARGIN,
        row1_wnd_y
    };
    _adv_frame_button.set_rect(adv_frame_btn_rect);

    const int row2_btns_width = (
        save_state_btn_rect.size.width +
        BUTTONS_HMARGIN +
        VIEWS_HMARGIN +
        restore_state_btn_rect.size.width
    );

    save_state_btn_rect.origin = Point2DI {
        bounds.size.width / 2 - row2_btns_width / 2,
        row2_btn_y
        row2_wnd_y
    };
    _save_state_button.set_rect(save_state_btn_rect);

    restore_state_btn_rect.origin = Point2DI {
        save_state_btn_rect.max_x() + BUTTONS_HMARGIN,
        row2_btn_y
        save_state_btn_rect.max_x() + VIEWS_HMARGIN,
        row2_wnd_y
    };
    _restore_state_button.set_rect(restore_state_btn_rect);

    verbose_log_checkbox_rect.origin = Point2DI {
        bounds.size.width / 2 - verbose_log_checkbox_rect.size.width / 2,
        row3_wnd_y
    };
    _verbose_log_checkbox.set_rect(verbose_log_checkbox_rect);

    update();
}

void MainWindow::_handle_start_button_cmd()


@@ 186,6 201,15 @@ void MainWindow::_handle_restore_state_button_cmd()
    }
}

void MainWindow::_handle_verbose_log_checkbox_cmd()
{
    _verbose_log_checkbox.toggle();

    if (_game_proc) {
        _game_proc->set_verbose_log_enabled(_verbose_log_checkbox.checked());
    }
}

void MainWindow::_reload_ui_state()
{
    if (_game_proc && _game_proc->is_running()) {


@@ 194,6 218,8 @@ void MainWindow::_reload_ui_state()
        _adv_frame_button.set_enabled(true);
        _save_state_button.set_enabled(true);
        _restore_state_button.set_enabled(true);
        _verbose_log_checkbox.set_enabled(true);
        _verbose_log_checkbox.set_checked(_game_proc->verbose_log_enabled());

        if (_game_proc->is_paused()) {
            _pause_button.set_text("Resume");


@@ 209,6 235,8 @@ void MainWindow::_reload_ui_state()
        _adv_frame_button.set_enabled(false);
        _save_state_button.set_enabled(false);
        _restore_state_button.set_enabled(false);
        _verbose_log_checkbox.set_enabled(false);
        _verbose_log_checkbox.set_checked(false);

        _stop_update_timer();
    }