From 205c67284cd66cca91e4eca9f407e5fd74193bee Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sun, 13 Apr 2025 13:05:17 +0200
Subject: [PATCH 1/5] Set version to 0.13.3

---
 CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8eff2a4a6..6e3628618 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.14)
 
-project(libscratchcpp VERSION 0.13.2 LANGUAGES C CXX)
+project(libscratchcpp VERSION 0.13.3 LANGUAGES C CXX)
 
 set(CMAKE_INCLUDE_CURRENT_DIR ON)
 set(CMAKE_CXX_STANDARD 17)

From caa0b62d672e0f75504316702946a9529961ea1e Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sun, 13 Apr 2025 16:29:30 +0200
Subject: [PATCH 2/5] Make scratchcpp-audio a shared library

Should fix this build error:
ld: warning: libminiaudio.so, needed by ../../scratchcpp-render/libscratchcpp/libscratchcpp.so, not found (try using -rpath or -rpath-link)
---
 src/audio/CMakeLists.txt | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/audio/CMakeLists.txt b/src/audio/CMakeLists.txt
index f3319207d..72d98eb76 100644
--- a/src/audio/CMakeLists.txt
+++ b/src/audio/CMakeLists.txt
@@ -1,6 +1,6 @@
 option(LIBSCRATCHCPP_AUDIO_SUPPORT "Audio support" ON)
 
-add_library(scratchcpp-audio STATIC)
+add_library(scratchcpp-audio SHARED)
 set(MINIAUDIO_SRC internal/thirdparty/miniaudio)
 
 if (LIBSCRATCHCPP_AUDIO_SUPPORT)
@@ -11,7 +11,7 @@ if (LIBSCRATCHCPP_AUDIO_SUPPORT)
     target_include_directories(scratchcpp-audio PUBLIC ${CMAKE_CURRENT_LIST_DIR}/${MINIAUDIO_SRC})
     install(TARGETS miniaudio DESTINATION lib)
 
-    target_link_libraries(scratchcpp-audio PRIVATE miniaudio)
+    target_link_libraries(scratchcpp-audio PUBLIC miniaudio)
     target_compile_definitions(scratchcpp-audio PUBLIC LIBSCRATCHCPP_AUDIO_SUPPORT)
 endif()
 
@@ -49,3 +49,5 @@ else()
         internal/audioloudnessstub.h
     )
 endif()
+
+install(TARGETS scratchcpp-audio DESTINATION lib)

From e73192fefe82f56b4a27a0cd796c852f5023e2ad Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sun, 13 Apr 2025 17:49:43 +0200
Subject: [PATCH 3/5] fix #639: Use memcpy() to copy downloaded asset data

---
 src/project_p.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/project_p.cpp b/src/project_p.cpp
index 5dd383311..48a414951 100644
--- a/src/project_p.cpp
+++ b/src/project_p.cpp
@@ -122,7 +122,7 @@ bool ProjectPrivate::tryLoad(IProjectReader *reader)
         for (size_t i = 0; i < assets.size(); i++) {
             const std::string &data = assetData[i];
             char *ptr = (char *)malloc(data.size() * sizeof(char));
-            strncpy(ptr, data.data(), data.size());
+            memcpy(ptr, data.data(), data.size() * sizeof(char));
             assets[assetNames[i]]->setData(data.size(), ptr);
         }
 

From 9608b4b5551a6020dab1d8d836252d81e1359431 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sun, 13 Apr 2025 18:21:50 +0200
Subject: [PATCH 4/5] Use static variables for global instances of audio
 classes

---
 src/audio/audioinput.cpp           |  4 ++--
 src/audio/audioinput.h             |  2 --
 src/audio/audiooutput.cpp          |  4 ++--
 src/audio/audiooutput.h            |  3 ---
 src/audio/internal/audioengine.cpp | 16 ++++++++--------
 src/audio/internal/audioengine.h   |  8 +++-----
 6 files changed, 15 insertions(+), 22 deletions(-)

