From c19137bd1af256fc50901dd267275f167e32002f Mon Sep 17 00:00:00 2001 From: NovaRain Date: Tue, 5 Oct 2021 13:36:58 +0800 Subject: [PATCH] Fixed crash at the end of DS sound playback * revert to the previous implementation. Made sure sfall only loads a localized resource file with valid name. Some code edits. --- artifacts/scripting/sfall function notes.md | 1 + sfall/Modules/LoadOrder.cpp | 11 ++- sfall/Modules/Message.cpp | 2 +- sfall/Modules/ScriptExtender.cpp | 2 +- sfall/Modules/Sound.cpp | 76 ++++++++++++++------- sfall/Modules/Worldmap.cpp | 4 +- 6 files changed, 66 insertions(+), 30 deletions(-) diff --git a/artifacts/scripting/sfall function notes.md b/artifacts/scripting/sfall function notes.md index 9ffc11ad..ee0e48ff 100644 --- a/artifacts/scripting/sfall function notes.md +++ b/artifacts/scripting/sfall function notes.md @@ -1046,6 +1046,7 @@ sfall_funcX metarule functions - Overrides the name of the script object that was set from **scrname.msg** - The changed name will be reset each time the player leaves the map or reloads the game - Passing an empty string ("") to the `name` argument or omitting it will allow the game to get the name for the object from pro_*.msg files +- The function can override the name only once for the same object until reset - __NOTE:__ this function is intended for use in normal game scripts diff --git a/sfall/Modules/LoadOrder.cpp b/sfall/Modules/LoadOrder.cpp index 8255942d..c854cc59 100644 --- a/sfall/Modules/LoadOrder.cpp +++ b/sfall/Modules/LoadOrder.cpp @@ -472,11 +472,16 @@ static void SfallResourceFile() { const char* sfallRes = "sfall.dat"; WIN32_FIND_DATA findData; - HANDLE hFind = FindFirstFile("sfall_??.dat", &findData); // example: sfall_ru.dat, sfall_zh.dat + HANDLE hFind = FindFirstFileA("sfall_??.dat", &findData); // example: sfall_ru.dat, sfall_zh.dat if (hFind != INVALID_HANDLE_VALUE) { + do { + if (std::strlen(&findData.cFileName[6]) == 6) { + dlog_f("Found a localized sfall resource file: %s\n", DL_MAIN, findData.cFileName); + sfallRes = findData.cFileName; + break; + } + } while (FindNextFileA(hFind, &findData)); FindClose(hFind); - dlog_f("Found a localized sfall resource file: %s\n", DL_MAIN, findData.cFileName); - sfallRes = findData.cFileName; } patchFiles.push_back(sfallRes); } diff --git a/sfall/Modules/Message.cpp b/sfall/Modules/Message.cpp index db76a341..de10c47a 100644 --- a/sfall/Modules/Message.cpp +++ b/sfall/Modules/Message.cpp @@ -174,7 +174,7 @@ static void ReadExtraGameMsgFiles() { path += ".msg"; fo::MessageList* list = new fo::MessageList(); if (fo::func::message_load(list, path.c_str()) == 1) { - Message::gExtraGameMsgLists.insert(std::make_pair(0x2000 + number, list)); + Message::gExtraGameMsgLists.emplace(0x2000 + number, list); } else { delete list; } diff --git a/sfall/Modules/ScriptExtender.cpp b/sfall/Modules/ScriptExtender.cpp index 8d6d1efe..c4efd423 100644 --- a/sfall/Modules/ScriptExtender.cpp +++ b/sfall/Modules/ScriptExtender.cpp @@ -561,7 +561,7 @@ static void PrepareGlobalScriptsListByMask() { fo::func::debug_printf("\n[SFALL] Script: %s will not be executed. A script with the same name already exists in another directory.", fullPath); continue; } - globalScriptFilesList.insert(std::make_pair(baseName, fullPath)); // script files should be sorted in alphabetical order + globalScriptFilesList.emplace(std::move(baseName), std::move(fullPath)); // script files should be sorted in alphabetical order } } fo::func::db_free_file_list(&filenames, 0); diff --git a/sfall/Modules/Sound.cpp b/sfall/Modules/Sound.cpp index 46df54af..938e78b9 100644 --- a/sfall/Modules/Sound.cpp +++ b/sfall/Modules/Sound.cpp @@ -16,7 +16,6 @@ * along with this program. If not, see . */ -#include #include #include #include @@ -31,7 +30,8 @@ namespace sfall { -#define SAFERELEASE(a) { if (a) { a->Release(); } } +#define WM_APP_DS_NOTIFY 0xA000 +#define SAFERELEASE(a) { if (a) { a->Release(); } } enum SoundType : DWORD { sfx_loop = 0, // sfall @@ -83,7 +83,7 @@ static bool deathSceneSpeech = false; static bool lipsPlaying = false; static void FreeSound(sDSSound* sound) { - sound->pEvent->SetNotifyWindow(0, WM_APP, 0); + sound->pEvent->SetNotifyWindow(0, WM_APP_DS_NOTIFY, 0); SAFERELEASE(sound->pAudio); SAFERELEASE(sound->pEvent); SAFERELEASE(sound->pSeek); @@ -93,8 +93,8 @@ static void FreeSound(sDSSound* sound) { } static void WipeSounds() { - for (size_t i = 0; i < playingSounds.size(); i++) FreeSound(playingSounds[i]); - for (size_t i = 0; i < loopingSounds.size(); i++) FreeSound(loopingSounds[i]); + for (auto &sound : playingSounds) FreeSound(sound); + for (auto &sound : loopingSounds) FreeSound(sound); playingSounds.clear(); loopingSounds.clear(); backgroundMusic = nullptr; @@ -105,33 +105,51 @@ static void WipeSounds() { } LRESULT CALLBACK SoundWndProc(HWND wnd, UINT msg, WPARAM w, LPARAM l) { - if (msg == WM_APP) { - if (!(l & 0xA0000000)) return 0; - sDSSound* sound = reinterpret_cast(l & ~0xA0000000); + if (msg == WM_APP_DS_NOTIFY) { + long id = l; + sDSSound* sound = nullptr; + size_t i; + if (id & SoundFlags::looping) { + for (i = 0; i < loopingSounds.size(); i++) { + if (loopingSounds[i]->id == id) { + sound = loopingSounds[i]; + break; + } + } + } else { + for (i = 0; i < playingSounds.size(); i++) { + if (playingSounds[i]->id == id) { + sound = playingSounds[i]; + break; + } + } + } + if (!sound || !sound->pEvent) return 0; + LONG e = 0; LONG_PTR p1 = 0, p2 = 0; - if (!FAILED(sound->pEvent->GetEvent(&e, &p1, &p2, 0))) { + bool shouldFree = false; + + while (!FAILED(sound->pEvent->GetEvent(&e, &p1, &p2, 0))) { + sound->pEvent->FreeEventParams(e, p1, p2); if (e == EC_COMPLETE) { if (sound->id & SoundFlags::looping) { LONGLONG pos = 0; sound->pSeek->SetPositions(&pos, AM_SEEKING_AbsolutePositioning, 0, AM_SEEKING_NoPositioning); sound->pControl->Run(); - sound->pEvent->FreeEventParams(e, p1, p2); } else { - sound->pEvent->FreeEventParams(e, p1, p2); if (sound->id & SoundFlags::on_stop) { // speech sound playback is completed fo::var::main_death_voiceover_done = 1; fo::var::endgame_subtitle_done = 1; lipsPlaying = false; speechSound = nullptr; } - playingSounds.erase( - std::find_if(playingSounds.cbegin(), playingSounds.cend(), [&](const sDSSound* snd) { return snd->id == sound->id; }) - ); - FreeSound(sound); + playingSounds.erase(playingSounds.cbegin() + i); + shouldFree = true; } } } + if (shouldFree) FreeSound(sound); return 0; } return DefWindowProc(wnd, msg, w, l); @@ -170,22 +188,34 @@ static DWORD GetSpeechPlayingPosition() { return static_cast(pos << 1); } -void __fastcall PauseSfallSound(sDSSound* sound) { - if (sound) sound->pControl->Pause(); -} +//void __fastcall PauseSfallSound(sDSSound* sound) { +// if (sound) sound->pControl->Pause(); +//} void __fastcall ResumeSfallSound(sDSSound* sound) { if (sound) sound->pControl->Run(); } void __stdcall PauseAllSfallSound() { - for (sDSSound* sound : loopingSounds) sound->pControl->Pause(); - for (sDSSound* sound : playingSounds) sound->pControl->Pause(); + for (sDSSound* sound : loopingSounds) { + sound->pEvent->SetNotifyFlags(AM_MEDIAEVENT_NONOTIFY); + sound->pControl->Pause(); + } + for (sDSSound* sound : playingSounds) { + sound->pEvent->SetNotifyFlags(AM_MEDIAEVENT_NONOTIFY); + sound->pControl->Pause(); + } } void __stdcall ResumeAllSfallSound() { - for (sDSSound* sound : loopingSounds) sound->pControl->Run(); - for (sDSSound* sound : playingSounds) sound->pControl->Run(); + for (sDSSound* sound : loopingSounds) { + sound->pEvent->SetNotifyFlags(0); + sound->pControl->Run(); + } + for (sDSSound* sound : playingSounds) { + sound->pEvent->SetNotifyFlags(0); + sound->pControl->Run(); + } } long Sound::CalculateVolumeDB(long masterVolume, long passVolume) { @@ -301,7 +331,7 @@ static sDSSound* PlayingSound(const wchar_t* pathFile, SoundMode mode, long adju break; } - sound->pEvent->SetNotifyWindow((OAHWND)soundwindow, WM_APP, ((unsigned long)sound | 0xA0000000)); + sound->pEvent->SetNotifyWindow((OAHWND)soundwindow, WM_APP_DS_NOTIFY, (LONG_PTR)sound->id); sound->pControl->Run(); if (isLoop) { diff --git a/sfall/Modules/Worldmap.cpp b/sfall/Modules/Worldmap.cpp index c53da37a..83ff9e1d 100644 --- a/sfall/Modules/Worldmap.cpp +++ b/sfall/Modules/Worldmap.cpp @@ -562,7 +562,7 @@ bool Worldmap::LoadData(HANDLE file) { ReadFile(file, &mID, 4, &sizeRead, 0); ReadFile(file, &elevData, sizeof(levelRest), &sizeRead, 0); if (sizeRead != sizeof(levelRest)) return true; - mapRestInfo.insert(std::make_pair(mID, elevData)); + mapRestInfo.emplace(mID, elevData); } if (count && !restMap) { HookCall(0x42E57A, critter_can_obj_dude_rest_hook); @@ -637,7 +637,7 @@ void Worldmap::SetRestMapLevel(int mapId, long elev, bool canRest) { elev++; } elevData.level[elev] = canRest; - mapRestInfo.insert(std::make_pair(mapId, elevData)); + mapRestInfo.emplace(mapId, elevData); } }