Search code examples
c#iosunity-game-enginemonochess

IL2CPP Compiler Runtime Errors for Unity3D iOS 64-bit


I have a Unity3D Mobile Chess app I am porting from 32-bit to 64-bit with Unity 3D 4.6.5f1. It's using OpenGLS2.0, .NET 2.0 libraries, and Universal binaries are being generated.

I am getting a runtime error which in the debugger says the following:

 NullReferenceException: A null value was found where an object instance was required.
  at <PrivateImplementationDetails>..ctor () [0x00000] in <filename unknown>:0 
  at ValilScriptObject.Update () [0x00000] in <filename unknown>:0 
  at System.Collections.Generic.Dictionary`2+ShimEnumerator[Boo.Lang.Runtime.DynamicDispatching.DispatcherKey,Boo.Lang.Runtime.DynamicDispatching.Dispatcher].get_Current () [0x00000] in <filename unknown>:0 
System.Collections.Generic.ShimEnumerator:get_Current()

(Filename: currently not available on il2cpp Line: 4294967295)

It compiles fine using Mono 2.0 but as soon as I port it to IL2CPP for 64-bit Universal binary it throws up the error.

The function it's referencing Update() appears to be fine.

void Update () {
    if(Request.Length>0)
    {
        string answ="";
        Answer=Engine1.GetNextMove(Request, null, Deep);
        Request="";
        if(Answer.Length>0) answ=Answer.Substring(0,2)+"-"+Answer.Substring(2,2);
        if(Answer.Length>4) answ+="="+(Answer.Substring(4,1)).ToUpper();
        ((TextMesh)GetComponent(typeof(TextMesh))).text=answ;

        //Application.ExternalCall("JSAnswer", answ);

        (GameObject.Find("Script2")).SendMessage("EngineAnswer",answ);
    }

}

It's simply using Valil Chess Engine (written in C#) to get appropriate answers (next move). It works fine in Mono 2.0 but is failing with IL2CPP. Any ideas?


Solution

  • I finally found an answer. When ChessEngine is initialized there is a ChessEngine.OpeningBook class that's initialized. I simply took out the class altogether, and it worked like a charm. The class looks like:

    using System;
    using System.IO;
    using System.Collections.Generic;
    using System.Reflection;
    //using Valil.Chess.Engine.Properties;
    
    namespace Valil.Chess.Engine
    {
        public sealed partial class ChessEngine
        {
            // hashtable with the board hash as the key and a list of moves for this board configuration as the value
            public static Dictionary<int, List<short>> book;
    
            // helps choose a move when the list contains more than one
            private Random random;
    
            /// <summary>
            /// Initializes the opening book.
            /// </summary>
            private void InitializeOpeningBook()
            {
                // initialize the random generator
                random = new Random(unchecked((int)DateTime.Now.Ticks));
    
                int Settings_Default_OpeningBookSize = 2755;
                //int Settings_Default_OpeningBookByteSize = 16530;
    
                //Assembly assembly = Assembly.GetExecutingAssembly();
                //String[] ss = assembly.GetManifestResourceNames();
    
                // THERE IS NO FILE & MANIFEST ASSEMBLY IN UNITY3D FOR FREE...
                // SO, CLASS ObookMem IS AS OPENING BOOK!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                Stream readstream = Assembly.GetExecutingAssembly().GetManifestResourceStream("valil_silverlightchess.book.bin");
    
                // the "book.bin" file is a binary file with this pattern: int,short,int,short etc.
                // a 4-byte int represent a board hash, the following 2-byte short is a move (the first byte represents the starting square, the second one the ending square)
    
                // read "book.bin" and put the values in the hashtable
                try
                {
    
                    using (BinaryReader br = new BinaryReader( readstream ))
    
    //                using (BinaryReader br = new BinaryReader(new BufferedStream(Assembly.GetExecutingAssembly().GetManifestResourceStream("Valil.Chess.Engine.book.bin"), Settings.Default.OpeningBookByteSize)))
    //                using (BinaryReader br = new BinaryReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("book.bin")))
    
    
                    {
                        book = new Dictionary<int, List<short>>(Settings_Default_OpeningBookSize);
    
                        for (int i = 0; i < Settings_Default_OpeningBookSize; i++)
                        {
                            int hash = br.ReadInt32();
                            short move = br.ReadInt16();
    
                            // if the hashtable already contains this hash, add the move to the list
                            // otherwise create a new list and add the pair to the hashtable
                            if (book.ContainsKey(hash))
                            {
                                book[hash].Add(move);
                            }
                            else
                            {
                                List<short> list = new List<short>(1);
                                list.Add(move);
                                book.Add(hash, list);
                            }
                        }
                    }
                }
                catch
                {
                }
            }
        }
    }
    

    I think that the IL2CPP compiler doesn't like System.Reflection and my Dictionary and List types.