-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathplugin_auto_reload.cpp
More file actions
142 lines (115 loc) · 5.15 KB
/
plugin_auto_reload.cpp
File metadata and controls
142 lines (115 loc) · 5.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include <hex/plugin.hpp>
#include <hex/api/content_registry.hpp>
#include <hex/api/imhex_api.hpp>
#include <hex/api/event_manager.hpp>
#include <hex/api/events/events_interaction.hpp>
#include <hex/providers/provider.hpp>
#include <hex/helpers/logger.hpp>
#include <chrono>
#include <mutex>
#include <thread>
#include <fstream>
#include <filesystem>
using namespace hex;
namespace hex::plugin::auto_reload {
namespace {
static bool s_autoReloadEnabled = false;
static int s_reloadIntervalMs = 100;
// Mutex to protect multiple reloads
static std::mutex s_reloadMutex;
// Retrieve the provider's filepath
std::optional<std::string> getProviderFilePath(prv::Provider* provider) {
if (provider == nullptr)
return std::nullopt;
try {
// Try to get the file path from the provider description
auto descriptions = provider->getDataDescription();
for (const auto& desc : descriptions) {
if (desc.name.find("path") != std::string::npos) {
return desc.value;
}
}
} catch (...) {
// Ignore errors
}
return std::nullopt;
}
void autoReloadService() {
// Sleep for configured interval
std::this_thread::sleep_for(std::chrono::milliseconds(s_reloadIntervalMs));
// Only reload if the feature is enabled
if (!s_autoReloadEnabled)
return;
// Prevent multiple reloads at once. Never happens, but just in case
if (!s_reloadMutex.try_lock())
return;
// Get the current provider and check if it's valid
auto provider = ImHexApi::Provider::get();
if (provider == nullptr || !provider->isAvailable()) {
s_reloadMutex.unlock();
return;
}
try {
// Get the file path from the provider
auto filePath = getProviderFilePath(provider);
if (!filePath) {
log::debug("Could not determine file path");
s_reloadMutex.unlock();
return;
}
// Store provider state
auto baseAddress = provider->getBaseAddress();
auto currentPage = provider->getCurrentPage();
// Read the file directly as a binary file
std::ifstream file(*filePath, std::ios::binary);
if (!file.good()) {
log::error("Failed to open file for reading");
s_reloadMutex.unlock();
return;
}
// Get file size after opening
auto fileSize = std::filesystem::file_size(std::filesystem::path(*filePath));
// Read the entire file into a buffer
std::vector<u8> buffer(fileSize);
file.read(reinterpret_cast<char*>(buffer.data()), fileSize);
file.close();
// Resize the provider to match the file size
if (provider->isResizable() && provider->getActualSize() != fileSize) {
provider->resizeRaw(fileSize);
}
// Write the data directly to the provider using writeRaw instead of write
// This bypasses the patching system and writes directly to the data
if (provider->isWritable() && fileSize > 0) {
provider->writeRaw(0, buffer.data(), buffer.size());
}
// Clear the edit flag to prevent red highlighting
provider->markDirty(false);
// Restore state
provider->setBaseAddress(baseAddress);
provider->setCurrentPage(currentPage);
// Post data changed event to update UI
EventManager::post<EventDataChanged>(provider);
} catch (const std::exception& e) {
log::error("Failed to reload file: {}", e.what());
} catch (...) {
log::error("Failed to reload file with unknown error");
}
s_reloadMutex.unlock();
}
}
}
using namespace hex::plugin::auto_reload;
IMHEX_PLUGIN_SETUP("Auto Reload", "stableversion", "Fast auto reload!") {
ContentRegistry::BackgroundServices::registerService("hex.builtin.background_service.auto_reload", autoReloadService);
ContentRegistry::Interface::addMenuItem(
{ "hex.builtin.menu.extras", "Auto Reload" },
3500,
Shortcut::None,
[] {
s_autoReloadEnabled = !s_autoReloadEnabled;
log::info("Auto Reload toggled: {}", s_autoReloadEnabled ? "enabled" : "disabled");
},
[] { return true; },
[] { return s_autoReloadEnabled; }
);
}