Skip to content

Commit 9b754d9

Browse files
committed
fixed profile switch freeze when nbb api
1 parent 064e101 commit 9b754d9

11 files changed

Lines changed: 302 additions & 28 deletions

File tree

CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,6 +1143,10 @@ set(TOOLSCREEN_GUI_INTEGRATION_TEST_CASES
11431143
profile-case-insensitive-collisions
11441144
profile-recover-missing-metadata
11451145
profile-async-save-skip-deleted-profile
1146+
profile-switch-ninjabrain-async-stop
1147+
profile-switch-ninjabrain-async-restart
1148+
profile-switch-invalid-default-mode-fallback
1149+
profile-switch-reader-mode-fallback
11461150
profile-switch-concurrent-readers
11471151
profile-switch-concurrent-lifecycle
11481152
profile-switch-concurrent-metadata-rebuild

src/bootstrap/dllmain.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1436,7 +1436,7 @@ static bool GetLatestViewportForHook(int& outModeW, int& outModeH, bool& outStre
14361436
auto cfgSnap = GetConfigSnapshot();
14371437
if (!cfgSnap) { return false; }
14381438

1439-
const ModeConfig* mode = GetModeFromSnapshot(*cfgSnap, currentModeId);
1439+
const ModeConfig* mode = GetModeFromSnapshotOrFallback(*cfgSnap, currentModeId);
14401440
if (!mode) { return false; }
14411441

14421442
if (s_cache.valid && s_cache.modeId != currentModeId) {
@@ -2186,7 +2186,7 @@ static UINT GetRawInputDataHook_Impl(GETRAWINPUTDATAPROC next, HRAWINPUT hRawInp
21862186
}
21872187

21882188
auto inputCfgSnap = GetConfigSnapshot();
2189-
const ModeConfig* mode = inputCfgSnap ? GetModeFromSnapshot(*inputCfgSnap, modeId) : nullptr;
2189+
const ModeConfig* mode = inputCfgSnap ? GetModeFromSnapshotOrFallback(*inputCfgSnap, modeId) : nullptr;
21902190
if (mode && mode->sensitivityOverrideEnabled) {
21912191
if (mode->separateXYSensitivity) {
21922192
sensitivityX = mode->modeSensitivityX;
@@ -2856,7 +2856,7 @@ static BOOL SwapBuffersHook_Impl(WGLSWAPBUFFERS next, HDC hDc) {
28562856
int modeWidth = 0, modeHeight = 0;
28572857
bool modeValid = false;
28582858
{
2859-
const ModeConfig* newMode = GetModeFromSnapshot(frameCfg, desiredModeId);
2859+
const ModeConfig* newMode = GetModeFromSnapshotOrFallback(frameCfg, desiredModeId);
28602860
if (newMode) {
28612861
modeWidth = newMode->width;
28622862
modeHeight = newMode->height;
@@ -2879,9 +2879,9 @@ static BOOL SwapBuffersHook_Impl(WGLSWAPBUFFERS next, HDC hDc) {
28792879
ModeConfig modeToRenderCopy;
28802880
bool modeFound = false;
28812881
{
2882-
const ModeConfig* tempMode = GetModeFromSnapshot(frameCfg, desiredModeId);
2882+
const ModeConfig* tempMode = GetModeFromSnapshotOrFallback(frameCfg, desiredModeId);
28832883
if (!tempMode && g_isTransitioningMode) {
2884-
tempMode = GetModeFromSnapshot(frameCfg, lastFrameModeIdCopy);
2884+
tempMode = GetModeFromSnapshotOrFallback(frameCfg, lastFrameModeIdCopy);
28852885
}
28862886
if (tempMode) {
28872887
modeToRenderCopy = *tempMode;

src/common/utils.cpp

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1863,6 +1863,36 @@ const ModeConfig* GetModeFromSnapshot(const Config& config, const std::string& i
18631863
return nullptr;
18641864
}
18651865

1866+
const ModeConfig* GetModeFromSnapshotOrFallback(const Config& config, const std::string& id, std::string* resolvedId) {
1867+
if (const ModeConfig* mode = GetModeFromSnapshot(config, id)) {
1868+
if (resolvedId) {
1869+
*resolvedId = mode->id;
1870+
}
1871+
return mode;
1872+
}
1873+
1874+
if (!config.defaultMode.empty()) {
1875+
if (const ModeConfig* defaultMode = GetModeFromSnapshot(config, config.defaultMode)) {
1876+
if (resolvedId) {
1877+
*resolvedId = defaultMode->id;
1878+
}
1879+
return defaultMode;
1880+
}
1881+
}
1882+
1883+
if (!config.modes.empty()) {
1884+
if (resolvedId) {
1885+
*resolvedId = config.modes.front().id;
1886+
}
1887+
return &config.modes.front();
1888+
}
1889+
1890+
if (resolvedId) {
1891+
resolvedId->clear();
1892+
}
1893+
return nullptr;
1894+
}
1895+
18661896
const MirrorConfig* GetMirrorFromSnapshot(const Config& config, const std::string& name) {
18671897
for (const auto& mirror : config.mirrors) {
18681898
if (mirror.name == name) return &mirror;
@@ -1882,7 +1912,7 @@ ModeViewportInfo GetCurrentModeViewport_Internal() {
18821912

18831913
// Use snapshot for thread-safe mode config lookup (called from multiple threads)
18841914
auto vpSnap = GetConfigSnapshot();
1885-
const ModeConfig* mode = vpSnap ? GetModeFromSnapshot(*vpSnap, modeId) : nullptr;
1915+
const ModeConfig* mode = vpSnap ? GetModeFromSnapshotOrFallback(*vpSnap, modeId) : nullptr;
18861916
if (!mode) {
18871917
return info;
18881918
}
@@ -3065,7 +3095,7 @@ static void RequestCurrentModeClientResizeSync(HWND hwnd, const char* source) {
30653095
if (!cfgSnap) { return; }
30663096

30673097
const std::string currentModeId = g_modeIdBuffers[g_currentModeIdIndex.load(std::memory_order_acquire)];
3068-
const ModeConfig* mode = GetModeFromSnapshot(*cfgSnap, currentModeId);
3098+
const ModeConfig* mode = GetModeFromSnapshotOrFallback(*cfgSnap, currentModeId);
30693099
if (!mode || mode->width <= 0 || mode->height <= 0) { return; }
30703100

30713101
if (EqualsIgnoreCase(mode->id, "Fullscreen") && mode->useRelativeSize) {

src/common/utils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,8 @@ ModeConfig* GetModeMutable(const std::string& id);
393393
MirrorConfig* GetMutableMirror(const std::string& name);
394394

395395
const ModeConfig* GetModeFromSnapshot(const Config& config, const std::string& id);
396+
const ModeConfig* GetModeFromSnapshotOrFallback(const Config& config, const std::string& id,
397+
std::string* resolvedId = nullptr);
396398
const MirrorConfig* GetMirrorFromSnapshot(const Config& config, const std::string& name);
397399
bool isWallTitleOrWaiting(const std::string& state);
398400
ModeViewportInfo GetCurrentModeViewport();

src/config/config_profiles.cpp

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -601,24 +601,28 @@ static void ApplyProfileSwitchRuntimeConfig(const Config& previousConfig) {
601601
}
602602

603603
SaveTheme();
604+
604605
if (ImGui::GetCurrentContext() != nullptr) {
605606
ApplyAppearanceConfig();
606607
}
608+
607609
RequestDynamicGuiFontRefresh(true);
608610

609611
ApplyKeyRepeatSettings();
612+
610613
if (g_config.confineCursor) {
611614
ApplyConfineCursorToGameWindow();
612615
} else {
613616
ClipCursorDirect(NULL);
614617
}
618+
615619
SetGlobalMirrorGammaMode(g_config.mirrorGammaMode);
616620

617621
const bool previousNinjabrainEnabled = previousConfig.ninjabrainOverlay.enabled;
618622
const bool currentNinjabrainEnabled = g_config.ninjabrainOverlay.enabled;
619623
if (!currentNinjabrainEnabled) {
620624
if (previousNinjabrainEnabled) {
621-
StopNinjabrainClient();
625+
StopNinjabrainClientAsync();
622626
}
623627
return;
624628
}
@@ -629,7 +633,7 @@ static void ApplyProfileSwitchRuntimeConfig(const Config& previousConfig) {
629633
}
630634

631635
if (previousConfig.ninjabrainOverlay.apiBaseUrl != g_config.ninjabrainOverlay.apiBaseUrl) {
632-
RestartNinjabrainClient();
636+
RestartNinjabrainClientAsync();
633637
}
634638
}
635639

@@ -720,6 +724,7 @@ void SwitchProfile(const std::string& newProfileName) {
720724
std::string resolvedNewProfileName;
721725
bool failedToSavePreviousProfile = false;
722726
bool failedToSaveProfilesMetadata = false;
727+
723728
const bool pendingConfigSave = g_configIsDirty.load(std::memory_order_acquire);
724729

725730
{
@@ -770,14 +775,6 @@ void SwitchProfile(const std::string& newProfileName) {
770775

771776
RemoveInvalidHotkeyModeReferences(g_config);
772777
ResetAllHotkeySecondaryModes(g_config);
773-
{
774-
std::lock_guard<std::mutex> lock(g_modeIdMutex);
775-
g_currentModeId = g_config.defaultMode;
776-
int nextIndex = 1 - g_currentModeIdIndex.load(std::memory_order_relaxed);
777-
g_modeIdBuffers[nextIndex] = g_config.defaultMode;
778-
g_currentModeIdIndex.store(nextIndex, std::memory_order_release);
779-
}
780-
WriteCurrentModeToFile(g_config.defaultMode);
781778

782779
{
783780
std::lock_guard<std::mutex> lock(g_hotkeyMainKeysMutex);
@@ -792,7 +789,9 @@ void SwitchProfile(const std::string& newProfileName) {
792789
for (const auto& [id, inst] : g_userImages) {
793790
if (inst.isAnimated) {
794791
for (GLuint tex : inst.frameTextures) {
795-
if (tex != 0) g_texturesToDelete.push_back(tex);
792+
if (tex != 0) {
793+
g_texturesToDelete.push_back(tex);
794+
}
796795
}
797796
} else if (inst.textureId != 0) {
798797
g_texturesToDelete.push_back(inst.textureId);
@@ -804,12 +803,21 @@ void SwitchProfile(const std::string& newProfileName) {
804803

805804
g_allImagesLoaded = false;
806805
g_pendingImageLoad = true;
806+
807807
RecalculateModeDimensions();
808808
RequestScreenMetricsRecalculation();
809-
PublishConfigSnapshot();
809+
PublishGuiConfigSnapshot();
810810

811-
ApplyProfileSwitchRuntimeConfig(previousConfig);
811+
{
812+
std::lock_guard<std::mutex> lock(g_modeIdMutex);
813+
g_currentModeId = g_config.defaultMode;
814+
const int nextIndex = 1 - g_currentModeIdIndex.load(std::memory_order_relaxed);
815+
g_modeIdBuffers[nextIndex] = g_config.defaultMode;
816+
g_currentModeIdIndex.store(nextIndex, std::memory_order_release);
817+
}
812818

819+
WriteCurrentModeToFile(g_config.defaultMode);
820+
ApplyProfileSwitchRuntimeConfig(previousConfig);
813821
g_configIsDirty.store(pendingConfigSave, std::memory_order_release);
814822
}
815823

src/features/window_overlay.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ std::string GetWindowOverlayAtPoint(int x, int y, int screenWidth, int screenHei
786786
std::vector<std::pair<std::string, WindowOverlayConfig>> activeOverlays;
787787
{
788788
auto overlaySnap = GetConfigSnapshot();
789-
const ModeConfig* mode = overlaySnap ? GetModeFromSnapshot(*overlaySnap, currentModeId) : nullptr;
789+
const ModeConfig* mode = overlaySnap ? GetModeFromSnapshotOrFallback(*overlaySnap, currentModeId) : nullptr;
790790
if (!mode) return "";
791791

792792
for (auto it = mode->windowOverlayIds.rbegin(); it != mode->windowOverlayIds.rend(); ++it) {

src/hooks/input_hook.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ static void ResendCurrentModeWmSize(HWND hWnd, const char* source) {
444444
if (!cfgSnap) { return; }
445445

446446
const std::string currentModeId = g_modeIdBuffers[g_currentModeIdIndex.load(std::memory_order_acquire)];
447-
const ModeConfig* mode = GetModeFromSnapshot(*cfgSnap, currentModeId);
447+
const ModeConfig* mode = GetModeFromSnapshotOrFallback(*cfgSnap, currentModeId);
448448
if (!mode || mode->width <= 0 || mode->height <= 0) { return; }
449449

450450
RequestWindowClientResize(hWnd, mode->width, mode->height, source);
@@ -1450,7 +1450,7 @@ InputHandlerResult HandleWmSizeModeDimensions(HWND hWnd, UINT uMsg, WPARAM wPara
14501450
if (msgW <= 0 || msgH <= 0) { return { false, 0 }; }
14511451

14521452
auto cfgSnap = GetConfigSnapshot();
1453-
const ModeConfig* mode = cfgSnap ? GetModeFromSnapshot(*cfgSnap, currentModeId) : nullptr;
1453+
const ModeConfig* mode = cfgSnap ? GetModeFromSnapshotOrFallback(*cfgSnap, currentModeId) : nullptr;
14541454
if (!mode || mode->width <= 0 || mode->height <= 0) { return { false, 0 }; }
14551455

14561456
if (EqualsIgnoreCase(mode->id, "Fullscreen")) {

src/runtime/logic_thread.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ void UpdateActiveMirrorConfigs() {
196196
if (currentModeId == s_lastMirrorConfigModeId && snapVer == s_lastMirrorConfigSnapshotVersion) {
197197
return;
198198
}
199-
const ModeConfig* mode = GetModeFromSnapshot(cfg, currentModeId);
199+
const ModeConfig* mode = GetModeFromSnapshotOrFallback(cfg, currentModeId);
200200
if (!mode) { return; }
201201

202202
std::vector<std::string> currentMirrorIds = mode->mirrorIds;
@@ -321,7 +321,7 @@ void UpdateCachedScreenMetrics() {
321321
std::string currentModeId = GetPublishedCurrentModeId();
322322
int beforeModeW = 0;
323323
int beforeModeH = 0;
324-
if (const ModeConfig* currentModeBefore = GetModeFromSnapshot(*baseSnapshot, currentModeId)) {
324+
if (const ModeConfig* currentModeBefore = GetModeFromSnapshotOrFallback(*baseSnapshot, currentModeId)) {
325325
beforeModeW = currentModeBefore->width;
326326
beforeModeH = currentModeBefore->height;
327327
}
@@ -331,7 +331,7 @@ void UpdateCachedScreenMetrics() {
331331

332332
int afterModeW = 0;
333333
int afterModeH = 0;
334-
if (const ModeConfig* currentModeAfter = GetModeFromSnapshot(resolvedConfig, currentModeId)) {
334+
if (const ModeConfig* currentModeAfter = GetModeFromSnapshotOrFallback(resolvedConfig, currentModeId)) {
335335
afterModeW = currentModeAfter->width;
336336
afterModeH = currentModeAfter->height;
337337
}
@@ -370,7 +370,7 @@ void UpdateCachedScreenMetrics() {
370370

371371
if (sourceSnapshotStillCurrent) {
372372
const std::string activeModeIdAfterPublish = GetPublishedCurrentModeId();
373-
if (const ModeConfig* activeMode = GetModeFromSnapshot(resolvedConfig, activeModeIdAfterPublish)) {
373+
if (const ModeConfig* activeMode = GetModeFromSnapshotOrFallback(resolvedConfig, activeModeIdAfterPublish)) {
374374
RetargetActiveModeTransition(*activeMode);
375375
}
376376
} else {
@@ -463,7 +463,7 @@ void UpdateCachedViewportMode() {
463463
// Get mode data via config snapshot (thread-safe, lock-free)
464464
auto cfgSnap = GetConfigSnapshot();
465465
if (!cfgSnap) return;
466-
const ModeConfig* mode = GetModeFromSnapshot(*cfgSnap, currentModeId);
466+
const ModeConfig* mode = GetModeFromSnapshotOrFallback(*cfgSnap, currentModeId);
467467

468468
int nextIndex = 1 - g_viewportModeCacheIndex.load(std::memory_order_relaxed);
469469
CachedModeViewport& cache = g_viewportModeCache[nextIndex];

tests/gui_integration/runner.inl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,10 @@ const auto& GetTestCaseDefinitions() {
182182
{"profile-case-insensitive-collisions", &RunProfileCaseInsensitiveCollisionTest},
183183
{"profile-recover-missing-metadata", &RunProfileRecoverMissingMetadataTest},
184184
{"profile-async-save-skip-deleted-profile", &RunProfileAsyncSaveSkipDeletedProfileTest},
185+
{"profile-switch-ninjabrain-async-stop", &RunProfileSwitchNinjabrainAsyncStopTest},
186+
{"profile-switch-ninjabrain-async-restart", &RunProfileSwitchNinjabrainAsyncRestartTest},
187+
{"profile-switch-invalid-default-mode-fallback", &RunProfileSwitchInvalidDefaultModeFallbackTest},
188+
{"profile-switch-reader-mode-fallback", &RunProfileSwitchReaderModeFallbackTest},
185189
{"profile-switch-concurrent-readers", &RunProfileSwitchConcurrentReadersTest},
186190
{"profile-switch-concurrent-lifecycle", &RunProfileSwitchConcurrentLifecycleTest},
187191
{"profile-switch-concurrent-metadata-rebuild", &RunProfileSwitchConcurrentMetadataRebuildTest},
@@ -869,10 +873,28 @@ void PauseForTransientConsole() {
869873
std::getline(std::cin, ignored);
870874
}
871875

876+
class ScopedTestProcessCleanup {
877+
public:
878+
~ScopedTestProcessCleanup() {
879+
try {
880+
StopNinjabrainClient();
881+
FlushLogs();
882+
883+
std::lock_guard<std::mutex> lock(g_logFileMutex);
884+
if (logFile.is_open()) {
885+
logFile.close();
886+
}
887+
logFile.clear();
888+
} catch (...) {
889+
}
890+
}
891+
};
892+
872893
} // namespace
873894

874895
int main(int argc, char** argv) {
875896
try {
897+
ScopedTestProcessCleanup cleanup;
876898
EnsureProcessDpiAwareness();
877899
const CommandLineOptions options = ParseCommandLine(argc, argv);
878900

0 commit comments

Comments
 (0)