More gui stuff

This commit is contained in:
fed 2023-07-16 03:02:06 +02:00
parent 7f4eb242d9
commit 97f261296c
6 changed files with 374 additions and 103 deletions

View File

@ -228,7 +228,7 @@ targetdir "%{wks.location}/bin/%{cfg.platform}/%{cfg.buildcfg}"
configurations {"Debug", "Release"}
language "C++"
cppdialect "C++20"
cppdialect "C++latest"
architecture "x86_64"
platforms "x64"

View File

@ -20,17 +20,102 @@ namespace gui::asset_list
bool shown_assets[game::XAssetType::ASSET_TYPE_COUNT]{};
std::string asset_type_filter;
std::string assets_name_filter[game::XAssetType::ASSET_TYPE_COUNT];
std::string assets_value_filter[game::XAssetType::ASSET_TYPE_COUNT];
std::string zone_name_filter[game::XAssetType::ASSET_TYPE_COUNT];
std::unordered_map<game::XAssetType, std::function<void(const std::string&)>> asset_view_callbacks;
void render_window()
bool default_only[game::ASSET_TYPE_COUNT] = {};
int asset_count[game::ASSET_TYPE_COUNT] = {};
bool disabled_zones[game::ASSET_TYPE_COUNT][0x100] = {};
bool show_asset_zone = true;
void draw_table_row(game::XAssetType type, const game::XAssetEntry* entry, bool should_add_view_btn)
{
static auto* enabled = &gui::enabled_menus["asset_list"];
ImGui::Begin("Asset list", enabled);
const auto asset = entry->asset;
auto asset_name = game::DB_GetXAssetName(&asset);
const auto is_default = entry->zoneIndex == 0;
static bool show_asset_zone = true;
if (asset_name[0] == '\0' || disabled_zones[type][entry->zoneIndex] || default_only[type] && !is_default)
{
return;
}
if (is_default)
{
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.43f, 0.15f, 0.15f, 1.f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.98f, 0.26f, 0.26f, 1.f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.98f, 0.06f, 0.06f, 1.f));
}
const auto _0 = gsl::finally([&]
{
if (is_default)
{
ImGui::PopStyleColor(3);
}
});
auto col_index = 0;
if (!utils::string::strstr_lower(asset_name, assets_name_filter[type].data()))
{
return;
}
if (type == game::ASSET_TYPE_LOCALIZE_ENTRY)
{
if (!utils::string::strstr_lower(entry->asset.header.localize->value, assets_value_filter[type].data()))
{
return;
}
}
ImGui::TableNextRow();
if (should_add_view_btn)
{
ImGui::TableSetColumnIndex(col_index++);
ImGui::PushID(asset_count[type]);
if (ImGui::Button("view"))
{
asset_view_callbacks.at(type)(asset_name);
}
ImGui::PopID();
}
if (show_asset_zone)
{
ImGui::TableSetColumnIndex(col_index++);
if (entry->zoneIndex > 0)
{
ImGui::Text(game::g_zones[entry->zoneIndex].name);
}
else
{
ImGui::Text("default");
}
}
ImGui::TableSetColumnIndex(col_index++);
if (ImGui::Button(asset_name))
{
gui::copy_to_clipboard(asset_name);
}
if (type == game::ASSET_TYPE_LOCALIZE_ENTRY)
{
ImGui::TableSetColumnIndex(col_index++);
if (ImGui::Button(entry->asset.header.localize->value))
{
gui::copy_to_clipboard(entry->asset.header.localize->value);
}
}
}
void draw_asset_type_list()
{
if (ImGui::TreeNode("loaded zones"))
{
for (auto i = 1u; i <= *game::g_zoneCount; i++)
@ -60,115 +145,104 @@ namespace gui::asset_list
}
ImGui::EndChild();
ImGui::End();
}
for (auto i = 0; i < game::XAssetType::ASSET_TYPE_COUNT; i++)
void draw_asset_list_filter(const game::XAssetType type)
{
ImGui::Text("count: %i / %i", asset_count[type], game::g_poolSize[type]);
ImGui::InputText("name", &assets_name_filter[type]);
if (type == game::ASSET_TYPE_LOCALIZE_ENTRY)
{
const auto name = game::g_assetNames[i];
const auto type = static_cast<game::XAssetType>(i);
ImGui::InputText("value", &assets_value_filter[type]);
}
if (!shown_assets[type])
if (ImGui::InputText("zone name", &zone_name_filter[type]))
{
for (auto zone = 0u; zone <= *game::g_zoneCount; zone++)
{
continue;
const auto zone_name = game::g_zones[zone].name;
disabled_zones[type][zone] = !utils::string::strstr_lower(zone_name, zone_name_filter[type].data());
}
}
ImGui::SetNextWindowSizeConstraints(ImVec2(500, 500), ImVec2(1000, 1000));
ImGui::Begin(name, &shown_assets[type]);
ImGui::Checkbox("default assets only", &default_only[type]);
}
static bool default_only[game::ASSET_TYPE_COUNT] = {};
static int asset_count[game::ASSET_TYPE_COUNT] = {};
static bool disabled_zones[game::ASSET_TYPE_COUNT][0x100] = {};
constexpr auto get_table_flags()
{
constexpr auto flags =
ImGuiTableFlags_BordersInnerH |
ImGuiTableFlags_BordersOuterH |
ImGuiTableFlags_BordersInnerV |
ImGuiTableFlags_BordersOuterV |
ImGuiTableFlags_RowBg |
ImGuiTableFlags_ScrollX |
ImGuiTableFlags_ScrollY;
ImGui::Text("count: %i / %i", asset_count[type], game::g_poolSize[type]);
return flags;
}
ImGui::InputText("asset name", &assets_name_filter[type]);
void draw_asset_list_entries(const game::XAssetType type)
{
const auto should_add_view_btn = asset_view_callbacks.contains(type);
constexpr auto flags = get_table_flags();
if (ImGui::InputText("zone name", &zone_name_filter[type]))
{
for (auto zone = 0u; zone <= *game::g_zoneCount; zone++)
{
const auto zone_name = game::g_zones[zone].name;
disabled_zones[type][zone] = !utils::string::strstr_lower(zone_name, zone_name_filter[type].data());
}
}
asset_count[type] = 0;
const auto should_add_view_btn = asset_view_callbacks.contains(type);
ImGui::Checkbox("default assets only", &default_only[type]);
ImGui::BeginChild("assets list");
ImGui::BeginChild("assets list");
auto column_count = 1;
column_count += should_add_view_btn;
column_count += show_asset_zone;
column_count += type == game::ASSET_TYPE_LOCALIZE_ENTRY;
asset_count[type] = 0;
if (ImGui::BeginTable("assets", column_count, flags))
{
fastfiles::enum_asset_entries(type, [&](const game::XAssetEntry* entry)
{
asset_count[type]++;
const auto asset = entry->asset;
auto asset_name = game::DB_GetXAssetName(&asset);
if (asset_name[0] == '\0')
{
return;
}
if (disabled_zones[type][entry->zoneIndex])
{
return;
}
const auto is_default = entry->zoneIndex == 0;
if (default_only[type] && !is_default)
{
return;
}
if (is_default)
{
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.43f, 0.15f, 0.15f, 1.f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.98f, 0.26f, 0.26f, 1.f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.98f, 0.06f, 0.06f, 1.f));
}
if (utils::string::strstr_lower(asset_name, assets_name_filter[type].data()))
{
if (show_asset_zone)
{
if (entry->zoneIndex > 0)
{
ImGui::Text(game::g_zones[entry->zoneIndex].name);
}
else
{
ImGui::Text("default");
}
ImGui::SameLine();
}
if (ImGui::Button(asset_name))
{
gui::copy_to_clipboard(asset_name);
}
if (should_add_view_btn)
{
ImGui::SameLine();
ImGui::PushID(asset_count[type]);
if (ImGui::Button("view"))
{
asset_view_callbacks.at(type)(asset_name);
}
ImGui::PopID();
}
}
if (is_default)
{
ImGui::PopStyleColor(3);
}
draw_table_row(type, entry, should_add_view_btn);
}, true);
ImGui::EndChild();
ImGui::End();
ImGui::EndTable();
}
ImGui::EndChild();
}
void draw_asset_list(const game::XAssetType type)
{
if (!shown_assets[type])
{
return;
}
const auto name = game::g_assetNames[type];
auto& io = ImGui::GetIO();
ImGui::SetNextWindowSizeConstraints(ImVec2(500, 500), io.DisplaySize);
ImGui::Begin(name, &shown_assets[type]);
draw_asset_list_filter(type);
draw_asset_list_entries(type);
ImGui::End();
}
void render_window()
{
static auto* enabled = &gui::enabled_menus["asset_list"];
ImGui::Begin("Asset list", enabled);
draw_asset_type_list();
for (auto i = 0; i < game::XAssetType::ASSET_TYPE_COUNT; i++)
{
draw_asset_list(static_cast<game::XAssetType>(i));
}
ImGui::End();
}
}

