Automap models and modifying SoundReplacement

Discuss coding questions, pull requests, and implementation details.
Post Reply
User avatar
XJDHDR
Posts: 258
Joined: Thu Jan 10, 2019 5:15 pm
Location: New Zealand
Contact:

Automap models and modifying SoundReplacement

Post 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);
        }
    }
}
Last edited by XJDHDR on Sun Mar 21, 2021 7:38 am, edited 1 time in total.

User avatar
pango
Posts: 3344
Joined: Wed Jul 18, 2018 6:14 pm
Location: France
Contact:

Re: Automap models and modifying SoundReplacement

Post 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()
Mastodon: @pango@fosstodon.org
When a measure becomes a target, it ceases to be a good measure.
-- Charles Goodhart

User avatar
XJDHDR
Posts: 258
Joined: Thu Jan 10, 2019 5:15 pm
Location: New Zealand
Contact:

Re: Automap models and modifying SoundReplacement

Post 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.
Last edited by XJDHDR on Wed Feb 17, 2021 12:08 am, edited 1 time in total.

User avatar
XJDHDR
Posts: 258
Joined: Thu Jan 10, 2019 5:15 pm
Location: New Zealand
Contact:

Re: Automap models and modifying SoundReplacement

Post 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?

User avatar
Interkarma
Posts: 7234
Joined: Sun Mar 22, 2015 1:51 am

Re: Automap models and modifying SoundReplacement

Post 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. :)

User avatar
XJDHDR
Posts: 258
Joined: Thu Jan 10, 2019 5:15 pm
Location: New Zealand
Contact:

Re: Automap models and modifying SoundReplacement

Post 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.

User avatar
Interkarma
Posts: 7234
Joined: Sun Mar 22, 2015 1:51 am

Re: Automap models and modifying SoundReplacement

Post by Interkarma »

Sounds good to me. :)

Post Reply