More gui stuff
This commit is contained in:
parent
7f4eb242d9
commit
97f261296c
@ -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"
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
138
src/client/component/gui/assets/stringtable.cpp
Normal file
138
src/client/component/gui/assets/stringtable.cpp
Normal 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)
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user