Page 1 of 1

Automap models and modifying SoundReplacement

Posted: Sat Feb 13, 2021 12:18 am
by XJDHDR
I have two things I need help with.

I've been trying to migrate SoundReplacement from using WWW to UnityWebRequest. The editor reports that it's outdated and there are comments in the code about migrating. I'll include the relevant portion of what I have so far. The problem is that while it works when I load replacement music, the game hard locks when it tries to load a WAV replacement (which causes streaming to be false). I'm pretty sure that it's the "WaitForSeconds(0)" call but if I don't add a way to make the code wait, unityWebRequestAudioClip might be equal to null when I assign it to the out variable.

Second question is where can I find the code that creates a dungeon automap's models? Especially the part where textures are applied to them?

Code: Select all

private static AudioClip unityWebRequestAudioClip;

private static bool TryImportAudioClip(string name, string extension, bool streaming, out AudioClip audioClip)
{
    // Seek from loose files
    string filePath = Path.Combine(soundPath, name + extension);
    if (File.Exists(filePath))
    {
        AudioType audioType = AudioType.UNKNOWN;
        if (extension.Equals("ogg", System.StringComparison.OrdinalIgnoreCase))
            audioType = AudioType.OGGVORBIS;
        else if (extension.Equals("wav", System.StringComparison.OrdinalIgnoreCase))
            audioType = AudioType.WAV;
        
        DaggerfallUnity.Instance.StartCoroutine(UseUnityWebRequest(filePath, streaming, audioType));
        
        while (unityWebRequestAudioClip == null)
            new WaitForSeconds(0);
        
        audioClip = unityWebRequestAudioClip;
        unityWebRequestAudioClip = null;
        Debug.LogErrorFormat("audioClip = " + audioClip + ", unityWebRequestAudioClip = " + unityWebRequestAudioClip);
        
        return true;
    }
}

private static IEnumerator UseUnityWebRequest(string filePath, bool streaming, AudioType audioType)
{
    using (UnityWebRequest unityWebRequest = UnityWebRequestMultimedia.GetAudioClip("file://" + filePath, audioType))
    {
        ((DownloadHandlerAudioClip)unityWebRequest.downloadHandler).streamAudio = true;
        unityWebRequest.SendWebRequest();
        if (streaming)
        {
            while (unityWebRequest.downloadProgress < 0.001)
                yield return new WaitForSeconds(0);
        }
        else
            yield return unityWebRequest.isDone;

        if (unityWebRequest.isNetworkError)
            Debug.LogErrorFormat("System error encountered while trying to load audioclip '{0}': {1}", filePath, unityWebRequest.error);
        else if (unityWebRequest.isHttpError)
            Debug.LogErrorFormat("Network error encountered while trying to load audioclip '{0}': {1}", filePath, unityWebRequest.responseCode);
        else
        {
            unityWebRequestAudioClip = ((DownloadHandlerAudioClip)unityWebRequest.downloadHandler).audioClip;
            Debug.LogWarningFormat("Web request done: " + unityWebRequestAudioClip + ", " + filePath);
        }
    }
}

Re: Automap models and modifying SoundReplacement

Posted: Sat Feb 13, 2021 11:16 am
by pango
Hi XJDHDR,

Yes, loading sounds can take time (compared to the time available to render frames), so it's done asynchronously using coroutines. I haven't used UnityWebRequest yet, but if you have code that depends on the completion of a coroutine, it probably should also be in a coroutine.
XJDHDR wrote: Sat Feb 13, 2021 12:18 am Second question is where can I find the mode that creates a dungeon automap's models? Especially the part where textures are applied to them?
You mean what class? That's in Assets/Scripts/Game/Automap.cs, in InjectMeshAndMaterialProperties()

Re: Automap models and modifying SoundReplacement

Posted: Tue Feb 16, 2021 1:52 am
by XJDHDR
pango wrote: Sat Feb 13, 2021 11:16 am Yes, loading sounds can take time (compared to the time available to render frames), so it's done asynchronously using coroutines. I haven't used UnityWebRequest yet, but if you have code that depends on the completion of a coroutine, it probably should also be in a coroutine.
The problem I've run into is that with WWW, you could create the AudioClip from the file that will be "downloaded" in the same thread that you create the downloader. It will then proceed in the background from there. A coroutine only needed to be created to clean up after the download finished.

Conversely, from what I've found for UnityWebRequest, pretty much all the work has to be done within a coroutine, including assigning the retrieved file to an AudioClip. Worse is that it will refuse to let you create an AudioClip for WAV files until it has finished downloading. This is also the case for OGG files unless you enable streaming. This means that I either need a way for the thread that requested the file to wait for the coroutine to finish. Or to refactor all of the dependant code to stop assuming that the AudioClip will be immediately available. At that point though, the question of just sticking with WWW becomes harder to answer. Even if it is obsolete, it works.
pango wrote: Sat Feb 13, 2021 11:16 am You mean what class? That's in Assets/Scripts/Game/Automap.cs, in InjectMeshAndMaterialProperties()
Thanks, I found that function and the place where the models are created.

Re: Automap models and modifying SoundReplacement

Posted: Tue Feb 16, 2021 7:12 pm
by XJDHDR
Here's another question somewhat related to the above. How does the folder hierarchy for scripts work in this project? If a contributor wants to add a new script to the repo, what are the guidelines for the folder it should be stored in?

Re: Automap models and modifying SoundReplacement

Posted: Tue Feb 16, 2021 11:41 pm
by Interkarma
If it's not clear where the script should go, try to place it in same folder as similar/related functionality. Or if you tell me about script's purpose, I'm happy to suggest a folder.

Here's a general breakdown of Scripts top-level folders.
  • API - all the base readers for DaggerfallConnect to read classic game files.
  • Editor - custom editor scripts.
  • External - outside scripts like iTween not created or maintained by us directly.
  • Game - all the core gameplay scripts, mostly sorted into subfolders based on game system.
  • Internal - mainly objects that bridge DaggerfallConnect data into Unity somehow - i.e. Daggerfall Tools for Unity.
  • Localization - related to localization.
  • Terrain - terrain helpers for world layout.
  • Utility - General helpers like image processing, date time support, animating materials, macro handling, camera tricks, etc.
In a project this old and large with so many humans involved, there's bound to be scripts that don't quite fit the structure or could arguably be placed elsewhere. Just ask if in doubt and I'll be happy to help. :)

Re: Automap models and modifying SoundReplacement

Posted: Wed Feb 17, 2021 12:06 am
by XJDHDR
The script in question is attached to every model used to build the Automap as those model objects are created. Based on your description, it sounds like it would go in the root of Game.

Re: Automap models and modifying SoundReplacement

Posted: Wed Feb 17, 2021 2:04 am
by Interkarma
Sounds good to me. :)