Search Unity

(SOLVED) odd bug with exotic IComparer function...

Discussion in 'Windows' started by FuzzyQuills, Dec 16, 2015.

  1. FuzzyQuills

    FuzzyQuills

    Joined:
    Jun 8, 2013
    Posts:
    2,871
    Hi guys, thought I would ask if any of you know of this issue:

    Essentially, I am making a racing game, and my ranking system uses a generic list with all the players in it. On other platforms (read: this includes Windows Standalone!) this works correctly.

    However, upon testing a WSA build (Universal 10), this build of my game has the ranking jumping all over the place! Basically, if I sit idle on the track, regardless if I am in first or at the very back, the ranking constantly jumps positions rather than actually stating the correct position. This only occurs on WSA, aka. if I make a build for android and run that, ranking shows up properly.

    So I ask; is this a known windows-specific bug with generic lists, a bug in List<>.indexOf, or am I doing something completely screwed up?

    Code for reference:
    Code (csharp):
    1.  
    2. //In my update function, I do this:
    3. racers.Sort(Compare);
    4. //then I do this to get the racer position:
    5. racers.IndexOf(playerData.GetComponent<RacerInfo>())+1;
    6. //the +1 is so being in 1st doesn't appear as 0
    7.  
    8. //the actual sorting code is here. (this could be the issue, this code exists outside of update)
    9. public int Compare(System.Object x, System.Object y) {
    10.         RacerInfo c1 = (RacerInfo)x;
    11.         RacerInfo c2 = (RacerInfo)y;
    12.  
    13.         if (c1.currLap > c2.currLap) return c2.currLap.CompareTo(c1.currLap);
    14.         else if (c1.currPnt > c2.currPnt) return c2.currPnt.CompareTo(c1.currPnt);
    15.         else return c1.dist2Next.CompareTo(c2.dist2Next);
    16. }
    17.  
    I apologize for some formatting issues, this was due to a bug in Microsoft edge, meaning I had to copy/paste a line of code at a time... :D

    I can also post a video clip of the bug for those wanting video footage
     
  2. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,676
    Hard to tell. Use VS debugger to check which step goes wrong - it should be fairly easy to figure it out.
     
  3. FuzzyQuills

    FuzzyQuills

    Joined:
    Jun 8, 2013
    Posts:
    2,871
    How would I go about doing that? :D I do see it fire up when I build with the green arrow, but where would I look? (I would assume in the Assembly.CSharp.dll)

    EDIT: Huh, it won't run; it tells me "unable to debug .NET compilation code: catastrophic failure" any idea?

    EDIT2: Oh wait, oops... I might have to turn on dev build first. :D
     
  4. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,732
    Drag and Drop youar script file to exported Visual Studio solution and you'll be able to debug script.
     
  5. FuzzyQuills

    FuzzyQuills

    Joined:
    Jun 8, 2013
    Posts:
    2,871
    Oh wow, I will have to try that, thank you. :)

    Ok, I dragged and dropped, do I just start the game? Sorry for asking too many questions, I haven't used VS much.
     
  6. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,676
    Yup, place a breakpoint inside the script and run the game.
     
  7. FuzzyQuills

    FuzzyQuills

    Joined:
    Jun 8, 2013
    Posts:
    2,871
    Ok, I tried this, and it didn't break at the point I specified. Do I need VS tools for this?
     
  8. FuzzyQuills

    FuzzyQuills

    Joined:
    Jun 8, 2013
    Posts:
    2,871
    Ok, I think I have found the problem, it appears that IComparer is behaving differently in WSA. Any idea of this?

    I need this fixed as, I will admit, the game affected by this bug is my Unity Dev Contest 2016 entry... :(
     
  9. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,676
    Can you define "is behaving differently"?
     
  10. FuzzyQuills

    FuzzyQuills

    Joined:
    Jun 8, 2013
    Posts:
    2,871
    I will... :D
    essentially, in every other platform I have tested (the editor included) the code (my IComparer) works properly.

    However, THE EXACT SAME CODE behaves a completely different way on the Windows Store Platform! And I know it's the IComparer; I was actually able to reproduce the same odd behavior that only normally occurs on WSA by changing my code slightly. (the rank jumps around rather than actually sampling the positions properly) It's like using WSA as the build platform optimizes something out!
     
  11. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,676
    Well, WSA is using .NET runtime, rather than Mono. What did you change so it makes behave the same?
     
  12. FuzzyQuills

    FuzzyQuills

    Joined:
    Jun 8, 2013
    Posts:
    2,871
    Here:

    Code that works properly everywhere except WSA
    Code (csharp):
    1.  
    2. public int Compare(System.Object x, System.Object y) {
    3.         RacerInfo c1 = (RacerInfo)x;
    4.         RacerInfo c2 = (RacerInfo)y;
    5.  
    6.         if (c1.currLap > c2.currLap) return c2.currLap.CompareTo(c1.currLap);
    7.         else if (c1.currPnt > c2.currPnt) return c2.currPnt.CompareTo(c1.currPnt);
    8.         else return c1.dist2Next.CompareTo(c2.dist2Next);
    9. }
    10.  
    This code specifically reproduces the WSA bug everywhere else... :D I was able to do several other pieces that do it wrong as well.
    Code (csharp):
    1.  
    2. public int Compare(System.Object x, System.Object y) {
    3.         RacerInfo c1 = (RacerInfo)x;
    4.         RacerInfo c2 = (RacerInfo)y;
    5.  
    6.         if (c1.currLap > c2.currLap) return 1;
    7.         else if (c1.currPnt > c2.currPnt) return 1;
    8.         else if (c1.dist2Next < c2.dist2Next) return 1;
    9.         else return -1;
    10. }
    11.  
    In fact, this doesn't only affect lists; it affects anything using IComparer I found (I switched to a static array to see if that would fix it, but to no avail... :()

    EDIT: Side-note; the player's car starts in 16th. In normal gameplay, it works as intended. in WSA however, it seems to almost always jump to "9" before going completely nuts!
     
  13. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,676
    Are those floats? Either way, you comparer is weird. I'm not sure what it's suppose to achieve: I'm surprised it worked in the first place. Usually the contract for IComparer is that
    Code (csharp):
    1. Compare(x, y) == -Compare(y, x)
    But it definitely is not in your case.

    Try this instead:

    Code (csharp):
    1. public int Compare(System.Object x, System.Object y)
    2. {
    3.     RacerInfo c1 = (RacerInfo)x;
    4.     RacerInfo c2 = (RacerInfo)y;
    5.  
    6.     if (c1.currLap != c2.currLap)
    7.         return c1.currLap > c2.currLap ? -1 : 1;
    8.  
    9.     if (c1.currPnt != c2.currPnt)
    10.         return c1.currPnt > c2.currPnt ? -1 : 1;
    11.  
    12.     return c1.dist2Next > c2.dist2Next ? 1 : -1;
    13. }
     
  14. FuzzyQuills

    FuzzyQuills

    Joined:
    Jun 8, 2013
    Posts:
    2,871
    One of them was (I changed it to an integer to avoid floating point precision errors)

    Will try later. Have to go now. :) Thank you for the help. :)
     
  15. FuzzyQuills

    FuzzyQuills

    Joined:
    Jun 8, 2013
    Posts:
    2,871
    Hi. :) I am back to say that you sir are an absolute genius!

    I did have to tweak your IComparer function a little bit for it to work for ranking, as it was potentially returning the distance difference as well as the other two. By using the else statements instead, it made sure that if the other numbers are the same, return the distance for sorting. :) that way, at least one thing is returned.
    Code (CSharp):
    1.  
    2. public int Compare(RacerInfo x, RacerInfo y)
    3. {
    4.         if (x.currLap != y.currLap)
    5.                 return x.currLap < y.currLap ? 1 : -1;
    6.         else if (x.currPnt != y.currPnt)
    7.                 return x.currPnt < y.currPnt ? 1 : -1;
    8.         else
    9.                 return x.dist2Next < y.dist2Next ? -1 : 1;
    10. }
    11.  
    (For those who want to use this code, substitute RacerInfo with either System.Object or your own car-tracking class!)

    Now it works on all platforms, including WSA! :) And it works perfectly. :) Thank you for your help!