[RELEASED] Www Loader - Fire'n'Forget with global Coroutiner

Wrapper for WWW basically, BUT:

  • Provide Fire’n’Forget API with a callback function.
  • Provide local cache by System.IO if the platform supports.
  • Provide custom timeout to interrupt the loading process.
  • Include a Coroutiner class to start a coroutine or delay call from any script.
  • Derive from CustomYieldInstruction for custom coroutine in case.

Remarks:

  • Full source code and example included, and here’s the web player example.
  • This has been tested only on Windows, made for my interactive project usage.
  • If you’re interested in the cache feature on other platforms, please contact me.

The further technical documentation is available here.
And the tutorial is right below.

WwwLoader:

  • Simple and similar APIs with callback to load each kind of data.

  • Or load a local image into an existing Texture2D.

  • Use WwwOption to set custom timeout or cache lifetime.

  • Use WWWForm to post data to a web server.

Coroutiner:

  • Start a global coroutine, just like using MonoBehaviour.

  • Repeat or delay call any action, and control the processing coroutine.

  • Use it from any script.

Release:

Www Loader - Fire'n'Forget with global Coroutiner | Network | Unity Asset Store

This thread is also for customer support, feel free to leave me a comment if you need.
Please let me know if there’s any question or suggestion.

I’d also forward important messages between the forum and my site to have them visible.
Thanks, enjoy!

Hi, guys,

I saw an issue below when getting the WWW’s MovieTexture.

Error: Cannot create FMOD::Sound instance for resource (null), (An invalid parameter was passed to this function. )
UnityEngine.WWW:get_movie()

It might be an Unity 5.3 bug post here.

The good news is the movie still plays well.
The bad one is, we may have to wait Unity to fix it.

New version 1.0.1 is currently “Published”.

  • Add a new class to run the coroutine since MonoBehaviour can’t be attached to a GameObject.
  • Remove logging when the loading starts or ends, since it’s noisy if used frequently.

I’m running a standalone windows build and it’s creating the folder i specify in

WwwLoader.cacheFolder = Path.GetFullPath(“Temp/images/cache”);

but after multiple calls to

WwwLoader.LoadImage(options, tex, (loader, data) => { });

the Temp/images/cache folder remains empty. The images are loading into my textures just fine, but nothing is caching.

Any thoughts?

Hi, thanks for your support at the first.
What file path did you load the image from? Is it from local or internet?
It downloads from internet and saves to local to make re-loading faster, so it won’t cache if loading a local image.

It is loading from the web. I’ve dug deeper and it appears to me that the filename that’s written to the cache is invalid as it’s adding double equals prior to the .jpg extension?

Here is the warning in the console (note: to protect sensitive client info I have modified the url to be invalid):

WwwLoader https://firebasestorage.googleapis.com/v0/b/dvr.appspot.com/o/wp_2.jpg?alt=media&token=e67baa3c-f3d8-489b-8692-0caa8a9680a5 failed to save cache.
System.IO.IOException: Win32 IO returned ERROR_INVALID_NAME. Path: E:\DVR\Temp\dvr\cache\4r4azGHr20hDAMcmDqyUKg==.jpg?alt=media&token=e67baa3c-f3d8-489b-8692-0caa8a9680a5
at System.IO.FileStream…ctor (System.String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, Boolean anonymous, FileOptions options) [0x00251] in /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.IO/FileStream.cs:320

Hi, @natwales

Thanks for your support and deeper digging with the log message, are you a programmer?
The problem looks caused by the generated cache file name.

I designed it for a normal URL without params, e.g., the “alt=media&token=e67…” after the “…jpg?”.
And use the “.jpg?..” as the cache file’s extension name, that it causes the exception.

[EDIT] If you’re willing, you can make it up by steps below:

  • Open the script file “Assets/WanzyeeStudio/Scripts/Basic/Class/WwwLoader.cs”.
  • Go to the line 179 and insert if(-1 != _e.IndexOfAny(Path.GetInvalidFileNameChars())) _e = “”;
  • It should work now, but the cache file may have no extension name.

[EDIT] Or you could try to send the params, e.g., “alt” and “token”, with WWWForm.

Then I’ll consider how to handle the cache file extension name to update the package.

Thank you, Regards,
Wanzyee

Thank @natwales for reporting the problem.

New version 1.0.3 is currently “Published”.

  • Fix the invalid char in the cache file extension name when the URL includes params.

It just works like before, but the cache file may have no extension name if the URL doesn’t end with a valid one.
The extension name examples below:

Please note, an audio URL must end with a file extension, that Unity depends on to determine the audio format.

First of all congratulations for the work done :wink:

