Author Topic: NGUI 3.0.X and Win8/8.1  (Read 7159 times)

Goepfie

  • Guest
NGUI 3.0.X and Win8/8.1
« on: November 05, 2013, 10:37:14 AM »
Hello again,

I know its frustrating (by reading your function comments i think you agree), but the current Event Delegate rewrite does not compile with Windows 8/8.1 Apps. There are three issues with EventDelegate.cs

  • The problems is "System.Delegate.CreateDelegate" is not a Windows Store compatible function.
  • #NETFX_CORE is necessary instead of !UNITY_EDITOR && UNITY_METRO or the Mono-compiler will throw a false positive
  • If you remove #define REFLECTION_SUPPORT you still need to include System.Reflection to have Callback and MethodInfo classes available

I hotfixed my version by removing the reflection support preprocessor directive, keeping the Reflection include and using NETFX_CORE in EventDelegate.cs

Regards!

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile

MRCalderon3D

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 3
    • View Profile
Re: NGUI 3.0.X and Win8/8.1
« Reply #2 on: November 12, 2013, 09:19:17 AM »
Hello again,

I know its frustrating (by reading your function comments i think you agree), but the current Event Delegate rewrite does not compile with Windows 8/8.1 Apps. There are three issues with EventDelegate.cs

  • The problems is "System.Delegate.CreateDelegate" is not a Windows Store compatible function.
  • #NETFX_CORE is necessary instead of !UNITY_EDITOR && UNITY_METRO or the Mono-compiler will throw a false positive
  • If you remove #define REFLECTION_SUPPORT you still need to include System.Reflection to have Callback and MethodInfo classes available

I hotfixed my version by removing the reflection support preprocessor directive, keeping the Reflection include and using NETFX_CORE in EventDelegate.cs

Regards!

I have the same problem, Could you paste the code of EventDelegate?, please

The link that ArenMook pasted, is a different bug IMO.

Thanks

Goepfie

  • Guest
Re: NGUI 3.0.X and Win8/8.1
« Reply #3 on: November 12, 2013, 11:28:18 AM »
Hey,

yes i thought so too. Bug still exists with U4.3f4 and NGUI 3.0.5.
Seeing how reflection is currently modeled the only quick and dirty way to fix to fix the issue, is to disable reflection support for Win8/8.1 completely. This will definitely be slower than the planned implementation.

IF you want to use this, you will have to
change line 10 to

  1. #if UNITY_EDITOR || (!UNITY_FLASH && !NETFX_CORE)
*

Also comment out these parts, since you won't use reflection at all

  1. #if !UNITY_EDITOR && UNITY_WP8
  2. ...
  3. #elif !UNITY_EDITOR && UNITY_METRO
  4. ...
*

in the future here should be used NETFX_CORE instead of UNITY_METRO, because if UNITY_METRO is set, Unity will still check against Mono, which does not know about the new function set for reflection in the .net framework. With NETFX_CORE it can be made sure that the code compiles.

MRCalderon3D

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 3
    • View Profile
Re: NGUI 3.0.X and Win8/8.1
« Reply #4 on: November 12, 2013, 11:44:34 AM »
Thanks you very much Geopfie

I went crazy changin it before your last post.

