adlnet-archive / scorm4unity

The Unity-SCORM Integration Toolkit is a demonstration of how content developers can use a game engine to create SCORM-Conformant content.
34 stars 17 forks source link

Unity 4.3 breaks scorm4unity - threading issue #11

Open jdessart-mt opened 10 years ago

jdessart-mt commented 10 years ago

UnityEngine.Application.ExternalCall no longer works from a secondary thread, and so many of the calls that ScormManager and ScormAPIWrapper make now fail.

jdessart-mt commented 10 years ago

I was able to work around this by wrapping all UnityEngine calls in delegates queued to run on the main thread, using an external library.

KlingOne commented 10 years ago

@jdessart-mt could you post a patch for your solution?

jdessart-mt commented 10 years ago

Edit: I used Loom, available from here: http://unitygems.com/threads/, which the author says is MIT licensed. My patch may not be useful, since part of it involved simply cutting out logging, since it worked otherwise and the logging wasn't crucial to the project needs at the time.

Essentially, I wrapped any call to Unity functions that must be run on the main thread in Loom.QueueOnMainThread. I'll attach the diff for the API wrapper, since it should be usable directly.


Unfortunately, it relies on third party code, so I'm not sure it would be useful here. The idea behind that code is to use a MonoBehaviour which keeps a list of delegates. Code executing on other threads adds to this list, and then those delegates are called from within the MonoBehaviour's Update method.

I can see if the author would be willing to include that code in scorm4unity.

jdessart-mt commented 10 years ago

Couldn't find where to attach a diff, so I've pasted it in here:

79c79,83
<             UnityEngine.Application.ExternalCall("doIsScorm2004",new object[] {CallbackObjectName, CallbackFunctionName, key });
---
> 
>             Loom.QueueOnMainThread(() =>
>             {
>                 UnityEngine.Application.ExternalCall("doIsScorm2004", new object[] { CallbackObjectName, CallbackFunctionName, key });
>             });
205c209,212
<                     UnityEngine.Application.ExternalCall("DebugPrint", "error " + e.Message);
---
>                     Loom.QueueOnMainThread(() =>
>                     {
>                         UnityEngine.Application.ExternalCall("DebugPrint", "error " + e.Message);
>                     });
243c250,254
<             UnityEngine.Application.ExternalCall("doGetValue", new object[] { get.GetIdentifier() , CallbackObjectName, CallbackFunctionName, key });
---
> 
>             Loom.QueueOnMainThread(() =>
>             {
>                 UnityEngine.Application.ExternalCall("doGetValue", new object[] { get.GetIdentifier(), CallbackObjectName, CallbackFunctionName, key });
>             });
276,277c287,293
<               UnityEngine.Application.ExternalCall("doSetValue", new object[] { set.GetIdentifier(), set.GetValue(), CallbackObjectName, CallbackFunctionName, key });
<               APICallResult returnval = WaitForReturn(key);
---
> 
>                 Loom.QueueOnMainThread(() =>
>                 {
>                     UnityEngine.Application.ExternalCall("doSetValue", new object[] { set.GetIdentifier(), set.GetValue(), CallbackObjectName, CallbackFunctionName, key });
>                 });
>               
>                 APICallResult returnval = WaitForReturn(key);
300c316,319
<           UnityEngine.GameObject.Find(CallbackObjectName).SendMessage("LogMessage",text,UnityEngine.SendMessageOptions.DontRequireReceiver);
---
>             Loom.QueueOnMainThread(() =>
>             {
>                 UnityEngine.GameObject.Find(CallbackObjectName).SendMessage("LogMessage", text, UnityEngine.SendMessageOptions.DontRequireReceiver);
>             });
307c326,329
<           UnityEngine.Application.ExternalCall("doCommit");   
---
>             Loom.QueueOnMainThread(() =>
>             {
>                 UnityEngine.Application.ExternalCall("doCommit");
>             });
314c336,339
<           UnityEngine.Application.ExternalCall("doTerminate");    
---
>             Loom.QueueOnMainThread(() =>
>             {
>                 UnityEngine.Application.ExternalCall("doTerminate");
>             });