Search Unity

Cannot cast to base class on Windows 8 Phone/Store

Discussion in 'Windows' started by Demigiant, Mar 2, 2015.

  1. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Hello,

    I'm developing and maintaining a tween engine for Unity, DOTween, but some users recently encountered an issue with Windows 8 Phone/Store (while everything works perfectly on all other platforms). After some investigation, it seems that the reason is that a derived class fails to be cast to its base one.

    Specifically, I have a
    Code (csharp):
    1. public class Vector3Plugin : ABSTweenPlugin<Vector3,Vector3,VectorOptions>
    which, when cast to its base, for example like this:
    Code (csharp):
    1. Vector3Plugin plug = new Vector3Plugin();
    2. return plug as ABSTweenPlugin<Vector3,Vector3,VectorOptions>;
    returns null if inside a DLL, or throws an exception
    if used directly inside some lose scripts.

    This cast should totally be possible, and happens only for Windows 8 Phone/Store targets. Any chance of a workaround, or even better of a possible fix?

    Thanks.
     
    Last edited: Mar 2, 2015
  2. Gaspar

    Gaspar

    Joined:
    Jun 14, 2014
    Posts:
    28
    Way to reproduce for me:
    1) Open project from attachment
    2) Build Windows Store, target Phone 8.1
    3) Build in Release mode and ARM
    4) Run on Windows Phone device
    5) I see "Tween 2" on the screen, but it should be "Tween 1"

    Visual Studio 2013, Unity 4.6.2f1
     

    Attached Files:

  3. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Just FYI, tried it on x86 Windows Phone emulator both from Unity 4.6.3 and Unity 5 RC3 - can't reproduce issue. Looks like a bug which only reproduces on ARM device.
     
  4. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,732
    Can you report this as a bug?
    Thanks.
     
  5. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    @Gaspar could you do that? Since I don't have Windows 8 I can't report it correctly.
     
  6. Gaspar

    Gaspar

    Joined:
    Jun 14, 2014
    Posts:
    28
    Reported. Case 676958
     
    codestage, Philipps and Demigiant like this.
  7. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Hello,

    Any news about this issue? That type of cast can't be replaced in the engine, and is severely breaking ports to the WP8 platform.
     
  8. Gaspar

    Gaspar

    Joined:
    Jun 14, 2014
    Posts:
    28
  9. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    I added a big balloon to DOTween's website to report this issue and with a link to the voting.
     
  10. myak

    myak

    Joined:
    Mar 30, 2015
    Posts:
    5
    I'm a rather beginner C# programmer, so I'm not sure if this applies, but I found this StackOverflow discussion. It's a bit different, as it's a runtime issue in our case, and not a compiler one. But one of the answers suggests casting to object first and then to the desired type as a workaround, maybe this would help. I don't yet own a WP device, so I can't test it myself.
     
  11. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Thanks @myak, I think I tried that already, but I'm gonna try again to be sure.
     
  12. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Interesting news, thanks to Rafal who's helping me test various options to try and work around this issue. For now we were unsuccessful, but Rafal discovered an interesting things.

    From VS:
    Debug build works
    Release build doesn't and generates the known error
    Master build (which apparently should be the build to set for final production) works!

    So in the meantime you can use master build. @Aurimas Cernius, maybe this info can be useful to you?
     
  13. XenoBits

    XenoBits

    Joined:
    Aug 28, 2014
    Posts:
    27
    I encountered the issue, as stated by Izitmee the Master build will work if executed or deployed from Visual Studio.

    Unefortunately it will not work if the build is deployed by others means, which can lead to issues during app certification or worst once the app is live on the store.
     
  14. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    I have an idea for a way to fix this issue (even if I hope Unity fixes it on their side too), since this seems to happen only with Unity's "interchangeable" structs (Vector2/3/4, probably also Color/Color32), because they kind of break some rules of the C# language.

    I'm sending a test copy to Rafal and we'll see.
     
  15. rafaellop

    rafaellop

    Joined:
    Feb 4, 2015
    Posts:
    26
    Hi,

    I've done 12 test builds Izitmee's test package with the following SDKs:

    UNITY Windows Phone 8 platform: debug, release, master

    UNITY Windows Store platform:
    Universal App: debug, release, master
    Phone 8.1 SDK: debug, release, master
    desktop SDK 8.1: debug, release, master

    In all cases the test passed correctly and with no debug errors.

    Cheers,
    Rafal
     
  16. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Note that @rafaellop's test passed correctly when tweening integers, not when tweening a Unity Vector3, which is the real issue. We're trying more tests now to find a workaround for that.
     
  17. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,675
    Heads up: we're looking into this. I don't have any updates yet, but I'll post here when I find out something.
     
    Last edited: Apr 13, 2015
  18. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    @Tautvydas Zilys Thank youuuuu :) I believe the reason is the way the implicit Vector2/3/4 (as well as Color/Color32) interchangeable cast is implemented in the Unity Engine.
     
  19. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,675
    Hi,

    we asked Microsoft for help pinning this issue down, and they have found the root cause of it. It's happening due to the combination of the way we handle assembly references and the way their tools compile managed assemblies to native code before deploying them to the phone (that's why you saw differences according to how it was deployed).

    This issue may affect generic types with generic arguments, that are defined in UnityEngine.dll and are value types (classes are not affected). So, Vector2/3/4, Color and Color32 (and several others) meet this requirement.

    We are currently looking for workarounds we can give you. I'll get back to this thread as soon as we find a solution.
     
    Demigiant likes this.
  20. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Thank you @Tautvydas Zilys !

    In the meantime I created an alternative version of DOTween which works on WP8.1 too (and on all other platforms). It's slightly slower (but just slightly) so I'll scrap it as soon as you'll have a viable alternative, but in the meantime I'm attaching it here. To make it work, I replaced Vector2/3/4, Color/Color32 and Quaternion (I actually thought Quaternion didn't fall into the issue, but after additional tests apparently it did too) with custom struct implementations, which implicitly cast to Unity's correct format only when applying the final values. That way, the "guilty" cast which couldn't happen is now happening and everything works.

    Cheers!
     

    Attached Files:

    chloridrik likes this.
  21. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,675
    Hi,

    we have found another workaround, though I'm not sure whether that is a better solution than what you did yourself (it's a similar one). The idea is to wrap structs from UnityEngine in another struct:

    Code (csharp):
    1. struct Vector3Wrapper
    2. {
    3.     public Vector3 vector3;
    4.  
    5.     public Vector3Wrapper(Vector3 v3)
    6.     {
    7.         vector3 = v3;
    8.     }
    9. }
    That way, you'll be able to use it as a generic parameter, but you'll have to change your code to do "vector3.vector3.x" instead of "vector3.x".

    Basically, you cannot use structs from UnityEngine as generic parameters directly. As long as you bypass that, it will be a valid workaround.

    We'll be looking to fix this issue in the future, but it will definitely not be in a patch release because it involves refactoring a lot of our code.
     
    tyoc213 and Demigiant like this.
  22. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Hi,

    that is another interesting workaround, didn't think of that, thanks. I'm going to make some tests to see what might be the most efficient one and will report back.
     
  23. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Tests made. I was actually surprised, but apparently the Wrapper version is faster than the Surrogate one (the custom Vector3/etc implementations). Also, I made the tests many times, and I don't know how this is possible (and still believe my computer must've gone crazy), but it seems that the Wrapper version is even slightly faster than using Vector3 directly (I'm testing from a regular Win executable build).

    Tweening 64,000 transforms (with disabled renderers) in a loop
    Regular Vector3 version, average FPS: 29,5
    Vector3 Wrapper version, average FPS: 29,75
    Vector3 Surrogate version, average FPS: 28,4

    Also, the Vector3 Wrapper version is the one that maintains the most constant FPS. I can only say that this is very nice. Thanks @Tautvydas Zilys
     
  24. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,675
    That's pretty cool :). I can't explain how it's faster, but I can totally see how it can be at least the same performance: struct wrapper has identical layout in memory, and the accesses to vector3 that are inside should be perfectly inlined (i. e. there should not be any difference whatsoever between doing vector3.vector3.x and vector3.x). As for it being faster, it must be some kind of weird cache line thing - it may be that since the type is in the same assembly, its type info is actually closer in memory - however, that's just a totally wild speculation, but I have no better explanation.
     
    Demigiant likes this.
  25. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    As long as it's faster I'm ok even if you explain it with chicken voodoo :D
     
  26. MrEsquire

    MrEsquire

    Joined:
    Nov 5, 2013
    Posts:
    2,712
    Any news on this?
     
  27. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,675
    No news yet. It's a huge architectural thing to change, and it's unlikely it will ever be fixed in 4.6.x line (because by definition, big changes can't go into patch releases).

    However, the plugin author has a workaround - does it not work for you?
     
  28. MrEsquire

    MrEsquire

    Joined:
    Nov 5, 2013
    Posts:
    2,712
    Thanks for the feedback, good point - I keep my eyes open for future builds.
     
  29. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Hey @MrEsquire, in the meantime you can download the Hyper-Compatible version of DOTween, which uses the workaround that Tautvydas suggested (just overwrite the existing files, run the Setup as usual, and the code stays the same).
     
  30. tyoc213

    tyoc213

    Joined:
    Nov 14, 2011
    Posts:
    168
    @lzitmee I can argue why the workaround is faster than the "original" with the implementations of unity internal (you say they "because they kind of break some rules of the C# language" (I will like to know the specific observations).

    I think wrapping them inside normal structs, make the compiler able to infer more things at compile/runtime for do a little optimization and that is why you see the difference, in other words this workaround not only help pass the error caused by the internal way unity does things, but also give more hints to the compiler on how to make it fast.

    Im sure if you could reverse (engineer) some loops of the code and compare them, you will see more direct usage of the structs with the workaround than with their actual implementation.

    So I hope that unity technologies does solve this for make other people code a little more fast (they already know it will).
     
    Last edited: Sep 11, 2015
    MrEsquire likes this.
  31. NeatWolf

    NeatWolf

    Joined:
    Sep 27, 2013
    Posts:
    924
    Hi,

    has this been fixed in Unity 5.4.2f2?
     
  32. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Nope, as far as I know.
     
  33. Ben-BearFish

    Ben-BearFish

    Joined:
    Sep 6, 2011
    Posts:
    1,204
    @Izitmee Does the normal version of DoTween now work with UWP? Or should we still use the Hyper-compatible version?

    Also, would it be possible for you to add a crossfade extension to audio sources? So we could crossfade between two audio sources. I'm still surprised this isn't part of Unity's native implementation.
     
  34. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,675
    As far as I know, UWP is not affected by this issue.
     
  35. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    @Tautvydas-Zilys You mean it's fixed? That would be awesome :)

    @Ben-BearFish I have no way of testing it. If you could try it, to be on the safe side, and let me know it would be great :) About cross-fade, I do use DOTween to make cross-fades between audios (in my DeAudio library for example), but it's not something I can add directly into DOTween. I mean, it would go beyond it's scope, since it would mean dealing with multiple audio instances etc, so it's something I feel would be wrong to add to a tween engine :p
     
  36. Ben-BearFish

    Ben-BearFish

    Joined:
    Sep 6, 2011
    Posts:
    1,204
    @Izitmee Understood. I didn't realize you wrote additional libraries. I'll look at DeAudio. Thanks. Does DeAudio work with the Hyper-compatible version of DoTween?

    Also, after looking at the DeAudio API how does it know which audio to crossfade? I only see there is one parameter for an audioclip. Does it Crossfade the currently playing audioclip?

    Are there any OnComplete events for Playing a clip?
     
    Last edited: May 11, 2017
  37. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Everything works with the hyper-compatible version :)

    DeAudio also manages audioClips etc, so it knows everything that's currently playing. The cross-fade is just tweens fading out all playing clips, and another one fading in the new one.
     
  38. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,675
    Yes, on Microsoft's side. It was ultimately a bug in their runtime. However, they did not backport the fix to WP8.1.
     
    jhocking likes this.
  39. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Wohoooooo \o/
     
  40. Ben-BearFish

    Ben-BearFish

    Joined:
    Sep 6, 2011
    Posts:
    1,204
    @Izitmee I was hoping to play Clip1, then Crossfade to Clip2 before Clip1 is over, then Crossfade to Clip3 before Clip2 is over, then Crossfade back to Clip1 before Clip 3 is over.

    Is it possible to do something like this with DeAudio for a situation like I wrote? I can't seem to come up with a good solution for that yet.