View File

@ -9,7 +9,7 @@ namespace gui::asset_list
void add_view_button(int id, game::XAssetType type, const char* name);
template <typename T>
void add_asset_view(game::XAssetType type, const std::function<bool(T*)>& draw_callback)
void add_asset_view(game::XAssetType type, const std::function<bool(T*)>& draw_callback, ImVec2 min_size = ImVec2(0, 0))
{
static std::unordered_set<std::string> opened_assets;
add_asset_view_callback(type, [](const std::string& name)
@ -29,6 +29,12 @@ namespace gui::asset_list
continue;
}
if (min_size.x != 0 && min_size.y != 0)
{
auto& io = ImGui::GetIO();
ImGui::SetNextWindowSizeConstraints(min_size, ImVec2(io.DisplaySize.x, io.DisplaySize.y));
}
auto is_open = true;
if (ImGui::Begin(name.data(), &is_open))
{

View File

@ -33,8 +33,6 @@ namespace gui::asset_list::mapents
std::atomic_bool done_parsing = false;
};
std::unordered_set<std::string> temp_files;
utils::concurrency::container<mapents_t, std::recursive_mutex> mapents;
void parse_mapents(game::MapEnts* asset, mapents_t& data)
@ -89,7 +87,6 @@ namespace gui::asset_list::mapents
{
const auto current_path = std::filesystem::current_path().generic_string();
const std::string path = utils::string::va("%s\\h2-mod\\tmp\\%s", current_path.data(), data.asset->name);
temp_files.insert(path);
utils::io::write_file(path, data.converted_mapents, false);
ShellExecuteA(nullptr, nullptr, path.data(), nullptr, nullptr, SW_SHOWNORMAL);
@ -135,10 +132,7 @@ namespace gui::asset_list::mapents
void pre_destroy() override
{
for (const auto& file : temp_files)
{
utils::io::remove_file(file);
}
utils::io::remove_directory("h2-mod/tmp");
}
};
}

