From 3e3bfd0baae4687abe1c38f945111fb8701c83d0 Mon Sep 17 00:00:00 2001 From: robojumper Date: Sat, 7 Jun 2025 22:29:27 +0200 Subject: [PATCH] A bit of source manager --- config/SOUE01/splits.txt | 1 + config/SOUE01/symbols.txt | 16 ++-- include/d/snd/d_snd_3d_actor.h | 2 - include/d/snd/d_snd_source.h | 17 ++-- include/d/snd/d_snd_source_group.h | 6 +- include/d/snd/d_snd_source_if.h | 5 +- include/d/snd/d_snd_source_mgr.h | 16 +++- src/d/snd/d_snd_control_player_mgr.cpp | 2 +- src/d/snd/d_snd_sound.cpp | 2 +- src/d/snd/d_snd_source.cpp | 16 ++-- src/d/snd/d_snd_source_group.cpp | 23 +++--- src/d/snd/d_snd_source_mgr.cpp | 107 ++++++++++++++++++++++++- 12 files changed, 165 insertions(+), 48 deletions(-) diff --git a/config/SOUE01/splits.txt b/config/SOUE01/splits.txt index 16053edc..8a4471e6 100644 --- a/config/SOUE01/splits.txt +++ b/config/SOUE01/splits.txt @@ -2456,6 +2456,7 @@ d/snd/d_snd_anim_sound.cpp: d/snd/d_snd_source_mgr.cpp: .text start:0x80382410 end:0x803864C8 align:16 .ctors start:0x804DB91C end:0x804DB920 + .sdata start:0x80574310 end:0x805743D0 .sbss start:0x80575DA8 end:0x80575DB0 .sdata2 start:0x8057DB68 end:0x8057DBC0 diff --git a/config/SOUE01/symbols.txt b/config/SOUE01/symbols.txt index b169a0e8..cc02a351 100644 --- a/config/SOUE01/symbols.txt +++ b/config/SOUE01/symbols.txt @@ -20985,20 +20985,20 @@ fn_803848B0 = .text:0x803848B0; // type:function size:0xAC fn_80384960 = .text:0x80384960; // type:function size:0x8C fn_803849F0 = .text:0x803849F0; // type:function size:0xC fn_80384A00 = .text:0x80384A00; // type:function size:0x174 -fn_80384B80 = .text:0x80384B80; // type:function size:0x178 -vt_0x10__14dSoundSource_cFv = .text:0x80384D00; // type:function size:0x8 -fn_80384D10 = .text:0x80384D10; // type:function size:0x78 +registerSource__15dSndSourceMgr_cFP14dSoundSource_c = .text:0x80384B80; // type:function size:0x178 +getCategory__14dSoundSource_cCFv = .text:0x80384D00; // type:function size:0x8 +isCertainEnemyType__15dSndSourceMgr_cFP14dSoundSource_c = .text:0x80384D10; // type:function size:0x78 fn_80384D90 = .text:0x80384D90; // type:function size:0x98 -fn_80384E30 = .text:0x80384E30; // type:function size:0xBC -fn_80384EF0 = .text:0x80384EF0; // type:function size:0xAC +unregisterSource__15dSndSourceMgr_cFP14dSoundSource_c = .text:0x80384E30; // type:function size:0xBC +removeSourceFromList__15dSndSourceMgr_cFP14dSoundSource_cPQ34nw4r2ut4List = .text:0x80384EF0; // type:function size:0xAC fn_80384FA0 = .text:0x80384FA0; // type:function size:0x14 -fn_80384FC0 = .text:0x80384FC0; // type:function size:0x50 +clearSourceLists__15dSndSourceMgr_cFv = .text:0x80384FC0; // type:function size:0x50 fn_80385010 = .text:0x80385010; // type:function size:0x60 fn_80385070 = .text:0x80385070; // type:function size:0x18 fn_80385090 = .text:0x80385090; // type:function size:0x18 fn_803850B0 = .text:0x803850B0; // type:function size:0x108 fn_803851C0 = .text:0x803851C0; // type:function size:0x74 -fn_80385240 = .text:0x80385240; // type:function size:0x64 +clearSourceList__15dSndSourceMgr_cFPQ34nw4r2ut4List = .text:0x80385240; // type:function size:0x64 fn_803852B0 = .text:0x803852B0; // type:function size:0x3C fn_803852F0 = .text:0x803852F0; // type:function size:0x3C fn_80385330 = .text:0x80385330; // type:function size:0x94 @@ -21130,7 +21130,7 @@ getSourceClosestToPlayer__17dSndSourceGroup_cFv = .text:0x80386DE0; // type:func fn_80386EF0 = .text:0x80386EF0; // type:function size:0x80 setParamFromName__17dSndSourceGroup_cFPCc = .text:0x80386F70; // type:function size:0x1A4C soundForActorInitRelated_803889c0 = .text:0x803889C0; // type:function size:0x4 -__ct__14dSoundSource_cFUcP9dAcBase_ciP17dSndSourceGroup_c = .text:0x803889D0; // type:function size:0x108 +__ct__14dSoundSource_cFUcP9dAcBase_cPCcP17dSndSourceGroup_c = .text:0x803889D0; // type:function size:0x108 __dt__14dSoundSource_cFv = .text:0x80388AE0; // type:function size:0xC4 vt_0x0C__14dSoundSource_cFv = .text:0x80388BB0; // type:function size:0x118 vt_0x44__14dSoundSource_cFv = .text:0x80388CD0; // type:function size:0x9C diff --git a/include/d/snd/d_snd_3d_actor.h b/include/d/snd/d_snd_3d_actor.h index ce5b37c7..dc93574d 100644 --- a/include/d/snd/d_snd_3d_actor.h +++ b/include/d/snd/d_snd_3d_actor.h @@ -7,8 +7,6 @@ #include "nw4r/snd/snd_Sound3DActor.h" class dSnd3DActor_c : public nw4r::snd::Sound3DActor { - static const u32 NUM_SOUNDS = 4; - public: dSnd3DActor_c(dSndSourceParam *pSourceParam, u8); diff --git a/include/d/snd/d_snd_source.h b/include/d/snd/d_snd_source.h index c19485ce..a304682d 100644 --- a/include/d/snd/d_snd_source.h +++ b/include/d/snd/d_snd_source.h @@ -6,13 +6,15 @@ #include "d/snd/d_snd_source_if.h" #include "nw4r/ut/ut_list.h" +#include + class dSndSourceGroup_c; /** Manages sound relating to a particular actor. */ /** Size: probably 0x15C */ class dSoundSource_c : public dSoundSourceIf_c, public dSnd3DActor_c { public: - dSoundSource_c(u8, dAcBase_c *, UNKWORD, dSndSourceGroup_c *pOwnerGroup); + dSoundSource_c(u8 sourceType, dAcBase_c *, const char *name, dSndSourceGroup_c *pOwnerGroup); virtual ~dSoundSource_c(); static u32 getCharacterTalkSoundId(u32 baseSoundId, dSoundSource_c *source); @@ -21,7 +23,10 @@ public: // This is where it gets a bit wild and this class starts mixing in overrides between // new virtual functions, which causes the vtable to list these functions in exactly this // order. - virtual const char *d_s_vt_0x17C() const; + virtual const char *getName() const; + bool isName(const char *name) const { + return !std::strcmp(getName(), name); + } virtual void d_s_vt_0x180(); virtual void d_s_vt_0x184(); virtual void d_s_vt_0x188(); @@ -60,7 +65,9 @@ public: // Overrides of dSoundSourceIf_c - always in the first section of // the vtable, so the order is not certain. May have to reorder for weak // function order. - + virtual s32 getCategory() const override { + return field_0x0FC; + } virtual const nw4r::math::VEC3 &getListenerPosition() const override; virtual bool hasPlayingSounds() const override; // 0x48 @@ -80,11 +87,11 @@ private: // at 0x58: thunk-vtable /* 0xE8 */ nw4r::ut::Node mMgrLink; - /* 0x0F0 */ UNKWORD field_0x0F0; + /* 0x0F0 */ const char *mpName; /* 0x0F4 */ UNKWORD field_0x0F4; /* 0x0F8 */ dAcBase_c *mpPlayer; /* 0x0FC */ u8 field_0x0FC; - /* 0x0FD */ u8 field_0x0FD; + /* 0x0FD */ u8 mSourceType; /* 0x0FE */ u8 field_0x0FE; /* 0x0FF */ u8 field_0x0FF; /* 0x100 */ u8 field_0x100; diff --git a/include/d/snd/d_snd_source_group.h b/include/d/snd/d_snd_source_group.h index cabf4f82..2e1e8c1f 100644 --- a/include/d/snd/d_snd_source_group.h +++ b/include/d/snd/d_snd_source_group.h @@ -21,7 +21,7 @@ class dSoundSource_c; class dSndSourceGroup_c { public: dSndSourceGroup_c(); - dSndSourceGroup_c(u32, const char*, u32, u32); + dSndSourceGroup_c(s32 sourceType, const char*, u32, s32 mSubtype); ~dSndSourceGroup_c(); void registerSource(dSoundSource_c *); @@ -46,8 +46,8 @@ private: /* 0x00 */ nw4r::ut::Node mNode1; /* 0x08 */ nw4r::ut::Node mNode2; /* 0x10 */ UNKWORD field_0x10; - /* 0x14 */ UNKWORD field_0x14; - /* 0x18 */ UNKWORD field_0x18; + /* 0x14 */ s32 mSourceCategory; + /* 0x18 */ s32 mSubtype; /* 0x1C */ u8 field_0x1C; /* 0x1D */ u8 field_0x1D; /* 0x1E */ SizedString<32> mName; diff --git a/include/d/snd/d_snd_source_if.h b/include/d/snd/d_snd_source_if.h index e1edb145..fa65be05 100644 --- a/include/d/snd/d_snd_source_if.h +++ b/include/d/snd/d_snd_source_if.h @@ -11,10 +11,11 @@ class dSoundSourceIf_c { public: virtual ~dSoundSourceIf_c() {} #define SOUNDSOURCE_VIRTUAL(offset) virtual void vt_##offset() = 0; + SOUNDSOURCE_VIRTUAL(0x0C); - SOUNDSOURCE_VIRTUAL(0x10); + virtual s32 getCategory() const = 0; // 0x10 SOUNDSOURCE_VIRTUAL(0x14); - virtual s32 getActorType() const; + virtual s32 getActorType() const = 0; SOUNDSOURCE_VIRTUAL(0x1C); SOUNDSOURCE_VIRTUAL(0x20); SOUNDSOURCE_VIRTUAL(0x24); diff --git a/include/d/snd/d_snd_source_mgr.h b/include/d/snd/d_snd_source_mgr.h index b74b13b4..5a728d2c 100644 --- a/include/d/snd/d_snd_source_mgr.h +++ b/include/d/snd/d_snd_source_mgr.h @@ -29,9 +29,17 @@ class dSndSourceMgr_c { public: dSndSourceMgr_c(); + void registerSource(dSoundSource_c *source); + void unregisterSource(dSoundSource_c *source); + void playFlowSound(u32 id); private: + static bool isCertainEnemyType(dSoundSource_c *source); + void removeSourceFromList(dSoundSource_c *source, nw4r::ut::List *list); + void clearSourceLists(); + void clearSourceList(nw4r::ut::List *list); + /* 0x0010 */ u8 field_0x0010; /* 0x0011 */ u8 field_0x0011; /* 0x0012 */ u8 field_0x0012; @@ -44,7 +52,7 @@ private: /* 0x003C */ dSndSourceGroup_c mGroups[NUM_GROUPS]; // Not sure what these are for - /* 0x383C */ nw4r::ut::List mSourceList1; // node offset 0xE8, probably into dSoundSource::mMgrLink + /* 0x383C */ nw4r::ut::List mAllSources; // node offset 0xE8, probably into dSoundSource::mMgrLink /* 0x3848 */ nw4r::ut::List field_0x3848; // node offset 0x15C, possibly a subset of source types /* 0x3854 */ nw4r::ut::List field_0x3854; // node offset 0x160 @@ -54,9 +62,9 @@ private: /* 0x386C */ f32 field_0x386C; /* 0x3870 */ dSoundSource_c *mpPlayerSource; - /* 0x3874 */ dSoundSource_c *mpFiTalkSource; - /* 0x3878 */ dSoundSource_c *field_0x3878; - /* 0x387C */ dSoundSource_c *field_0x387C; + /* 0x3874 */ dSoundSource_c *mpKenseiSource; + /* 0x3878 */ dSoundSource_c *mpBoomerangSource; + /* 0x387C */ dSoundSource_c *mpTBoatSource; /* 0x3880 */ dSoundSource_c *field_0x3880; // fi singing related? /* 0x3884 */ dSoundSource_c *field_0x3884; }; diff --git a/src/d/snd/d_snd_control_player_mgr.cpp b/src/d/snd/d_snd_control_player_mgr.cpp index 75fa02d1..5bb01d0a 100644 --- a/src/d/snd/d_snd_control_player_mgr.cpp +++ b/src/d/snd/d_snd_control_player_mgr.cpp @@ -146,7 +146,7 @@ void dSndControlPlayerMgr_c::calc() { void dSndControlPlayerMgr_c::executeControls() { dSndControlPlayer_c *next; - dSndControlPlayer_c *iter = static_cast(nw4r::ut::List_GetNext(&mActiveControls, nullptr)); + dSndControlPlayer_c *iter = static_cast(nw4r::ut::List_GetFirst(&mActiveControls)); while (iter != nullptr) { next = static_cast(nw4r::ut::List_GetNext(&mActiveControls, iter)); iter->calc(); diff --git a/src/d/snd/d_snd_sound.cpp b/src/d/snd/d_snd_sound.cpp index ff5a55a4..39354783 100644 --- a/src/d/snd/d_snd_sound.cpp +++ b/src/d/snd/d_snd_sound.cpp @@ -67,7 +67,7 @@ void dSndSound_c::calc() { } dSndControlSound_c *next; - dSndControlSound_c *iter = static_cast(nw4r::ut::List_GetNext(&mList, nullptr)); + dSndControlSound_c *iter = static_cast(nw4r::ut::List_GetFirst(&mList)); while (iter != nullptr) { next = static_cast(nw4r::ut::List_GetNext(&mList, iter)); iter->calc(); diff --git a/src/d/snd/d_snd_source.cpp b/src/d/snd/d_snd_source.cpp index 4e582666..73d55433 100644 --- a/src/d/snd/d_snd_source.cpp +++ b/src/d/snd/d_snd_source.cpp @@ -6,11 +6,12 @@ #include "d/snd/d_snd_mgr.h" #include "d/snd/d_snd_player_mgr.h" #include "d/snd/d_snd_source_group.h" +#include "d/snd/d_snd_source_mgr.h" #include "nw4r/snd/snd_SoundStartable.h" #include "nw4r/ut/ut_list.h" #include "sized_string.h" -extern "C" u8 fn_80382590(u8, UNKWORD); +extern "C" u8 fn_80382590(u8, const char*); struct d_snd_mgr_unk_6_sinit { d_snd_mgr_unk_6_sinit() : field_0x00(0), field_0x04(0.0f) {} @@ -25,12 +26,12 @@ const char *help_i_need_data() { return "%s_%s_%d"; } -dSoundSource_c::dSoundSource_c(u8 a1, dAcBase_c *player, UNKWORD a3, dSndSourceGroup_c *pOwnerGroup) - : dSnd3DActor_c(pOwnerGroup->getAmbientParam(), a1), - field_0x0F0(a3), +dSoundSource_c::dSoundSource_c(u8 sourceType, dAcBase_c *player, const char *name, dSndSourceGroup_c *pOwnerGroup) + : dSnd3DActor_c(pOwnerGroup->getAmbientParam(), sourceType), + mpName(name), field_0x0F4(0), mpPlayer(player), - field_0x0FD(a1), + mSourceType(sourceType), field_0x0FE(0), field_0x0FF(0), field_0x100(0), @@ -44,7 +45,7 @@ dSoundSource_c::dSoundSource_c(u8 a1, dAcBase_c *player, UNKWORD a3, dSndSourceG field_0x154(0), field_0x158(-1), field_0x15A(-1) { - field_0x0FC = fn_80382590(a1, a3); + field_0x0FC = fn_80382590(sourceType, name); // TODO: Offsetof nw4r::ut::List_Init(&field_0x110, 0xEC); nw4r::ut::List_Init(&field_0x120, 0x04); @@ -56,6 +57,7 @@ dSoundSource_c::~dSoundSource_c() { SetUserParam(0); vt_0x44(); d_s_vt_0x1BC(); + dSndSourceMgr_c::GetInstance()->unregisterSource(this); mpOwnerGroup->unregisterSource(this); } @@ -111,7 +113,7 @@ u32 dSoundSource_c::getCharacterTalkSoundId(u32 baseSoundId, dSoundSource_c *sou baseLabel = dSndMgr_c::GetInstance()->getArchive()->GetSoundLabelString(baseSoundId); } - const char *charLabel = source->d_s_vt_0x17C(); + const char *charLabel = source->getName(); label.sprintf("%s_%s", baseLabel, charLabel); u32 newLabel = dSndPlayerMgr_c::GetInstance()->convertLabelStringToSoundId(label); if (newLabel != -1) { diff --git a/src/d/snd/d_snd_source_group.cpp b/src/d/snd/d_snd_source_group.cpp index 91e2542e..1f938fb7 100644 --- a/src/d/snd/d_snd_source_group.cpp +++ b/src/d/snd/d_snd_source_group.cpp @@ -9,18 +9,19 @@ extern "C" bool isInStage(const char *stageName); -void dSndSourceGroup_c::set(s32 type, const char *name) { +void dSndSourceGroup_c::set(s32 sourceType, const char *name) { + // TODO enums resetSoundSourceParam(); bool assignedParam = false; - switch (field_0x14) { + switch (mSourceCategory) { case 0: { assignedParam = true; mParam.field_0x10 = INFINITY; break; } case 1: - if (type == 7) { + if (sourceType == 7) { assignedParam = true; mParam.field_0x00 = 1500.0f; mParam.field_0x10 = INFINITY; @@ -28,7 +29,7 @@ void dSndSourceGroup_c::set(s32 type, const char *name) { break; } - if (!assignedParam && (type == 44 || type == 58)) { + if (!assignedParam && (sourceType == 44 || sourceType == 58)) { assignedParam = true; mParam.field_0x10 = INFINITY; } @@ -38,7 +39,7 @@ void dSndSourceGroup_c::set(s32 type, const char *name) { } if (!assignedParam) { - switch (type) { + switch (sourceType) { case 51: { mParam.field_0x00 = 300.0f; mParam.field_0x04 = 800.0; @@ -69,7 +70,7 @@ void dSndSourceGroup_c::resetSoundSourceParam() { } dSndSourceGroup_c::dSndSourceGroup_c() - : field_0x18(0), + : mSubtype(0), field_0x1C(0), field_0x1D(0), mName(""), @@ -110,10 +111,10 @@ void dSndSourceGroup_c::unregisterSource(dSoundSource_c *source) { } void dSndSourceGroup_c::clearList() { - dSoundSource_c *source = static_cast(nw4r::ut::List_GetNext(&mSourceList, nullptr)); + dSoundSource_c *source = static_cast(nw4r::ut::List_GetFirst(&mSourceList)); while (source != nullptr) { nw4r::ut::List_Remove(&mSourceList, source); - source = static_cast(nw4r::ut::List_GetNext(&mSourceList, nullptr)); + source = static_cast(nw4r::ut::List_GetFirst(&mSourceList)); } } @@ -124,7 +125,7 @@ dSoundSource_c *dSndSourceGroup_c::getSourceClosestToListener() { mpCachedClosestSourceToListener = nullptr; f32 closest = INFINITY; - for (dSoundSource_c *source = static_cast(nw4r::ut::List_GetNext(&mSourceList, nullptr)); + for (dSoundSource_c *source = static_cast(nw4r::ut::List_GetFirst(&mSourceList)); source != nullptr; source = static_cast(nw4r::ut::List_GetNext(&mSourceList, source))) { if (source->getActorType() != 1 && source->getActorType() != 48) { f32 dist = source->getDistanceToListener(); @@ -144,12 +145,12 @@ dSoundSource_c *dSndSourceGroup_c::getSourceClosestToPlayer() { } if ((s32)nw4r::ut::List_GetSize(&mSourceList) <= 1) { - return static_cast(nw4r::ut::List_GetNext(&mSourceList, nullptr)); + return static_cast(nw4r::ut::List_GetFirst(&mSourceList)); } mpCachedClosestSourceToPlayer = nullptr; f32 closest = INFINITY; - for (dSoundSource_c *source = static_cast(nw4r::ut::List_GetNext(&mSourceList, nullptr)); + for (dSoundSource_c *source = static_cast(nw4r::ut::List_GetFirst(&mSourceList)); source != nullptr; source = static_cast(nw4r::ut::List_GetNext(&mSourceList, source))) { if (source->getActorType() != 1 && source->getActorType() != 48) { f32 dist = source->getDistanceToPlayer(); diff --git a/src/d/snd/d_snd_source_mgr.cpp b/src/d/snd/d_snd_source_mgr.cpp index 8cf61822..0dcc9ed4 100644 --- a/src/d/snd/d_snd_source_mgr.cpp +++ b/src/d/snd/d_snd_source_mgr.cpp @@ -18,9 +18,9 @@ dSndSourceMgr_c::dSndSourceMgr_c() field_0x3868(0), field_0x386C(INFINITY), mpPlayerSource(nullptr), - mpFiTalkSource(nullptr), - field_0x3878(nullptr), - field_0x387C(nullptr), + mpKenseiSource(nullptr), + mpBoomerangSource(nullptr), + mpTBoatSource(nullptr), field_0x3880(nullptr), field_0x3884(nullptr) { // TODO offsetof @@ -29,7 +29,7 @@ dSndSourceMgr_c::dSndSourceMgr_c() // TODO figure out what these are for nw4r::ut::List_Init(&mGroupList3, 8); - nw4r::ut::List_Init(&mSourceList1, 0xE8); + nw4r::ut::List_Init(&mAllSources, 0xE8); nw4r::ut::List_Init(&field_0x3848, 0x15C); nw4r::ut::List_Init(&field_0x3854, 0x160); @@ -39,3 +39,102 @@ dSndSourceMgr_c::dSndSourceMgr_c() nw4r::ut::List_Append(&mGroupList2, group); } } + +void dSndSourceMgr_c::registerSource(dSoundSource_c *source) { + if (source != nullptr) { + nw4r::ut::List_Append(&mAllSources, source); + // TODO enums + switch (source->getCategory()) { + case 0: { + if (source->getActorType() == 0 && mpPlayerSource == nullptr) { + mpPlayerSource = source; + } + break; + } + case 1: { + if (source->getActorType() == 6) { + mpBoomerangSource = source; + } + break; + } + case 2: { + if (isCertainEnemyType(source)) { + nw4r::ut::List_Append(&field_0x3848, source); + } + break; + } + case 6: { + nw4r::ut::List_Append(&field_0x3854, source); + break; + } + case 3: { + if (source->isName("TBoat") && mpTBoatSource == nullptr) { + mpTBoatSource = source; + } + break; + } + case 4: { + if (source->getActorType() == 44) { + mpKenseiSource = source; + } + break; + } + } + } +} + +void dSndSourceMgr_c::unregisterSource(dSoundSource_c *source) { + if (source != nullptr) { + removeSourceFromList(source, &mAllSources); + removeSourceFromList(source, &field_0x3848); + removeSourceFromList(source, &field_0x3854); + if (source == mpPlayerSource) { + mpPlayerSource = nullptr; + } else if (source == mpKenseiSource) { + mpKenseiSource = nullptr; + } else if (source == mpBoomerangSource) { + mpBoomerangSource = nullptr; + } + + if (mpTBoatSource == source) { + mpTBoatSource = nullptr; + } + } +} + +void dSndSourceMgr_c::removeSourceFromList(dSoundSource_c *source, nw4r::ut::List *list) { + if (source != nullptr && list != nullptr) { + // This removal code appears to be needlessly defensive + dSoundSource_c *sourceIter = static_cast(nw4r::ut::List_GetFirst(list)); + while (sourceIter != nullptr) { + if (field_0x3880 == source) { + // why in here???? + field_0x3880 = nullptr; + } + + if (sourceIter == source) { + nw4r::ut::List_Remove(list, sourceIter); + sourceIter = nullptr; + } else { + sourceIter = static_cast(nw4r::ut::List_GetNext(list, sourceIter)); + } + } + } +} + +void dSndSourceMgr_c::clearSourceLists() { + clearSourceList(&mAllSources); + clearSourceList(&field_0x3848); + clearSourceList(&field_0x3854); + mpPlayerSource = nullptr; +} + +void dSndSourceMgr_c::clearSourceList(nw4r::ut::List *list) { + if (list != nullptr) { + dSoundSource_c *sourceIter = static_cast(nw4r::ut::List_GetFirst(list)); + while (sourceIter != nullptr) { + nw4r::ut::List_Remove(list, sourceIter); + sourceIter = static_cast(nw4r::ut::List_GetFirst(list)); + } + } +}