Now i wanted to ask you (since i am a neophyte in C# and Unity)… how can i make synchronous my requests in a WebGL project? Then initiate a request, and wait for the result before performing any other action.

        public static void APIRequest2(string action, string user, string token){
            var timeout = 5f;
            var cache = TimeSpan.FromSeconds (1);
            string url = "...";
            WwwLoader.LoadText (
                new WwwOption(url, null, timeout, cache), (loader, data) => {
                    //if (null != loader.error) {
                        HandleData(data);
                    //}
                }
            );
        }

        public static void HandleData(string data){
            // ret now contains the contents of the rest service
            string sStrings = "0.00";

            XmlDocument xmlDoc = new XmlDocument ();
            xmlDoc.LoadXml (data);
            XmlNodeList itemList = xmlDoc.GetElementsByTagName ("item");

            foreach (XmlNode itemInfo in itemList) {
                XmlNodeList itemContent = itemInfo.ChildNodes;
                foreach (XmlNode itemItens in itemContent) {
                    if (itemItens.Name == "result") {
                        sStrings = itemItens.InnerText;

                    }
                }
            }
             
            updateGold(sStrings);

            Debug.LogWarning ("BESettings::APIRequest2: " + sStrings);
        }

Hi, @Collateral-Studios ,
Excuse me, I can’t properly understand your question… T-T

Q: “wait for the result before performing any other action.”
Your code looks fine, line9:“HandleData(data)” will be called after line6:“WwwLoader.LoadText” loaded.

Since you said “neophyte in C# and Unity”, my example code may be not clear enough.
I used C# anonymous method to make my example shorter…LOL

The example code:

WwwLoader.LoadText(
    new WwwOption(url, null, timeout, cache),
    (loader, data) => { if(null != loader.error) HandleData(data); }
);

could be understanded as below:

public void StartRequest(){
    WwwLoader.LoadText(
        new WwwOption(url, null, timeout, cache),
        ActionAfterWaitResult
    );
}

public void ActionAfterWaitResult(WwwLoader loader, string data){
    if(null != loader.error){
        Debug.LogError("Oops! " + loader.error);
    }else{
        //~~do whatever action you want here~~
    }
}

Does this help? Please let me know if you have further question.

Thanks for the immediate answer.
But in my project, i have several scenes and i call the wwwloader from the awake event of the second scene to set a value from the start.

If use the WebClient, i have no kind of problem, evidently the Weblient blocks any process until the end of its execution. But it does not work on WebGL

        public static void APIRequest(string action, string user, string token)
        {          
                var SyncClient = new WebClient ();

                try
                {
                    // actually execute the GET request
                    var content = SyncClient.DownloadString ("...");

                    // ret now contains the contents of the rest service
                    string sStrings = "0.00";

                    XmlDocument xmlDoc = new XmlDocument ();
                    ...

                    foreach (XmlNode itemInfo in itemList) {
                        ...
                                sStrings = itemItens.InnerText;
                        ...
                    }

                    tGold =  double.Parse(sStrings) /100;
                }
                catch (WebException we)
                {
                    // WebException.Status holds useful information
                    Console.WriteLine(we.Message + "\n" + we.Status.ToString());
                }
                catch (NotSupportedException ne)
                {
                    // other errors
                    Console.WriteLine(ne.Message);
                }
            }
        }

Hi, @Collateral-Studios ,
Did you mean what you want is: “Load 2nd scene > Invoke Awake() in the 2nd scene > Download settings > Set value > Run the 2nd scene” ?
So you want to block Unity main thread while loading?

Hi, @Collateral-Studios ,

Generally, we don’t want to block unity main thread, it causes the screen stuck.
So Unity makes WWW and Coroutine for doing other actions while downloading.

Here’s another code example in a format easier to read.

//Unity Coroutine, place in a MonoBehaviour
private IEnumerator Start(){
           
    var content = "";

    //start downloading and wait until finished with "yield return"
    yield return WwwLoader.LoadText(
        new WwwOption("...", null, 10f, TimeSpan.FromTicks(-1)),
        (l, s) => content = s
    );

    //do whatever after downloaded
    Debug.Log(content);

}

If you really need to “sync and block the main thread and stuck the screen”, please let me know, them I may need to update the scripts. LOL!

New version 1.0.4 is currently “Published”.

  • Add a flag of WwwOption to block the thread for sync loading.
private WwwOption option = new WwwOption("https://git.io/vDnp7"){ cache = TimeSpan.MinValue};
private void OnGUI(){

    GUILayout.Label(Time.frameCount.ToString()); //for watching if the screen stuck when sync
    option.sync = GUILayout.Toggle(option.sync, "Sync");

    if(GUILayout.Button("Load")){
        Debug.Log("Start");
        WwwLoader.LoadText(option, (loader, text) => Debug.Log(text));
        Debug.Log(option.sync ? "Sync" : "Async");
    }

}

New version 1.0.5 is currently “Published”.

  • Refactoring and update to use newer Unity API.
  • Move the example scene to a sub folder.

Yup, got included in Unity MEGA SALE !!

Hey guys,

Thank aixiang.cheng for reporting an issue as the attachment snapshot.

That WwwLoader gets the AudioClip or MovieTexture of a WWW by reflection for compatibility from Unity 5 to 5.6, even 2017.2, but it’s broken after 2017.4, because Unity changed the API.

I’ll upload the fixed package asap.

If, and only if, you face the same issue and have to make it work right away, you could modify the code described below:

  1. Find and open the file WwwLoader.cs.
  2. Find _movieGetter = GetPatchGetter<MovieTexture>("movie", "GetMovieTexture"); and replace to _movieGetter = (www) => www.GetMovieTexture();
  3. Find _audioGetter = GetPatchGetter<AudioClip>("audioClip", "GetAudioClip"); and replace to _audioGetter = (www) => www.GetAudioClip();
  4. Save and close the file, these will make it work with the new API after 2017.4.

Thank you.

New version 1.0.6 is currently “Published”.

  • Coroutiner now supports both play and edit mode, WwwLoader also does.
  • Coroutiner changes to use singleton component to run for better performance.
  • Fix the methods to get the AudioClip and MovieTexture in different Unity versions.
  • Avoid potential freezing by disposing the WWW in another thread.

Thank aixiang.cheng again for reporting the disposing issue.
If you faced it before the update published, you can find the file WwwLoader.cs, and edit it as below:

Find

www.Dispose();

Replace to

new Thread(() => www.Dispose()).Start();

Thanks for your support.

New version 1.0.7 is currently “Pblished”.

  • Provide assembly definition files, please be aware the script files were moved therefore.

It’s recommended to update only if you downloaded my other packages which include asmdef.