private static void OnUnhandledException(object _, UnhandledExceptionEventArgs e)
        {
            var exception = e.ExceptionObject as Exception;

            Alt.LogError(e.IsTerminating ? "FATAL EXCEPTION:" : "UNHANDLED EXCEPTION:");
            Alt.LogError(exception?.ToString());

            if (!e.IsTerminating)
            {
                return;
            }

            if (_core is null)
            {
                Alt.LogError("Cannot show error dialog because core is not initialized yet");
                return;
            }

            if (_resource is null)
            {
                Alt.LogError("Cannot show error dialog because resources is not initialized yet");
                return;
            }

            var options = _resource.OnUnhandledException(e);

            if (options == null)
            {
                Alt.LogInfo("Unhandled exception handler was null, skipping error dialog");
                return;
            }

            try
            {
                var dialog = new ErrorDialog(_core, options, exception);
                dialog.Show();
            }
            catch (Exception executionException)
            {
                Alt.LogError("Failed to show error dialog: " + executionException);
            }
        }
        public static void MainWithAssembly(Assembly resourceAssembly, IntPtr resourcePointer, IntPtr corePointer, string dllName)
        {
            DllName = dllName;

            var library = new Library(DllName, true);
            var logger  = new Logger(library, corePointer);

            Alt.Logger = logger;
            Alt.Log("Library initialized");

            unsafe
            {
                if (library.Shared.Core_GetEventEnumSize() != (byte)EventType.SIZE)
                {
                    throw new Exception("Event type enum size doesn't match. Please, update the nuget");
                }
            }

            AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;

            _resourcePointer = resourcePointer;
            _corePointer     = corePointer;

            var type     = typeof(IResource);
            var resource = resourceAssembly.GetTypes().FirstOrDefault(t => t.IsClass && !t.IsAbstract && type.IsAssignableFrom(t));

            if (resource is null)
            {
                throw new Exception("Cannot find resource");
                return;
            }

            _resource = (IResource)Activator.CreateInstance(resource) !;
            Alt.Log("Resource created");

            Alt.Logger = _resource.GetLogger(library, corePointer);

            var playerPool = new PlayerPool(_resource.GetPlayerFactory());

            Alt.Log("Player pool created");

            var vehiclePool = new VehiclePool(_resource.GetVehicleFactory());

            Alt.Log("Vehicle pool created");

            var blipPool = new BlipPool(_resource.GetBlipFactory());

            Alt.Log("Blip pool created");

            var checkpointPool = new CheckpointPool(_resource.GetCheckpointFactory());

            Alt.Log("Checkpoint pool created");

            var audioPool = new AudioPool(_resource.GetAudioFactory());

            Alt.Log("Audio pool created");

            var httpClientPool = new HttpClientPool(_resource.GetHttpClientFactory());

            Alt.Log("Http client pool created");

            var webSocketClientPool = new WebSocketClientPool(_resource.GetWebSocketClientFactory());

            Alt.Log("WebSocket client pool created");

            var webViewPool = new WebViewPool(_resource.GetWebViewFactory());

            Alt.Log("Webview pool created");

            var rmlDocumentPool = new RmlDocumentPool(new RmlDocumentFactory());
            var rmlElementPool  = new RmlElementPool(new RmlElementFactory());

            Alt.Log("Rml pools created");

            var nativeResourcePool = new NativeResourcePool(_resource.GetResourceFactory());

            Alt.Log("Native resource pool created");

            var baseBaseObjectPool = new BaseBaseObjectPool(playerPool, vehiclePool, blipPool, checkpointPool, audioPool, httpClientPool, webSocketClientPool, webViewPool, rmlElementPool, rmlDocumentPool);
            var baseEntityPool     = new BaseEntityPool(playerPool, vehiclePool);
            var timerPool          = new TimerPool();

            var natives = _resource.GetNatives(DllName);

            var client = new Core(
                library,
                corePointer,
                resourcePointer,
                playerPool,
                vehiclePool,
                blipPool,
                checkpointPool,
                audioPool,
                httpClientPool,
                webSocketClientPool,
                webViewPool,
                rmlDocumentPool,
                rmlElementPool,
                baseBaseObjectPool,
                baseEntityPool,
                nativeResourcePool,
                timerPool,
                logger,
                natives
                );

            _core          = client;
            Alt.CoreImpl   = client;
            AltShared.Core = client;
            Alt.Log("Core initialized");

            _core.GetPlayers();
            _core.GetVehicles();
            _core.GetBlips();

            playerPool.InitLocalPlayer(_core);

            _core.Resource.CSharpResourceImpl.SetDelegates();
            Alt.Log("Delegates set");

            _resource.OnStart();
            Alt.Log("Startup finished");
        }