This is my EventDelegate.cs script. It seems to work but I don't know what I changed exactly...

  1. //----------------------------------------------
  2. //            NGUI: Next-Gen UI kit
  3. // Copyright © 2011-2013 Tasharen Entertainment
  4. //----------------------------------------------
  5.  
  6. //#if UNITY_EDITOR || !UNITY_FLASH
  7. //#define REFLECTION_SUPPORT
  8. //#endif
  9.  
  10. //#if REFLECTION_SUPPORT
  11. using System.Reflection;
  12. //#endif
  13.  
  14. using System.Collections.Generic;
  15. using UnityEngine;
  16.  
  17. /// <summary>
  18. /// Delegate callback that Unity can serialize and set via Inspector.
  19. /// </summary>
  20.  
  21. [System.Serializable]
  22. public class EventDelegate
  23. {
  24.         [SerializeField] MonoBehaviour mTarget;
  25.         [SerializeField] string mMethodName;
  26.  
  27.         /// <summary>
  28.         /// Whether the event delegate will be removed after execution.
  29.         /// </summary>
  30.  
  31.         public bool oneShot = false;
  32.  
  33.         public delegate void Callback();
  34.         Callback mCachedCallback;
  35.         bool mRawDelegate = false;
  36.  
  37.         /// <summary>
  38.         /// Event delegate's target object.
  39.         /// </summary>
  40.  
  41.         public MonoBehaviour target { get { return mTarget; } set { mTarget = value; mCachedCallback = null; mRawDelegate = false; } }
  42.  
  43.         /// <summary>
  44.         /// Event delegate's method name.
  45.         /// </summary>
  46.  
  47.         public string methodName { get { return mMethodName; } set { mMethodName = value; mCachedCallback = null; mRawDelegate = false; } }
  48.  
  49.         /// <summary>
  50.         /// Whether this delegate's values have been set.
  51.         /// </summary>
  52.  
  53.         public bool isValid { get { return (mRawDelegate && mCachedCallback != null) || (mTarget != null && !string.IsNullOrEmpty(mMethodName)); } }
  54.  
  55.         /// <summary>
  56.         /// Whether the target script is actually enabled.
  57.         /// </summary>
  58.  
  59.         public bool isEnabled { get { return (mRawDelegate && mCachedCallback != null) || (mTarget != null && mTarget.enabled); } }
  60.  
  61.         public EventDelegate () { }
  62.         public EventDelegate (Callback call) { Set(call); }
  63.         public EventDelegate (MonoBehaviour target, string methodName) { Set(target, methodName); }
  64.  
  65.         /// <summary>
  66.         /// Windows 8 is retarded.
  67.         /// </summary>
  68.  
  69. #if !UNITY_EDITOR && UNITY_WP8
  70.         static string GetMethodName (Callback callback)
  71.         {
  72.                 System.Delegate d = callback as System.Delegate;
  73.                 return d.Method.Name;
  74.         }
  75.  
  76.         static bool IsValid (Callback callback)
  77.         {
  78.                 System.Delegate d = callback as System.Delegate;
  79.                 return d != null && d.Method != null;
  80.         }
  81. //#elif !UNITY_EDITOR && UNITY_METRO
  82. #elif NETFX_CORE
  83.         static string GetMethodName (Callback callback)
  84.         {
  85.                 System.Delegate d = callback as System.Delegate;
  86.                 return d.GetMethodInfo().Name;
  87.         }
  88.  
  89.         static bool IsValid (Callback callback)
  90.         {
  91.                 System.Delegate d = callback as System.Delegate;
  92.                 return d != null && d.GetMethodInfo() != null;
  93.         }
  94. //#elif REFLECTION_SUPPORT
  95. //    static string GetMethodName (Callback callback) { return callback.Method.Name; }
  96. //    static bool IsValid (Callback callback) { return callback != null && callback.Method != null; }
  97. #else
  98.         static bool IsValid (Callback callback) { return callback != null; }
  99. #endif
  100.  
  101.         /// <summary>
  102.         /// Equality operator.
  103.         /// </summary>
  104.  
  105.         public override bool Equals (object obj)
  106.         {
  107.                 if (obj == null)
  108.                 {
  109.                         return !isValid;
  110.                 }
  111.  
  112.                 if (obj is Callback)
  113.                 {
  114.                         Callback callback = obj as Callback;
  115. //#if REFLECTION_SUPPORT
  116. //            if (callback.Equals(mCachedCallback)) return true;
  117. //            return (mTarget == callback.Target && string.Equals(mMethodName, GetMethodName(callback)));
  118. //#elif UNITY_FLASH
  119. #if UNITY_FLASH
  120.                         return (callback == mCachedCallback);
  121. #else
  122.             return callback.Equals(mCachedCallback);
  123. #endif
  124.                 }
  125.                
  126.                 if (obj is EventDelegate)
  127.                 {
  128.                         EventDelegate del = obj as EventDelegate;
  129.                         return (mTarget == del.mTarget && string.Equals(mMethodName, del.mMethodName));
  130.                 }
  131.                 return false;
  132.         }
  133.  
  134.         static int s_Hash = "EventDelegate".GetHashCode();
  135.  
  136.         /// <summary>
  137.         /// Used in equality operators.
  138.         /// </summary>
  139.  
  140.         public override int GetHashCode () { return s_Hash; }
  141.  
  142.         /// <summary>
  143.         /// Convert the saved target and method name into an actual delegate.
  144.         /// </summary>
  145.  
  146.         Callback Get ()
  147.         {
  148. //#if REFLECTION_SUPPORT
  149. //        if (!mRawDelegate && (mCachedCallback == null || mCachedCallback.Target != mTarget || GetMethodName(mCachedCallback) != mMethodName))
  150. //        {
  151. //            if (mTarget != null && !string.IsNullOrEmpty(mMethodName))
  152. //            {
  153. //                mCachedCallback = (Callback)System.Delegate.CreateDelegate(typeof(Callback), mTarget, mMethodName);
  154. //            }
  155. //            else return null;
  156. //        }
  157. //#endif
  158.                 return mCachedCallback;
  159.         }
  160.  
  161.         /// <summary>
  162.         /// Set the delegate callback directly.
  163.         /// </summary>
  164.  
  165.         void Set (Callback call)
  166.         {
  167.                 if (call == null || !IsValid(call))
  168.                 {
  169.                         mTarget = null;
  170.                         mMethodName = null;
  171.                         mCachedCallback = null;
  172.                         mRawDelegate = false;
  173.                 }
  174.                 else
  175.                 {
  176. //#if REFLECTION_SUPPORT
  177. //            mTarget = call.Target as MonoBehaviour;
  178.  
  179. //            if (mTarget == null)
  180. //            {
  181. //                mRawDelegate = true;
  182. //                mCachedCallback = call;
  183. //                mMethodName = null;
  184. //            }
  185. //            else
  186. //            {
  187. //                mMethodName = GetMethodName(call);
  188. //                mRawDelegate = false;
  189. //            }
  190. //#else
  191.                         mRawDelegate = true;
  192.                         mCachedCallback = call;
  193.                         mMethodName = null;
  194.                         mTarget = null;
  195. //#endif
  196.                 }
  197.         }
  198.  
  199.         /// <summary>
  200.         /// Set the delegate callback using the target and method names.
  201.         /// </summary>
  202.  
  203.         public void Set (MonoBehaviour target, string methodName)
  204.         {
  205.                 this.mTarget = target;
  206.                 this.mMethodName = methodName;
  207.                 mCachedCallback = null;
  208.                 mRawDelegate = false;
  209.         }
  210.  
  211.         /// <summary>
  212.         /// Execute the delegate, if possible.
  213.         /// This will only be used when the application is playing in order to prevent unintentional state changes.
  214.         /// </summary>
  215.  
  216.         public bool Execute ()
  217.         {
  218. #if UNITY_EDITOR
  219.                 if (Application.isPlaying)
  220. #endif
  221.                 {
  222.                         Callback call = Get();
  223.  
  224.                         if (call != null)
  225.                         {
  226.                                 call();
  227.                                 return true;
  228.                         }
  229. //#if !REFLECTION_SUPPORT
  230. //            if (isValid)
  231. //            {
  232. //                mTarget.SendMessage(mMethodName, SendMessageOptions.DontRequireReceiver);
  233. //                return true;
  234. //            }
  235. //#endif
  236.                 }
  237.                 return false;
  238.         }
  239.  
  240.         /// <summary>
  241.         /// Clear the event delegate.
  242.         /// </summary>
  243.  
  244.         public void Clear ()
  245.         {
  246.                 mTarget = null;
  247.                 mMethodName = null;
  248.                 mRawDelegate = false;
  249.                 mCachedCallback = null;
  250.         }
  251.  
  252.         /// <summary>
  253.         /// Convert the delegate to its string representation.
  254.         /// </summary>
  255.  
  256.         public override string ToString ()
  257.         {
  258.                 if (mTarget != null)
  259.                 {
  260.                         string typeName = mTarget.GetType().ToString();
  261.                         int period = typeName.LastIndexOf('.');
  262.                         if (period > 0) typeName = typeName.Substring(period + 1);
  263.  
  264.                         if (!string.IsNullOrEmpty(methodName)) return typeName + "." + methodName;
  265.                         else return typeName + ".[delegate]";
  266.                 }
  267.                 return mRawDelegate ? "[delegate]" : null;
  268.         }
  269.  
  270.         /// <summary>
  271.         /// Execute an entire list of delegates.
  272.         /// </summary>
  273.  
  274.         static public void Execute (List<EventDelegate> list)
  275.         {
  276.                 if (list != null)
  277.                 {
  278.                         for (int i = 0; i < list.Count; )
  279.                         {
  280.                                 EventDelegate del = list[i];
  281.  
  282.                                 if (del != null)
  283.                                 {
  284.                                         del.Execute();
  285.  
  286.                                         if (del.oneShot)
  287.                                         {
  288.                                                 list.RemoveAt(i);
  289.                                                 continue;
  290.                                         }
  291.                                 }
  292.                                 ++i;
  293.                         }
  294.                 }
  295.         }
  296.  
  297.         /// <summary>
  298.         /// Convenience function to check if the specified list of delegates can be executed.
  299.         /// </summary>
  300.  
  301.         static public bool IsValid (List<EventDelegate> list)
  302.         {
  303.                 if (list != null)
  304.                 {
  305.                         for (int i = 0, imax = list.Count; i < imax; ++i)
  306.                         {
  307.                                 EventDelegate del = list[i];
  308.                                 if (del != null && del.isValid)
  309.                                         return true;
  310.                         }
  311.                 }
  312.                 return false;
  313.         }
  314.  
  315.         /// <summary>
  316.         /// Assign a new event delegate.
  317.         /// </summary>
  318.  
  319.         static public void Set (List<EventDelegate> list, Callback callback)
  320.         {
  321.                 if (list != null)
  322.                 {
  323.                         list.Clear();
  324.                         list.Add(new EventDelegate(callback));
  325.                 }
  326.         }
  327.  
  328.         /// <summary>
  329.         /// Append a new event delegate to the list.
  330.         /// </summary>
  331.  
  332.         static public void Add (List<EventDelegate> list, Callback callback) { Add(list, callback, false); }
  333.  
  334.         /// <summary>
  335.         /// Append a new event delegate to the list.
  336.         /// </summary>
  337.  
  338.         static public void Add (List<EventDelegate> list, Callback callback, bool oneShot)
  339.         {
  340.                 if (list != null)
  341.                 {
  342.                         for (int i = 0, imax = list.Count; i < imax; ++i)
  343.                         {
  344.                                 EventDelegate del = list[i];
  345.                                 if (del != null && del.Equals(callback))
  346.                                         return;
  347.                         }
  348.  
  349.                         EventDelegate ed = new EventDelegate(callback);
  350.                         ed.oneShot = oneShot;
  351.                         list.Add(ed);
  352.                 }
  353.                 else
  354.                 {
  355.                         Debug.LogWarning("Attempting to add a callback to a list that's null");
  356.                 }
  357.         }
  358.  
  359.         /// <summary>
  360.         /// Append a new event delegate to the list.
  361.         /// </summary>
  362.  
  363.         static public void Add (List<EventDelegate> list, EventDelegate ev) { Add(list, ev, false); }
  364.  
  365.         /// <summary>
  366.         /// Append a new event delegate to the list.
  367.         /// </summary>
  368.  
  369.         static public void Add (List<EventDelegate> list, EventDelegate ev, bool oneShot)
  370.         {
  371.                 if (list != null)
  372.                 {
  373.                         for (int i = 0, imax = list.Count; i < imax; ++i)
  374.                         {
  375.                                 EventDelegate del = list[i];
  376.                                 if (del != null && del.Equals(ev))
  377.                                         return;
  378.                         }
  379.                        
  380.                         EventDelegate ed = new EventDelegate(ev.target, ev.methodName);
  381.                         ed.oneShot = oneShot;
  382.                         list.Add(ed);
  383.                 }
  384.                 else
  385.                 {
  386.                         Debug.LogWarning("Attempting to add a callback to a list that's null");
  387.                 }
  388.         }
  389.  
  390.         /// <summary>
  391.         /// Remove an existing event delegate from the list.
  392.         /// </summary>
  393.  
  394.         static public bool Remove (List<EventDelegate> list, Callback callback)
  395.         {
  396.                 if (list != null)
  397.                 {
  398.                         for (int i = 0, imax = list.Count; i < imax; ++i)
  399.                         {
  400.                                 EventDelegate del = list[i];
  401.                                
  402.                                 if (del != null && del.Equals(callback))
  403.                                 {
  404.                                         list.RemoveAt(i);
  405.                                         return true;
  406.                                 }
  407.                         }
  408.                 }
  409.                 return false;
  410.         }
  411. }

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: NGUI 3.0.X and Win8/8.1
« Reply #5 on: November 12, 2013, 02:46:48 PM »
@Goepfie: For Win8 stuff (which is quite ridiculous with it mono/net being different between different versions / Win8 devices), I've always relied on user contributions. I don't have Win8 myself, nor any WP8 devices, and I can't properly test something I don't have, so when a user posts "here's the code, it works for me", I integrate it into the repository. Then the next user comes along and says "it doesn't work for me!" I can only sigh. This happened around 10 times now.