View File

@ -0,0 +1,138 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "game/game.hpp"
#include "game/dvars.hpp"
#include "component/scheduler.hpp"
#include "component/command.hpp"
#include "component/fastfiles.hpp"
#include "component/gsc/script_loading.hpp"
#include "../gui.hpp"
#include "../asset_list.hpp"
#include "utils/mapents.hpp"
#include <utils/string.hpp>
#include <utils/hook.hpp>
#include <utils/concurrency.hpp>
#include <utils/io.hpp>
namespace gui::asset_list::stringtable
{
namespace
{
void copy_table(game::StringTable* asset)
{
std::string buffer;
for (auto row = 0; row < asset->rowCount; row++)
{
for (auto column = 0; column < asset->columnCount; column++)
{
const auto index = (row * asset->columnCount) + column;
const auto string_value = asset->values[index].string;
const auto last_char = (column == asset->columnCount - 1) ? "\n" : ",";
if (string_value == nullptr)
{
buffer.append(last_char);
}
else
{
std::string str = string_value;
auto added_quotes = false;
if (str.contains(','))
{
added_quotes = true;
str.insert(str.begin(), '"');
str.insert(str.end(), '"');
}
if (str.contains('\"') && !added_quotes)
{
str = std::regex_replace(str, std::regex("\""), "\\\"");
str.insert(str.begin(), '"');
str.insert(str.end(), '"');
}
str = std::regex_replace(str, std::regex("\n"), "\\n");
buffer.append(utils::string::va("%s%s", str.data(), last_char));
}
}
}
gui::copy_to_clipboard(buffer);
}
bool draw_asset(game::StringTable* asset)
{
if (asset->columnCount * asset->rowCount == 0)
{
ImGui::Text("empty table");
return true;
}
constexpr auto flags =
ImGuiTableFlags_BordersInnerH |
ImGuiTableFlags_BordersOuterH |
ImGuiTableFlags_BordersInnerV |
ImGuiTableFlags_BordersOuterV |
ImGuiTableFlags_RowBg |
ImGuiTableFlags_ScrollX |
ImGuiTableFlags_ScrollY;
const auto size = ImGui::GetContentRegionAvail();
if (ImGui::Button("copy all"))
{
copy_table(asset);
}
if (ImGui::BeginTable(asset->name, asset->columnCount, flags, size))
{
for (auto row = 0; row < asset->rowCount; row++)
{
ImGui::TableNextRow();
for (auto column = 0; column < asset->columnCount; column++)
{
ImGui::TableSetColumnIndex(column);
const auto index = (row * asset->columnCount) + column;
const auto string_value = asset->values[index].string;
if (string_value == nullptr)
{
ImGui::Text("");
}
else
{
ImGui::PushStyleColor(ImGuiCol_::ImGuiCol_Button, ImVec4(0, 0, 0, 0));
ImGui::PushID(index);
if (ImGui::Button(string_value))
{
gui::copy_to_clipboard(string_value);
}
ImGui::PopID();
ImGui::PopStyleColor();
}
}
}
ImGui::EndTable();
}
return true;
}
}
class component final : public component_interface
{
public:
void post_unpack() override
{
gui::asset_list::add_asset_view<game::StringTable>(game::ASSET_TYPE_STRINGTABLE, draw_asset, ImVec2(200, 200));
}
};
}
REGISTER_COMPONENT(gui::asset_list::stringtable::component)