diff --git a/src/audio/audioinput.cpp b/src/audio/audioinput.cpp
index 38f1c263b..1d7b87529 100644
--- a/src/audio/audioinput.cpp
+++ b/src/audio/audioinput.cpp
@@ -10,7 +10,7 @@
 
 using namespace libscratchcpp;
 
-std::shared_ptr<IAudioInput> AudioInput::m_instance = std::make_shared<AudioInput>();
+static std::shared_ptr<IAudioInput> INSTANCE = std::make_shared<AudioInput>();
 
 AudioInput::AudioInput()
 {
@@ -18,7 +18,7 @@ AudioInput::AudioInput()
 
 std::shared_ptr<IAudioInput> AudioInput::instance()
 {
-    return m_instance;
+    return INSTANCE;
 }
 
 std::shared_ptr<IAudioLoudness> AudioInput::audioLoudness() const
diff --git a/src/audio/audioinput.h b/src/audio/audioinput.h
index 527dc6626..7d59e6e6f 100644
--- a/src/audio/audioinput.h
+++ b/src/audio/audioinput.h
@@ -19,8 +19,6 @@ class AudioInput : public IAudioInput
         std::shared_ptr<IAudioLoudness> audioLoudness() const override;
 
     private:
-        static std::shared_ptr<IAudioInput> m_instance;
-
         mutable std::shared_ptr<IAudioLoudness> m_audioLoudness;
 };
 
diff --git a/src/audio/audiooutput.cpp b/src/audio/audiooutput.cpp
index c7f15d4c7..96e1c9e76 100644
--- a/src/audio/audiooutput.cpp
+++ b/src/audio/audiooutput.cpp
@@ -10,7 +10,7 @@
 
 using namespace libscratchcpp;
 
-std::shared_ptr<IAudioOutput> AudioOutput::m_instance = std::make_shared<AudioOutput>();
+static std::shared_ptr<IAudioOutput> INSTANCE = std::make_shared<AudioOutput>();
 
 AudioOutput::AudioOutput()
 {
@@ -18,7 +18,7 @@ AudioOutput::AudioOutput()
 
 std::shared_ptr<IAudioOutput> AudioOutput::instance()
 {
-    return m_instance;
+    return INSTANCE;
 }
 
 std::shared_ptr<IAudioPlayer> AudioOutput::createAudioPlayer() const
diff --git a/src/audio/audiooutput.h b/src/audio/audiooutput.h
index bb6e734bb..e331b545a 100644
--- a/src/audio/audiooutput.h
+++ b/src/audio/audiooutput.h
@@ -15,9 +15,6 @@ class AudioOutput : public IAudioOutput
         static std::shared_ptr<IAudioOutput> instance();
 
         std::shared_ptr<IAudioPlayer> createAudioPlayer() const override;
-
-    private:
-        static std::shared_ptr<IAudioOutput> m_instance;
 };
 
 } // namespace libscratchcpp
diff --git a/src/audio/internal/audioengine.cpp b/src/audio/internal/audioengine.cpp
index 1af3874d4..aa170f6c4 100644
--- a/src/audio/internal/audioengine.cpp
+++ b/src/audio/internal/audioengine.cpp
@@ -7,27 +7,27 @@
 
 using namespace libscratchcpp;
 
-AudioEngine AudioEngine::instance;
+static AudioEngine INSTANCE;
 
 IAudioEngine *IAudioEngine::instance()
 {
-    return &AudioEngine::instance;
+    return &INSTANCE;
 }
 
 ma_engine *AudioEngine::engine()
 {
-    if (!instance.m_initialized)
-        instance.init();
+    if (!INSTANCE.m_initialized)
+        INSTANCE.init();
 
-    return instance.m_initialized ? instance.m_engine : nullptr;
+    return INSTANCE.m_initialized ? INSTANCE.m_engine : nullptr;
 }
 
 bool AudioEngine::initialized()
 {
-    if (!instance.m_initialized)
-        instance.init();
+    if (!INSTANCE.m_initialized)
+        INSTANCE.init();
 
-    return instance.m_initialized;
+    return INSTANCE.m_initialized;
 }
 
 float AudioEngine::volume() const
