示例#1
0
        /// <summary>
        /// Aborts execution of this script.
        /// </summary>
        public void Abort()
        {
            IsRunning = false;

            waitEvent.Release();

            try
            {
                Aborted?.Invoke(this, EventArgs.Empty);
            }
            catch (Exception ex)
            {
                ScriptDomain.HandleUnhandledException(this, new UnhandledExceptionEventArgs(ex, true));
            }

            if (thread != null)
            {
                thread.Abort(); thread = null;

                Log.Message(Log.Level.Info, "Aborted script ", Name, ".");
            }

            // Unregister any console commands attached to this script
            var console = AppDomain.CurrentDomain.GetData("Console") as Console;

            console?.UnregisterCommands(ScriptInstance.GetType());
        }
示例#2
0
        /// <summary>
        /// Initializes the script domain inside its application domain.
        /// </summary>
        /// <param name="apiBasePath">The path to the root directory containing the scripting API assemblies.</param>
        private ScriptDomain(string apiBasePath)
        {
            // Each application domain has its own copy of this static variable, so only need to set it once
            CurrentDomain = this;

            // Attach resolve handler to new domain
            AppDomain.AssemblyResolve    += HandleResolve;
            AppDomain.UnhandledException += HandleUnhandledException;

            // Load API assemblies into this script domain
            foreach (string apiPath in Directory.EnumerateFiles(apiBasePath, "ScriptHookVDotNet*.dll", SearchOption.TopDirectoryOnly))
            {
                Log.Message(Log.Level.Debug, "Loading API from ", apiPath, " ...");

                try
                {
                    var assembly = Assembly.LoadFrom(apiPath);
                    scriptApis.Add(assembly);

                    // set the default script api to use.
                    if (assembly.GetName().Version.Major == 2)
                    {
                        Log.Message(Log.Level.Info, "Found default script api: ", assembly.GetName().FullName);
                        defaultScriptApi = assembly;
                    }
                }
                catch (Exception ex)
                {
                    Log.Message(Log.Level.Error, "Unable to load ", Path.GetFileName(apiPath), ": ", ex.ToString());
                }
            }
        }
示例#3
0
        /// <summary>
        /// The main execution logic of all scripts.
        /// </summary>
        void MainLoop()
        {
            IsRunning = true;

            // Wait for script domain to continue this script
            continueEvent.Wait();

            while (IsRunning)
            {
                // Process keyboard events
                while (keyboardEvents.TryDequeue(out Tuple <bool, KeyEventArgs> ev))
                {
                    try
                    {
                        if (!ev.Item1)
                        {
                            KeyUp?.Invoke(this, ev.Item2);
                        }
                        else
                        {
                            KeyDown?.Invoke(this, ev.Item2);
                        }
                    }
                    catch (ThreadAbortException)
                    {
                        // Stop main loop immediately on a thread abort exception
                        return;
                    }
                    catch (Exception ex)
                    {
                        ScriptDomain.HandleUnhandledException(this, new UnhandledExceptionEventArgs(ex, false));
                        break;                         // Break out of key event loop, but continue to run script
                    }
                }

                try
                {
                    Tick?.Invoke(this, EventArgs.Empty);
                }
                catch (ThreadAbortException)
                {
                    // Stop main loop immediately on a thread abort exception
                    return;
                }
                catch (Exception ex)
                {
                    ScriptDomain.HandleUnhandledException(this, new UnhandledExceptionEventArgs(ex, true));

                    // An exception during tick is fatal, so abort the script and stop main loop
                    Abort(); return;
                }

                // Yield execution to next tick
                Wait(Interval);
            }
        }
        /// <summary>
        /// Unloads scripts and destroys an existing script domain.
        /// </summary>
        /// <param name="domain">The script domain to unload.</param>
        public static void Unload(ScriptDomain domain)
        {
            Log.Message(Log.Level.Info, "Unloading script domain ...");

            domain.Abort();
            domain.Dispose();

            try
            {
                AppDomain.Unload(domain.AppDomain);
            }
            catch (Exception ex)
            {
                Log.Message(Log.Level.Error, "Failed to unload script domain: ", ex.ToString());
            }
        }
示例#5
0
        /// <summary>
        /// Creates a new script domain.
        /// </summary>
        /// <param name="basePath">The path to the application root directory.</param>
        /// <param name="scriptPath">The path to the directory containing scripts.</param>
        /// <returns>The script domain or <c>null</c> in case of failure.</returns>
        public static ScriptDomain Load(string basePath, string scriptPath)
        {
            // Make absolute path to scrips location
            if (!Path.IsPathRooted(scriptPath))
            {
                scriptPath = Path.Combine(Path.GetDirectoryName(basePath), scriptPath);
            }
            scriptPath = Path.GetFullPath(scriptPath);

            // Create application and script domain for all the scripts to reside in
            var name  = "ScriptDomain_" + (scriptPath.GetHashCode() ^ Environment.TickCount).ToString("X");
            var setup = new AppDomainSetup();

            setup.ShadowCopyFiles       = "true";       // Copy assemblies into memory rather than locking the file, so they can be updated while the domain is still loaded
            setup.ShadowCopyDirectories = scriptPath;   // Only shadow copy files in the scripts directory
            setup.ApplicationBase       = scriptPath;

            var appdomain = AppDomain.CreateDomain(name, null, setup, new System.Security.PermissionSet(System.Security.Permissions.PermissionState.Unrestricted));

            appdomain.InitializeLifetimeService();             // Give the application domain an infinite lifetime

            // Need to attach the resolve handler to the current domain too, so that the .NET framework finds this assembly in the ASI file
            AppDomain.CurrentDomain.AssemblyResolve += HandleResolve;

            ScriptDomain scriptdomain = null;

            try
            {
                var loaded = appdomain.CreateInstanceFromAndUnwrap(typeof(ScriptDomain).Assembly.Location, typeof(ScriptDomain).FullName, false, BindingFlags.NonPublic | BindingFlags.Instance, null, new object[] { basePath }, null, null);
                Log.Message(Log.Level.Info, "Loaded: ", loaded.GetType().ToString());
                scriptdomain = (ScriptDomain)loaded;
            }
            catch (Exception ex)
            {
                Log.Message(Log.Level.Error, "Failed to create script domain: ", ex.ToString(), ex.StackTrace);
                AppDomain.Unload(appdomain);
            }

            // Remove resolve handler again
            AppDomain.CurrentDomain.AssemblyResolve -= HandleResolve;
            return(scriptdomain);
        }
示例#6
0
        /// <summary>
        /// Aborts execution of this script.
        /// </summary>
        public void Abort()
        {
            IsRunning = false;

            try
            {
                Aborted?.Invoke(this, EventArgs.Empty);
            }
            catch (Exception ex)
            {
                ScriptDomain.HandleUnhandledException(this, new UnhandledExceptionEventArgs(ex, true));
            }

            waitEvent.Release();

            if (thread != null)
            {
                Log.Message(Log.Level.Warning, "Aborted script ", Name, ".");

                thread.Abort(); thread = null;
            }
        }