View File

@ -75,6 +75,63 @@ namespace gui
});
}
std::vector<int> imgui_colors =
{
ImGuiCol_FrameBg,
ImGuiCol_FrameBgHovered,
ImGuiCol_FrameBgActive,
ImGuiCol_TitleBgActive,
ImGuiCol_ScrollbarGrabActive,
ImGuiCol_CheckMark,
ImGuiCol_SliderGrab,
ImGuiCol_SliderGrabActive,
ImGuiCol_Button,
ImGuiCol_ButtonHovered,
ImGuiCol_ButtonActive,
ImGuiCol_Header,
ImGuiCol_HeaderHovered,
ImGuiCol_HeaderActive,
ImGuiCol_SeparatorHovered,
ImGuiCol_SeparatorActive,
ImGuiCol_ResizeGrip,
ImGuiCol_ResizeGripHovered,
ImGuiCol_ResizeGripActive,
ImGuiCol_TextSelectedBg,
ImGuiCol_NavHighlight,
};
void update_colors()
{
auto& style = ImGui::GetStyle();
const auto colors = style.Colors;
const auto now = std::chrono::system_clock::now();
const auto days = std::chrono::floor<std::chrono::days>(now);
std::chrono::year_month_day y_m_d{days};
if (y_m_d.month() != std::chrono::month(6))
{
return;
}
for (const auto& id : imgui_colors)
{
const auto color = colors[id];
ImVec4 hsv_color =
{
static_cast<float>((game::Sys_Milliseconds() / 100) % 256) / 255.f,
1.f, 1.f, 1.f,
};
ImVec4 rgba_color{};
ImGui::ColorConvertHSVtoRGB(hsv_color.x, hsv_color.y, hsv_color.z, rgba_color.x, rgba_color.y, rgba_color.z);
rgba_color.w = color.w;
colors[id] = rgba_color;
}
}
void new_gui_frame()
{
ImGui::GetIO().MouseDrawCursor = toggled;
@ -87,6 +144,8 @@ namespace gui
*game::keyCatchers &= ~0x10;
}
update_colors();
ImGui_ImplDX11_NewFrame();
ImGui_ImplWin32_NewFrame();
run_event_queue();