summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryum <yum.food.vr@gmail.com>2023-07-25 16:26:34 -0700
committeryum <yum.food.vr@gmail.com>2023-07-25 16:26:34 -0700
commit91a9105fb74a3590527f03c680f999eb9629c13d (patch)
tree97a20e251eb5d7fbae17f4dc2f149913db6a2047
parentfcd038681640f64eada9541fd82c1ef182bfed7c (diff)
Add ability to auto-regen unity assets
Add two buttons: start auto re-generation of Unity assets, and stop. These start/stop a thread which periodically (every 3 seconds) hashes the user-provided animator, menu and parameters. When any one of these change, it invokes the function to generate Unity assets. The hash is non-cryptographic, so it's light. The only hit is that we have to read the entire file contents every few seconds, and compute a sum across that entire memory region. This is extremely light unless you're on a spinning platter hard drive with a small cache. Still seeing the bug where the material drops ref to the font bitmaps. Probably need to update the .mat using the guids in the bitmap .meta files.
-rw-r--r--GUI/GUI/GUI/Frame.cpp132
-rw-r--r--GUI/GUI/GUI/Frame.h4
2 files changed, 136 insertions, 0 deletions
diff --git a/GUI/GUI/GUI/Frame.cpp b/GUI/GUI/GUI/Frame.cpp
index d269728..221bb7a 100644
--- a/GUI/GUI/GUI/Frame.cpp
+++ b/GUI/GUI/GUI/Frame.cpp
@@ -7,6 +7,7 @@
#include <filesystem>
#include <fstream>
+#include <numeric>
#include <regex>
#include <sstream>
#include <string>
@@ -70,6 +71,8 @@ namespace {
ID_UNITY_PARAMETERS_GENERATED_NAME,
ID_UNITY_MENU_GENERATED_NAME,
ID_UNITY_BUTTON_GEN_ANIMATOR,
+ ID_UNITY_BUTTON_AUTO_REFRESH,
+ ID_UNITY_BUTTON_AUTO_REFRESH_STOP,
ID_UNITY_CHARS_PER_SYNC,
ID_UNITY_BYTES_PER_CHAR,
ID_UNITY_ROWS,
@@ -540,6 +543,11 @@ Frame::Frame()
}
{
auto p = std::promise<bool>();
+ unity_auto_refresh_ = p.get_future();
+ p.set_value(true);
+ }
+ {
+ auto p = std::promise<bool>();
dump_mics_ = p.get_future();
p.set_value(true);
}
@@ -1199,12 +1207,32 @@ Frame::Frame()
ID_UNITY_BUTTON_GEN_ANIMATOR, "Generate avatar assets");
unity_button_gen_fx->SetWindowStyleFlag(wxBU_EXACTFIT);
+ auto* unity_button_auto_refresh = new wxButton(unity_config_panel,
+ ID_UNITY_BUTTON_AUTO_REFRESH, "Begin auto generating assets on change");
+ unity_button_auto_refresh->SetWindowStyleFlag(wxBU_EXACTFIT);
+ unity_button_auto_refresh->SetToolTip(
+ "When the configured FX controller, parameters, or menu "
+ "change (as determined by its hash changing), "
+ "automatically regenerate TaSTT assets."
+ );
+
+ auto* unity_button_auto_refresh_stop = new wxButton(unity_config_panel,
+ ID_UNITY_BUTTON_AUTO_REFRESH_STOP,
+ "Stop auto generating assets on change");
+ unity_button_auto_refresh_stop->SetWindowStyleFlag(wxBU_EXACTFIT);
+ unity_button_auto_refresh_stop->SetToolTip(
+ "Stop auto-generating TaSTT assets on change.");
+
auto* sizer = new wxBoxSizer(wxVERTICAL);
unity_config_panel->SetSizer(sizer);
sizer->Add(unity_config_panel_pairs);
sizer->Add(clear_osc);
sizer->Add(unity_button_gen_fx, /*proportion=*/0,
/*flags=*/wxEXPAND);
+ sizer->Add(unity_button_auto_refresh, /*proportion=*/0,
+ /*flags=*/wxEXPAND);
+ sizer->Add(unity_button_auto_refresh_stop, /*proportion=*/0,
+ /*flags=*/wxEXPAND);
}
auto* sizer = new wxBoxSizer(wxHORIZONTAL);
@@ -1342,6 +1370,10 @@ Frame::Frame()
Bind(wxEVT_BUTTON, &Frame::OnDumpMics, this, ID_PY_DUMP_MICS_BUTTON);
Bind(wxEVT_BUTTON, &Frame::OnGenerateFX, this,
ID_UNITY_BUTTON_GEN_ANIMATOR);
+ Bind(wxEVT_BUTTON, &Frame::OnUnityAutoRefresh, this,
+ ID_UNITY_BUTTON_AUTO_REFRESH);
+ Bind(wxEVT_BUTTON, &Frame::OnUnityAutoRefreshStop, this,
+ ID_UNITY_BUTTON_AUTO_REFRESH_STOP);
Bind(wxEVT_BUTTON, &Frame::OnListPip, this, ID_DEBUG_BUTTON_LIST_PIP);
Bind(wxEVT_BUTTON, &Frame::OnClearPip, this, ID_DEBUG_BUTTON_CLEAR_PIP);
Bind(wxEVT_BUTTON, &Frame::OnListPip, this, ID_DEBUG_BUTTON_LIST_PIP);
@@ -1775,6 +1807,106 @@ void Frame::OnGenerateFX(wxCommandEvent& event)
}));
}
+// Return a non-cryptographic hash of the file at `path`.
+std::string hash_non_crypto(const std::string& path) {
+ std::ifstream file_ifs(path, std::ios::binary);
+ if (!file_ifs) {
+ std::cerr << "Could not open the file: " << path << '\n';
+ return 0;
+ }
+
+ // Read all bytes from the file into a vector
+ std::vector<uint8_t> data((std::istreambuf_iterator<char>(file_ifs)),
+ std::istreambuf_iterator<char>());
+
+ // Compute the hash as a sum of all bytes
+ uint32_t hash = std::accumulate(data.begin(), data.end(), 0);
+
+ std::stringstream ss;
+ ss << std::hex << hash;
+ return ss.str();
+}
+
+void Frame::OnUnityAutoRefresh(wxCommandEvent& event)
+{
+ auto status = unity_auto_refresh_.wait_for(std::chrono::seconds(0));
+ if (status != std::future_status::ready) {
+ Log(unity_out_, "Auto refresh thread already running\n");
+ return;
+ }
+
+ run_unity_auto_refresh_ = true;
+
+ unity_auto_refresh_ = std::move(std::async(std::launch::async, [&]() {
+ std::string fx_hash_prev;
+ std::string params_hash_prev;
+ std::string menu_hash_prev;
+ while (run_unity_auto_refresh_) {
+ std::this_thread::sleep_for(std::chrono::seconds(3));
+
+ std::filesystem::path unity_animator_path;
+ if (!GetUserPath(unity_out_,
+ unity_animator_file_picker_->GetPath().ToStdString(),
+ unity_animator_path,
+ "Cannot auto-refresh FX layer: Failed to validate animator directory")) {
+ return false;
+ }
+ std::filesystem::path unity_parameters_path;
+ if (!GetUserPath(unity_out_,
+ unity_parameters_file_picker_->GetPath().ToStdString(),
+ unity_parameters_path,
+ "Cannot auto-refresh FX layer: Failed to validate parameters directory")) {
+ return false;
+ }
+ std::filesystem::path unity_menu_path;
+ if (!GetUserPath(unity_out_, unity_menu_file_picker_->GetPath().ToStdString(),
+ unity_menu_path,
+ "Cannot auto-refresh FX layer: Failed to validate menu directory")) {
+ return false;
+ }
+
+ if (fx_hash_prev.empty() || params_hash_prev.empty() || menu_hash_prev.empty()) {
+ Log(unity_out_, "Generating initial hash of animator, parameters and menu\n");
+ fx_hash_prev = hash_non_crypto(unity_animator_path.string());
+ params_hash_prev = hash_non_crypto(unity_parameters_path.string());
+ menu_hash_prev = hash_non_crypto(unity_menu_path.string());
+ continue;
+ }
+
+ const std::string fx_hash = hash_non_crypto(unity_animator_path.string());
+ const std::string params_hash = hash_non_crypto(unity_parameters_path.string());
+ const std::string menu_hash = hash_non_crypto(unity_menu_path.string());
+
+ if (fx_hash.empty() || params_hash.empty() || menu_hash.empty()) {
+ Log(unity_out_, "Failed to hash animator ({}, {}), parameters ({}, {}), or menu ({}, {})\n",
+ unity_animator_path.string(), fx_hash,
+ unity_parameters_path.string(), params_hash,
+ unity_menu_path.string(), menu_hash);
+ continue;
+ }
+
+ if (fx_hash != fx_hash_prev ||
+ params_hash != params_hash_prev ||
+ menu_hash != menu_hash_prev) {
+ Log(unity_out_, "Detected change in animator ({}), params ({}), or menu ({}), regenerating unity assets\n",
+ fx_hash != fx_hash_prev ? "CHANGED" : "NO_CHANGE",
+ params_hash != params_hash_prev ? "CHANGED" : "NO_CHANGE",
+ menu_hash != menu_hash_prev ? "CHANGED" : "NO_CHANGE");
+ OnGenerateFX(event);
+ fx_hash_prev = fx_hash;
+ params_hash_prev = params_hash;
+ menu_hash_prev = menu_hash;
+ }
+ }
+ Log(unity_out_, "Stopping unity asset auto-generation\n");
+ return true;
+ }));
+}
+
+void Frame::OnUnityAutoRefreshStop(wxCommandEvent& event) {
+ run_unity_auto_refresh_ = false;
+}
+
void Frame::OnListPip(wxCommandEvent& event)
{
Log(debug_out_, "Listing pip packages... ");
diff --git a/GUI/GUI/GUI/Frame.h b/GUI/GUI/GUI/Frame.h
index bed6cf7..45ebf65 100644
--- a/GUI/GUI/GUI/Frame.h
+++ b/GUI/GUI/GUI/Frame.h
@@ -78,7 +78,9 @@ private:
std::future<bool> obs_app_;
Transcript transcript_;
bool run_py_app_;
+ bool run_unity_auto_refresh_;
std::future<bool> unity_app_;
+ std::future<bool> unity_auto_refresh_;
std::future<bool> dump_mics_;
std::future<bool> env_proc_;
std::future<void> reset_venv_proc_;
@@ -102,6 +104,8 @@ private:
void OnAppStop(wxCommandEvent& event);
void OnAppDrain(wxTimerEvent& event);
void OnGenerateFX(wxCommandEvent& event);
+ void OnUnityAutoRefresh(wxCommandEvent& event);
+ void OnUnityAutoRefreshStop(wxCommandEvent& event);
void OnUnityParamChangeImpl();
void OnUnityParamChange(wxCommandEvent& event);
void OnListPip(wxCommandEvent& event);