All I need is for at least one person to figure out which functionality doesn't work on which Win8 platforms and tweak the #ifdefs in the file to match without breaking something else.

Goepfie

  • Guest
Re: NGUI 3.0.X and Win8/8.1
« Reply #6 on: November 13, 2013, 06:03:26 AM »
@Goepfie: For Win8 stuff (which is quite ridiculous with it mono/net being different between different versions / Win8 devices), I've always relied on user contributions. I don't have Win8 myself, nor any WP8 devices, and I can't properly test something I don't have, so when a user posts "here's the code, it works for me", I integrate it into the repository. Then the next user comes along and says "it doesn't work for me!" I can only sigh. This happened around 10 times now.

All I need is for at least one person to figure out which functionality doesn't work on which Win8 platforms and tweak the #ifdefs in the file to match without breaking something else.

@ArenMook: I certainly understand, I am just trying to help out a bit. I am sorry if you interpreted it as an insult. If there is a more constructive way to submit code/bugs just let me know.

In detail the problem is .Net for Store has no "CreateDelegate" function. Here is the overview of the Delegate class and their implementations: http://msdn.microsoft.com/en-us/library/System.Delegate%28v=vs.110%29.aspx The ugly green bag-like-icon represents the .Net Framework for Windows Store Apps. I don't know myself if there is a replacement function implemented somewhere else.