diff --git a/src/audio/internal/audioengine.h b/src/audio/internal/audioengine.h
index 02672ff30..4b030837d 100644
--- a/src/audio/internal/audioengine.h
+++ b/src/audio/internal/audioengine.h
@@ -15,6 +15,9 @@ namespace libscratchcpp
 class AudioEngine : public IAudioEngine
 {
     public:
+        AudioEngine();
+        ~AudioEngine();
+
         friend class IAudioEngine;
 
         static ma_engine *engine();
@@ -24,13 +27,8 @@ class AudioEngine : public IAudioEngine
         void setVolume(float volume) override;
 
     private:
-        AudioEngine();
-        ~AudioEngine();
-
         void init();
 
-        static AudioEngine instance;
-
         ma_engine *m_engine = nullptr;
         bool m_initialized = false;
         float m_volume = 1.0f;

From 6741f0375700f531e2a23e4a1277756d897b0812 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sun, 13 Apr 2025 18:39:09 +0200
Subject: [PATCH 5/5] Fix missing asset data

Multiple assets can use the same asset file.
---
 src/project_p.cpp | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/src/project_p.cpp b/src/project_p.cpp
index 48a414951..bfc005ae5 100644
--- a/src/project_p.cpp
+++ b/src/project_p.cpp
@@ -76,7 +76,7 @@ bool ProjectPrivate::tryLoad(IProjectReader *reader)
 
         // Get asset file names
         std::vector<std::string> assetNames;
-        std::unordered_map<std::string, Asset *> assets;
+        std::unordered_map<std::string, std::vector<Asset *>> assets; // multiple assets can use the same file
         const auto &targets = reader->targets();
 
         for (auto target : targets) {
@@ -87,18 +87,18 @@ bool ProjectPrivate::tryLoad(IProjectReader *reader)
                 auto it = std::find(assetNames.begin(), assetNames.end(), costume->fileName());
                 if (it == assetNames.end()) {
                     assetNames.push_back(costume->fileName());
-                    assets[assetNames.back()] = costume.get();
+                    assets[assetNames.back()] = { costume.get() };
                 } else
-                    assets[*it] = costume.get();
+                    assets[*it].push_back(costume.get());
             }
 
             for (auto sound : sounds) {
                 auto it = std::find(assetNames.begin(), assetNames.end(), sound->fileName());
                 if (it == assetNames.end()) {
                     assetNames.push_back(sound->fileName());
-                    assets[assetNames.back()] = sound.get();
+                    assets[assetNames.back()] = { sound.get() };
                 } else
-                    assets[*it] = sound.get();
+                    assets[*it].push_back(sound.get());
             }
         }
 
@@ -120,10 +120,14 @@ bool ProjectPrivate::tryLoad(IProjectReader *reader)
 
         // Load asset data
         for (size_t i = 0; i < assets.size(); i++) {
-            const std::string &data = assetData[i];
-            char *ptr = (char *)malloc(data.size() * sizeof(char));
-            memcpy(ptr, data.data(), data.size() * sizeof(char));
-            assets[assetNames[i]]->setData(data.size(), ptr);
+            const std::vector<Asset *> &assetList = assets[assetNames[i]];
+
+            for (Asset *asset : assetList) {
+                const std::string &data = assetData[i];
+                char *ptr = (char *)malloc(data.size() * sizeof(char));
+                memcpy(ptr, data.data(), data.size() * sizeof(char));
+                asset->setData(data.size(), ptr);
+            }
         }
 
     } else {