The preprocessors are semantically correct. The reason it did not compile I had to find out in unity metro beta discussion board also. There is this slight difference between UNITY_METRO (Is interpreted by the Unity Editor and compiled against Net 3.5 like anything else) and NETFX_CORE (Is interpreted later while building when .NET is used).

Therefore Mono/3.5 does not have GetMethodInfo() and it's alike implemented and will throw an exception, even though it is Metro compatible Code.

The first solution (adjust preprocessors, keep REFLECTION_SUPPORT, but exempt the CreateDelegate Line and use SendMessage) I posted just makes sure it compiles, but did produce some unwanted behavior later.

The second more stable solution would be to treat Win8/8.1 Metro in this case like the Flash config and give up on reflection. This is what I tried to advice MRCalderon3D to use as a hotfix.
« Last Edit: November 13, 2013, 07:48:38 AM by Goepfie »

MRCalderon3D

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 3
    • View Profile
Re: NGUI 3.0.X and Win8/8.1
« Reply #7 on: November 13, 2013, 07:24:02 AM »
@Goepfie:  I don't have Win8 myself, nor any WP8 devices, and I can't properly test something I don't have,

@ArenMook: I will give you a windows 8 pro license via MP

@Goepfie: thanks a lot for your help.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: NGUI 3.0.X and Win8/8.1
« Reply #8 on: November 13, 2013, 03:54:46 PM »
@Goepfie: I didn't interpreted it as an insult. My reaction was along the lines of "ugh... again?" kinda thing. :) I've added the changes to the pro repository btw, hopefully the last time I have to do that. And it's really disappointing that proper reflection is not supported.