Exemple #1
0
        /// <summary>
        ///   Loads inbound HCE executable with the inbound configuration.
        /// </summary>
        /// <param name="executable">
        ///   Object representing a legal HCE executable.
        /// </param>
        /// <param name="configuration">
        ///   Object representing the kernel configuration.
        /// </param>
        public static void Invoke(Executable executable, Configuration configuration)
        {
            /* Clear log file */
            {
                if (Exists(Paths.Exception) && new FileInfo(Paths.Exception).Length > 1048576) // If larger than 1 MiB, ...
                {
                    System.IO.File.WriteAllText(Paths.Exception, "");                          // ...clear log.
                }
            }

            /* Switch to legacy kernel modes */
            {
                if (!Exists(Legacy))
                {
                    configuration.Mode = Configuration.ConfigurationMode.SPV33;
                }
            }

            Init(); /* initc.txt declarations */
            Blam(); /* blam.sav enhancements  */
            Open(); /* opensauce declarations */
            Exec(); /* haloce.exe invocation  */

            Core("CORE.MAIN: Successfully updated the initiation, profile and OS files, and invoked the HCE executable.");

            /**
             * We declare the contents of the initiation file in this method before dealing with the profile enhancements and
             * the executable invocation. It's the most important task, so we have to deal with it first.
             *
             * The values declared by the HXE kernel for the initiation file are categorised into the following sections:
             *
             * -   RESUME: Campaign resuming support for the SPV3 mod, which permits compatibility with SPV3's main UI;
             * -   TWEAKS: Rudimentary tweaks including cinematic bars, and controller enhancements (magnetism & auto-aim);
             * -   SHADER: SPV3 post-processing configurations, including activated shaders & shader intensity levels.
             */

            void Init()
            {
                var init = (Initiation)GetFullPath(executable.Debug.Initiation);

                Resume(); /* spv3 campaign resume with ui.map compatibility */
                Tweaks(); /* hce/spv3 start-up miscellaneous tweaks         */
                Shader(); /* spv3 post-processing toggles & settings        */
                Unlock(); /* spv3.1 legacy maps unlocking mechanism         */

                try
                {
                    init.Save();

                    Core("MAIN.INIT: Initiation data has been successfully applied and saved.");
                }
                catch (Exception e)
                {
                    var msg = " -- MAIN.INIT HALTED.\n Error:  " + e.ToString() + "\n";
                    var log = (File)Paths.Exception;
                    log.AppendAllText(msg);
                    Error(msg);
                }

                /**
                 * Resume the campaign based on the progress of the last used profile. This requires:
                 *
                 * -   a LASTPROF.TXT file to be located in the profile path declared for the inbound executable; and
                 * -   the directory for the profile declared in the aforementioned plaintext file; and
                 * -   the savegame.bin for the respective profile, to infer the campaign progress.
                 */

                void Resume()
                {
                    if (configuration.Mode != Configuration.ConfigurationMode.SPV32 &&
                        configuration.Mode != Configuration.ConfigurationMode.SPV33)
                    {
                        return;
                    }

                    try
                    {
                        var lastprof = (LastProfile)Custom.LastProfile(executable.Profile.Path);

                        /** Check if lastprof.txt exists
                         * If it exists, load its data
                         * Else, create a new one
                         */
                        if (lastprof.Exists())
                        {
                            lastprof.Load();
                        }
                        else
                        {
                            Error("Lastprof.txt does not Exist.");
                            Core("Saving LastProf.txt...");
                            lastprof.Save();
                        }

                        var name = lastprof.Profile;
                        var save = (Progress)Custom.Progress(executable.Profile.Path, name);

                        /** Check for the existence of the blam.sav specified by LastProfile.
                         * If it exists, skip this abomination.
                         * Else, create a new player profile
                         *   or search for existing profiles.
                         */
                        if (!save.Exists())
                        {
                            Error("Player Profile specified in LastProfile not found.");
                            var savegames = Custom.Profiles(executable.Profile.Path);

                            /** Check if the Savegames (profiles) folder exists.
                             * If it exists, search for existing profiles.
                             * Else, create a new player profile.
                             */
                            if (Exists(savegames))
                            {
                                List <Profile> profiles      = Profile.List(savegames);
                                List <Profile> validProfiles = new List <Profile> {
                                };

                                /** Check for any existing profile folders
                                 * If any are found, check if their blam.sav also exists.
                                 *  Select the first valid profile.
                                 * Else, create a new player profile.
                                 */
                                if (profiles.Count != 0)
                                {
                                    foreach (Profile profile in profiles)
                                    {
                                        if (profile.Exists())
                                        {
                                            validProfiles.Add(profile); // todo: implement better validation
                                        }
                                    }
                                    lastprof.Profile = validProfiles[0].Details.Name;
                                    lastprof.Save();
                                }
                                else
                                {
                                    Error("No profiles found in savegames folder.");
                                    Core("Generating new profile");
                                    NewProfile.Generate(executable.Profile.Path, lastprof, new Profile(), false);
                                }
                            }
                            else
                            {
                                Error("Savegames folder does not exist.");
                                Core("Creating savegames folder and a new profile...");
                                NewProfile.Generate(executable.Profile.Path, lastprof, new Profile(), false);;
                            }
                            name = lastprof.Profile;
                            save = (Progress)Custom.Progress(executable.Profile.Path, name);
                        }

                        var campaign = new Campaign(Paths.Campaign(configuration.Mode));

                        campaign.Load();
                        save.Load(campaign);

                        init.Progress = save;
                        init.Resume   = campaign.Resume;

                        Core("INIT.RESUME: Campaign checkpoint information has been applied to the initiation file.");

                        Debug("INIT.RESUME: Mission    - " + init.Progress.Mission.Name);
                        Debug("INIT.RESUME: Difficulty - " + init.Progress.Difficulty.Name);
                    }
                    catch (Exception e)
                    {
                        var msg = " -- INIT.RESUME HALTED\n Error:  " + e.ToString() + "\n";
                        var log = (File)Paths.Exception;
                        log.AppendAllText(msg);
                        Error(e.Message + " -- INIT.RESUME HALTED");
                    }
                }

                /**
                 * Rudimentary tweaks including:
                 *
                 * -   Player Auto-aim
                 * -   Player Magnetism
                 * -   Acceleration
                 *
                 * ... and stuff for SPV3:
                 *
                 * -   Cinematic Bars
                 * -   Motion Sensor
                 */

                void Tweaks()
                {
                    init.PlayerAutoaim     = configuration.Tweaks.AutoAim;
                    init.PlayerMagnetism   = configuration.Tweaks.Magnetism;
                    init.MouseAcceleration = configuration.Tweaks.Acceleration;
                    init.Gamma             = configuration.Video.Gamma;

                    if (configuration.Mode == Configuration.ConfigurationMode.SPV32 ||
                        configuration.Mode == Configuration.ConfigurationMode.SPV33)
                    {
                        init.CinemaBars   = configuration.Tweaks.CinemaBars;
                        init.MotionSensor = configuration.Tweaks.Sensor;
                        init.Unload       = configuration.Tweaks.Unload;

                        Core("INIT.TWEAKS: SPV3 cinematic bars, motion sensor and unload tweaks have been updated.");

                        Debug("INIT.TWEAKS: Cinematic Bars - " + init.CinemaBars);
                        Debug("INIT.TWEAKS: Motion Sensor  - " + init.MotionSensor);
                        Debug("INIT.TWEAKS: Unload         - " + init.Unload);
                    }

                    Core("INIT.TWEAKS: Magnetism, auto-aim, and mouse acceleration tweaks have been updated.");

                    Debug("INIT.TWEAKS: Player Auto-aim    - " + init.PlayerAutoaim);
                    Debug("INIT.TWEAKS: Player Magnetism   - " + init.PlayerMagnetism);
                    Debug("INIT.TWEAKS: Mouse Acceleration - " + init.MouseAcceleration);
                    Debug("INIT.TWEAKS: Gamma              - " + init.Gamma);
                }

                /**
                 * SPV3 shader toggles and configurations.
                 */

                void Shader()
                {
                    if (configuration.Mode != Configuration.ConfigurationMode.SPV32 &&
                        configuration.Mode != Configuration.ConfigurationMode.SPV33)
                    {
                        return;
                    }

                    init.Shaders = configuration.Shaders;

                    Core("INIT.SHADER: SPV3 post-processing effects have been assigned to the initiation file.");
                }

                /**
                 * Indeed, SPV3.1 had some DRM I wasn't quite a fan of. This routine unlocks the 3.1 campaigns. Is this a crack?
                 * I should have a demo screen playing here, along with greetings to friends all over the world.
                 *
                 * Idea: Release 3.2 with an NFO file with ANSI art.
                 */

                void Unlock()
                {
                    if (configuration.Mode != Configuration.ConfigurationMode.SPV32)
                    {
                        return;
                    }

                    init.Unlock = true;

                    Core("INIT.UNLOCK: SPV3.1 campaign has been unlocked for subsequent invocation.");
                }
            }

            /**
             * We enhance the player's profile by applying the highest video & audio quality settings, along with forcing the
             * resolution declared in video parameters of the inbound executable.
             *
             * The enhancements are applied based on the provided configuration and the successful inference
             * the last used profile in the specified profiles directory.
             */

            void Blam()
            {
                Profile blam;

                try
                {
                    blam = Profile.Detect(executable.Profile.Path);

                    Video();
                    Audio();
                    Input();

                    blam.Save();

                    Core("MAIN.BLAM: Profile enhancements have been successfully applied and saved.");
                }
                catch (FileNotFoundException)
                {
                    var lastprof = (LastProfile)Custom.LastProfile(executable.Profile.Path);
                    var scaffold = lastprof.Exists() && System.IO.File.Exists(Custom.Profile(executable.Profile.Path, lastprof.Profile));

                    if (!lastprof.Exists())
                    {
                        Core("Lastprof.txt does not exist.");
                    }

                    if (!scaffold)
                    {
                        Debug("Savegames scaffold doesn't exist.");
                    }
                    else
                    {
                        Debug("Savegames scaffold detected.");
                    }

                    Core("Calling LastProfile.Generate()...");
                    NewProfile.Generate(executable.Profile.Path, lastprof, blam = new Profile(), scaffold);
                }
                catch (Exception e)
                {
                    var msg = " -- MAIN.BLAM HALTED\n Error:  " + e.ToString() + "\n";
                    var log = (File)Paths.Exception;
                    log.AppendAllText(msg);
                    Error(msg);
                }

                /**
                 * Apply the resolution specified in video parameters of the inbound executable OR apply the primary screen's
                 * current resolution. This enforces HCE to run at the desired or native resolution, and also obsoletes Ecran.
                 *
                 * Additionally, effects and qualities are enabled and set to the maximum level, respectively. Of course, this
                 * also depends on the provided configuration.
                 */

                void Video()
                {
                    if (!configuration.Video.ResolutionEnabled)
                    {
                        // infer from resolution if Native Resoluton preferred.
                        if (executable.Video.Width == 0 || executable.Video.Height == 0)
                        {
                            executable.Video.Width  = (ushort)PrimaryScreen.Bounds.Width;
                            executable.Video.Height = (ushort)PrimaryScreen.Bounds.Height;

                            Core("BLAM.VIDEO.RESOLUTION: No resolution provided. Applied native resolution to executable.");
                        }
                        else if (executable.Video.Width > (ushort)PrimaryScreen.Bounds.Width ||
                                 executable.Video.Height > (ushort)PrimaryScreen.Bounds.Height)
                        {
                            executable.Video.Width  = (ushort)PrimaryScreen.Bounds.Width;
                            executable.Video.Height = (ushort)PrimaryScreen.Bounds.Height;

                            Core("BLAM.VIDEO.RESOLUTION: Resolution out of bounds. Applied native resolution to executable.");
                        }

                        blam.Video.Resolution.Width  = executable.Video.Width;
                        blam.Video.Resolution.Height = executable.Video.Height;

                        Core("BLAM.VIDEO.RESOLUTION: Executable resolution has been assigned to the inferred profile.");

                        Debug("BLAM.VIDEO.RESOLUTION: Width  - " + blam.Video.Resolution.Width);
                        Debug("BLAM.VIDEO.RESOLUTION: Height - " + blam.Video.Resolution.Height);
                    }

                    if (configuration.Video.Bless)
                    {
                        executable.Video.Width  -= 10;
                        executable.Video.Height -= 10;
                        Core("BLAM.VIDEO.BLESS: Tweaked executable resolution for border-less support.");
                    }

                    if (configuration.Video.Quality)
                    {
                        blam.Video.Effects.Specular = true;
                        blam.Video.Effects.Shadows  = true;
                        blam.Video.Effects.Decals   = true;

                        blam.Video.Quality   = VideoQuality.High;
                        blam.Video.Particles = VideoParticles.High;

                        Core("BLAM.VIDEO.QUALITY: Patched effects and quality to the highest levels.");

                        Debug("BLAM.VIDEO.QUALITY: Specular  - " + blam.Video.Effects.Specular);
                        Debug("BLAM.VIDEO.QUALITY: Shadows   - " + blam.Video.Effects.Shadows);
                        Debug("BLAM.VIDEO.QUALITY: Decals    - " + blam.Video.Effects.Decals);
                        Debug("BLAM.VIDEO.QUALITY: Quality   - " + blam.Video.Quality);
                        Debug("BLAM.VIDEO.QUALITY: Particles - " + blam.Video.Particles);
                    }

                    if (configuration.Video.Uncap)
                    {
                        blam.Video.FrameRate = VideoFrameRate.VsyncOff;

                        Core("BLAM.VIDEO.UNCAP: Applied V-Sync off for framerate uncap.");

                        Debug("BLAM.VIDEO.UNCAP: Framerate - " + blam.Video.FrameRate);
                    }

                    Core("BLAM.VIDEO: Video enhancements have been applied accordingly.");
                }

                /**
                 * Apply the highest audio settings and toggle Hardware Acceleration & EAX. The latter will require a compatible
                 * library such as DSOAL for it to actually work.
                 */

                void Audio()
                {
                    if (configuration.Audio.Quality)
                    {
                        blam.Audio.Quality = AudioQuality.High;
                        blam.Audio.Variety = AudioVariety.High;

                        Core("BLAM.AUDIO.QUALITY: Patched audio quality to the highest level.");

                        Debug("BLAM.AUDIO.QUALITY: Quality - " + blam.Audio.Quality);
                        Debug("BLAM.AUDIO.QUALITY: Variety - " + blam.Audio.Variety);
                    }

                    if (configuration.Audio.Enhancements)
                    {
                        if (System.IO.File.Exists(DSOAL))
                        {
                            blam.Audio.HWA = true;
                            blam.Audio.EAX = true;

                            Core("BLAM.AUDIO.ENHANCEMENTS: Enabled Hardware Acceleration & EAX.");
                        }
                        else
                        {
                            blam.Audio.HWA = false;
                            blam.Audio.EAX = false;

                            Core("BLAM.AUDIO.ENHANCEMENTS: DSOAL not found. Refusing to enable HWA & EAX..");
                        }

                        Debug("BLAM.AUDIO.ENHANCEMENTS: HWA - " + blam.Audio.HWA);
                        Debug("BLAM.AUDIO.ENHANCEMENTS: EAX - " + blam.Audio.EAX);
                    }

                    Core("BLAM.AUDIO: Audio enhancements have been applied accordingly.");
                }

                /**
                 * Apply SPV3's preset input to the controller.
                 */

                void Input()
                {
                    if (!configuration.Input.Override)
                    {
                        return;
                    }

                    blam.Input.Mapping = new Dictionary <Profile.ProfileInput.Action, Profile.ProfileInput.Button>
                    {
                        { Profile.ProfileInput.Action.MoveForward, Profile.ProfileInput.Button.LSU },
                        { Profile.ProfileInput.Action.MoveBackward, Profile.ProfileInput.Button.LSD },
                        { Profile.ProfileInput.Action.MoveLeft, Profile.ProfileInput.Button.LSL },
                        { Profile.ProfileInput.Action.MoveRight, Profile.ProfileInput.Button.LSR },
                        { Profile.ProfileInput.Action.Crouch, Profile.ProfileInput.Button.LSM },
                        { Profile.ProfileInput.Action.Reload, Profile.ProfileInput.Button.DPU },
                        { Profile.ProfileInput.Action.Jump, Profile.ProfileInput.Button.A },
                        { Profile.ProfileInput.Action.SwitchGrenade, Profile.ProfileInput.Button.B },
                        { Profile.ProfileInput.Action.Action, Profile.ProfileInput.Button.X },
                        { Profile.ProfileInput.Action.SwitchWeapon, Profile.ProfileInput.Button.Y },
                        { Profile.ProfileInput.Action.LookUp, Profile.ProfileInput.Button.RSU },
                        { Profile.ProfileInput.Action.LookDown, Profile.ProfileInput.Button.RSD },
                        { Profile.ProfileInput.Action.LookLeft, Profile.ProfileInput.Button.RSL },
                        { Profile.ProfileInput.Action.LookRight, Profile.ProfileInput.Button.RSR },
                        { Profile.ProfileInput.Action.ScopeZoom, Profile.ProfileInput.Button.RSM },
                        { Profile.ProfileInput.Action.ThrowGrenade, Profile.ProfileInput.Button.LB },
                        { Profile.ProfileInput.Action.Flashlight, Profile.ProfileInput.Button.LT },
                        { Profile.ProfileInput.Action.MeleeAttack, Profile.ProfileInput.Button.RB },
                        { Profile.ProfileInput.Action.FireWeapon, Profile.ProfileInput.Button.RT }
                    };

                    blam.Input.BitBinding = new Dictionary <Profile.ProfileInput.OddValues, Profile.ProfileInput.OddOffsets>
                    {
                        { Profile.ProfileInput.OddValues.Button1, Profile.ProfileInput.OddOffsets.MenuAccept },
                        { Profile.ProfileInput.OddValues.Button2, Profile.ProfileInput.OddOffsets.MenuBack }
                    };

                    Core("BLAM.INPUT: Input overrides have been applied accordingly.");
                }
            }

            /**
             * For SPV3.2+, we will tweak the OpenSauce settings to ensure full compatibility with 3.2+'s specifications and
             * post-processing effects.
             */

            void Open()
            {
                var open = (OpenSauce)Custom.OpenSauce(executable.Profile.Path);
                var mod  = System.IO.File.Exists("./dinput8.dll") ||
                           System.IO.File.Exists("./mods/opensauce.dll");

                if (System.IO.File.Exists("./dinput8.dll"))
                {
                    Debug("dinput8.dll exists");
                }
                else
                {
                    Debug("dinput8 not found");
                }

                if (System.IO.File.Exists("./mods/opensauce.dll"))
                {
                    Debug("opensauce.dll exists");
                }
                else
                {
                    Debug("opensauce.dll not found");
                }

                if (!mod)
                {
                    Debug("Open Sauce not found");
                }

                if (open.Exists() && mod)
                {
                    open.Load();
                }
                else if (mod)
                {
                    open.Save();
                    open.Load();
                }


                try
                {
                    if (configuration.Mode == Configuration.ConfigurationMode.HCE)
                    {
                        return;
                    }

                    open.Rasterizer.PostProcessing.MotionBlur.Enabled = (configuration.Shaders & PP.MOTION_BLUR_BUILT_IN) != 0;
                    open.HUD.ScaleHUD = true;                                 /* fixes user interface    */
                    open.Camera.IgnoreFOVChangeInCinematics           = true; /* fixes user interface    */
                    open.Camera.IgnoreFOVChangeInMainMenu             = true; /* fixes user interface    */
                    open.Rasterizer.ShaderExtensions.Effect.DepthFade = true; /* shader optimisations    */

                    open.Save();

                    Core("MAIN.OPEN: Conditionally applied SPV3 fixes - enabled HUD scaling, FOV ignoreing, and depth fade.");

                    Debug("MAIN.OPEN: Motion Blur          - " + open.Rasterizer.PostProcessing.MotionBlur.Enabled);
                    Debug("MAIN.OPEN: HUD Scaling          - " + open.HUD.ScaleHUD);
                    Debug("MAIN.OPEN: Cinematic FOV Ignore - " + open.Camera.IgnoreFOVChangeInCinematics);
                    Debug("MAIN.OPEN: Main Menu FOV Ignore - " + open.Camera.IgnoreFOVChangeInMainMenu);
                    Debug("MAIN.OPEN: Depth Fade Effects   - " + open.Rasterizer.ShaderExtensions.Effect.DepthFade);
                }
                catch (Exception e)
                {
                    var msg = " -- MAIN.OPEN\n Error:  " + e.ToString() + "\n";
                    var log = (File)Paths.Exception;
                    log.AppendAllText(msg);
                    Error(msg);
                }
            }

            /**
             * Gracefully halt any potentially hanging HCE processes, conditionally patch the HCE executable with LAA flag,
             * and start the executable.
             */

            void Exec()
            {
                Reset();
                Patch();
                Start();
                Bless();

                Core("MAIN.EXEC: All HCE execution routines have been successfully resolved.");

                /**
                 * This method encourages the kernel to wait for a potential HCE process to end before proceeding with any
                 * subsequent routines. For some odd reason, there are cases where HCE runs in the background after the end-user
                 * exits it, thus prohibiting any additional processes from being invoked. To mitigate that, we gracefully kill
                 * any existing ones.
                 */

                void Reset()
                {
                    Info("Killing existing HCE processes");

                    try
                    {
                        foreach (var process in GetProcessesByName("haloce"))
                        {
                            process.Kill();
                        }
                    }
                    catch (Exception e)
                    {
                        var msg = " -- MAIN.BLAM HALTED\n Error:  " + e.ToString() + "\n";
                        var log = (File)Paths.Exception;
                        log.AppendAllText(msg);
                        Info(msg);
                    }

                    var tries = 0;

                    Wait("Waiting for existing HCE process to end ");

                    while (GetProcessesByName("haloce").Length > 0 && tries <= 25)
                    {
                        System.Console.Write(Resources.Progress);
                        tries++;
                    }

                    if (tries == 25)
                    {
                        Error("Could not kill HCE process. Process initiation errors may occur.");
                    }

                    Core("EXEC.RESET: Finalised attempts of killing potential HCE processes.");
                }

                /**
                 * If the HCE executable is not already patched with the LAA flag, this method will take care of modifying the
                 * byte's value to enable the respective LAA flag.
                 */

                void Patch()
                {
                    if (configuration.Tweaks.Acceleration)
                    {
                        configuration.Tweaks.Patches |= Patcher.EXEP.DISABLE_MOUSE_ACCELERATION;
                    }
                    if (configuration.Video.GammaOn == false)
                    {
                        configuration.Tweaks.Patches |= Patcher.EXEP.DISABLE_SYSTEM_GAMMA;
                    }

                    try
                    {
                        new Patcher().Write(configuration.Tweaks.Patches, executable.Path);
                        Core("EXEC.PATCH: Conditional patching has been handled.");
                    }
                    catch (Exception e)
                    {
                        var msg = " -- EXEC.PATCH HALTED\n Error:  " + e.ToString() + "\n";
                        var log = (File)Paths.Exception;
                        log.AppendAllText(msg);
                        Error(msg);
                    }
                }

                /**
                 * God is on my side if this method actually gets called.
                 */

                void Start()
                {
                    try
                    {
                        executable.Start(configuration.Main.Elevated);

                        Core("EXEC.START: Successfully started the inferred HCE executable.");
                    }
                    catch (Exception e)
                    {
                        var msg = " -- EXEC.START HALTED\n Error:  " + e.ToString() + "\n";
                        var log = (File)Paths.Exception;
                        log.AppendAllText(msg);
                        Error(msg);
                    }
                }

                /**
                 * Bless for border-less!
                 */

                void Bless()
                {
                    if (!configuration.Video.Bless)
                    {
                        return;
                    }

                    const int LOADED_OFFSET   = 0x0064533B; /* 0x6B4051 could also be used, according to github.com/gbMichelle */
                    const int PROCESS_WM_READ = 0x0010;
                    const int GWL_STYLE       = -16;
                    const int SWP_NOMOVE      = 0X2;
                    const int SWP_NOSIZE      = 1;
                    const int SWP_NOZORDER    = 0X4;
                    const int SWP_SHOWWINDOW  = 0x0040;
                    const int WS_SYSMENU      = 0x00080000;
                    const int WS_MAXIMIZEBOX  = 0x00010000;
                    const int WS_MINIMIZEBOX  = 0x00020000;
                    const int WS_SIZEBOX      = 0x00040000;
                    const int WS_BORDER       = 0x00800000;
                    const int WS_DLGFRAME     = 0x00400000;
                    const int WS_CAPTION      =
                        SWP_NOMOVE | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_BORDER | WS_DLGFRAME | WS_SIZEBOX;

                    try
                    {
                        var processes = GetProcesses();

                        foreach (var process in processes)
                        {
                            if (!process.ProcessName.StartsWith("haloce"))
                            {
                                continue;
                            }

                            /**
                             * The bless hack is applied only when HCE has been loaded. HXE deems HCE as loaded when the main menu has
                             * been initiated.
                             *
                             * This is determined by checking the value declared at LOADED_OFFSET. The value changes from 0 to 1 the
                             * moment HCE has loaded.
                             *
                             * The reason we apply the hack then is for robustness: the HCE window becomes responsive around that time
                             * after the loading sequence.
                             */

                            var processHandle = OpenProcess(PROCESS_WM_READ, false, process.Id);

                            var bytesRead = 0;
                            var buffer    = new byte[1];
                            var loaded    = false;

                            while (!loaded && process.HasExited != true)
                            {
                                ReadProcessMemory((int)processHandle, LOADED_OFFSET, buffer, buffer.Length, ref bytesRead);
                                loaded = buffer[0] == 1;
                            }

                            /**
                             * The hack attempts to hide any window controls and also move the window to the top left of the current
                             * display. In most circumstances, this should work just fine. If people are applying border-less mode and
                             * use a resolution lower than their screen resolution, then, err... why?
                             */

                            var pFoundWindow = process.MainWindowHandle;
                            var style        = GetWindowLong(pFoundWindow, GWL_STYLE);
                            SetWindowLong(pFoundWindow, GWL_STYLE, style & ~WS_CAPTION);
                            SetWindowPos(pFoundWindow, 0, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
                            Core("EXEC.BLESS: Applied border-less hack to the HCE process window.");
                        }
                    }
                    catch (Exception e)
                    {
                        var msg = " -- EXEC.START HALTED\n Error:  " + e.ToString() + "\n";
                        var log = (File)Paths.Exception;
                        log.AppendAllText(msg);
                        Error(msg);
                    }
                }
            }
        }
Exemple #2
0
 /// <summary>
 ///   Invokes the HCE executable.
 /// </summary>
 private static void InvokeExecutable(Executable executable)
 {
     executable.Start();
 }
Exemple #3
0
        /// <summary>
        ///   Loads inbound HCE executable with the inbound configuration.
        /// </summary>
        /// <param name="executable">
        ///   Object representing a legal HCE executable.
        /// </param>
        /// <param name="configuration">
        ///   Object representing the kernel configuration.
        /// </param>
        public static void Invoke(Executable executable, Configuration configuration)
        {
            Init(); /* initc.txt declarations */
            Blam(); /* blam.sav enhancements  */
            Open(); /* opensauce declarations */
            Exec(); /* haloce.exe invocation  */

            Core("CORE.MAIN: Successfully updated the initiation, profile and OS files, and invoked the HCE executable.");

            /**
             * We declare the contents of the initiation file in this method before dealing with the profile enhancements and
             * the executable invocation. It's the most important task, so we have to deal with it first.
             *
             * The values declared by the HXE kernel for the initiation file are categorised into the following sections:
             *
             * -   RESUME: Campaign resuming support for the SPV3 mod, which permits compatibility with SPV3's main UI;
             * -   TWEAKS: Rudimentary tweaks including cinematic bars, and controller enhancements (magnetism & auto-aim);
             * -   SHADER: SPV3 post-processing configurations, including activated shaders & shader intensity levels.
             */

            void Init()
            {
                var init = (Initiation)GetFullPath(executable.Debug.Initiation);

                Resume(); /* spv3 campaign resume with ui.map compatibility */
                Tweaks(); /* hce/spv3 start-up miscellaneous tweaks         */
                Shader(); /* spv3 post-processing toggles & settings        */
                Unlock(); /* spv3.1 legacy maps unlocking mechanism         */

                try
                {
                    init.Save();

                    Core("MAIN.INIT: Initiation data has been successfully applied and saved.");
                }
                catch (Exception e)
                {
                    Error(e.Message + " -- MAIN.INIT HALTED");
                }

                /**
                 * Resume the campaign based on the progress of the last used profile. This requires:
                 *
                 * -   a LASTPROF.TXT file to be located in the profile path declared for the inbound executable; and
                 * -   the directory for the profile declared in the aforementioned plaintext file; and
                 * -   the savegame.bin for the respective profile, to infer the campaign progress.
                 */

                void Resume()
                {
                    try
                    {
                        var prof = (LastProfile)Custom.LastProfile(executable.Profile.Path);

                        if (!prof.Exists())
                        {
                            return;
                        }

                        prof.Load();

                        var name = prof.Profile;
                        var save = (Progress)Custom.Progress(executable.Profile.Path, name);

                        if (!save.Exists())
                        {
                            return;
                        }

                        save.Load();

                        init.Mission    = save.Mission;
                        init.Difficulty = save.Difficulty;

                        Core("INIT.RESUME: Campaign checkpoint information has been applied to the initiation file.");

                        Debug("INIT.RESUME: Mission    - " + init.Mission);
                        Debug("INIT.RESUME: Difficulty - " + init.Difficulty);
                    }
                    catch (Exception e)
                    {
                        Error(e.Message + " -- INIT.RESUME HALTED");
                    }
                }

                /**
                 * Rudimentary tweaks including:
                 *
                 * -   Player Auto-aim
                 * -   Player Magnetism
                 * -   Execution speed
                 * -   Acceleration
                 *
                 * ... and stuff for SPV3:
                 *
                 * -   Cinematic Bars
                 * -   Motion Sensor
                 */

                void Tweaks()
                {
                    init.PlayerAutoaim     = configuration.Tweaks.AutoAim;
                    init.PlayerMagnetism   = configuration.Tweaks.Magnetism;
                    init.Speed             = configuration.Tweaks.Speed;
                    init.MouseAcceleration = configuration.Tweaks.Acceleration;
                    init.Gamma             = configuration.Video.Gamma;

                    if (configuration.Mode == Configuration.ConfigurationMode.SPV32)
                    {
                        init.CinematicBars = configuration.Tweaks.Cinematic;
                        init.MotionSensor  = configuration.Tweaks.Sensor;
                        init.Unload        = configuration.Tweaks.Unload;

                        Core("INIT.TWEAKS: SPV3.2 cinematic bars, motion sensor and unload tweaks have been updated.");

                        Debug("INIT.TWEAKS: Cinematic Bars - " + init.CinematicBars);
                        Debug("INIT.TWEAKS: Motion Sensor  - " + init.MotionSensor);
                        Debug("INIT.TWEAKS: Unload         - " + init.Unload);
                    }

                    Core("INIT.TWEAKS: Magnetism, auto-aim, speed and mouse acceleration tweaks have been updated.");

                    Debug("INIT.TWEAKS: Player Auto-aim    - " + init.PlayerAutoaim);
                    Debug("INIT.TWEAKS: Player Magnetism   - " + init.PlayerMagnetism);
                    Debug("INIT.TWEAKS: Speed              - " + init.Speed);
                    Debug("INIT.TWEAKS: Mouse Acceleration - " + init.MouseAcceleration);
                    Debug("INIT.TWEAKS: Gamma              - " + init.Gamma);
                }

                /**
                 * SPV3.2 shader toggles and configurations.
                 */

                void Shader()
                {
                    if (configuration.Mode != Configuration.ConfigurationMode.SPV32)
                    {
                        return;
                    }

                    init.PostProcessing.Internal           = configuration.Shaders.Internal;
                    init.PostProcessing.External           = configuration.Shaders.External;
                    init.PostProcessing.GBuffer            = configuration.Shaders.GBuffer;
                    init.PostProcessing.DepthFade          = configuration.Shaders.DepthFade;
                    init.PostProcessing.Bloom              = configuration.Shaders.Bloom;
                    init.PostProcessing.LensDirt           = configuration.Shaders.LensDirt;
                    init.PostProcessing.DynamicLensFlares  = configuration.Shaders.DynamicLensFlares;
                    init.PostProcessing.VolumetricLighting = configuration.Shaders.VolumetricLighting;
                    init.PostProcessing.AntiAliasing       = configuration.Shaders.AntiAliasing;
                    init.PostProcessing.HudVisor           = configuration.Shaders.HudVisor;
                    init.PostProcessing.FilmGrain          = configuration.Shaders.FilmGrain;
                    init.PostProcessing.MotionBlur         = configuration.Shaders.MotionBlur;
                    init.PostProcessing.MXAO = configuration.Shaders.MXAO;
                    init.PostProcessing.DOF  = configuration.Shaders.DOF;

                    Core("INIT.SHADER: SPV3.2 post-processing effects have been assigned to the initiation file.");

                    Debug("INIT.SHADER: Internal            - " + init.PostProcessing.Internal);
                    Debug("INIT.SHADER: External            - " + init.PostProcessing.External);
                    Debug("INIT.SHADER: GBuffer             - " + init.PostProcessing.GBuffer);
                    Debug("INIT.SHADER: DepthFade           - " + init.PostProcessing.DepthFade);
                    Debug("INIT.SHADER: Bloom               - " + init.PostProcessing.Bloom);
                    Debug("INIT.SHADER: LensDirt            - " + init.PostProcessing.LensDirt);
                    Debug("INIT.SHADER: Dynamic Lens Flares - " + init.PostProcessing.DynamicLensFlares);
                    Debug("INIT.SHADER: Volumetric Lighting - " + init.PostProcessing.VolumetricLighting);
                    Debug("INIT.SHADER: Anti Aliasing       - " + init.PostProcessing.AntiAliasing);
                    Debug("INIT.SHADER: HUD Visor           - " + init.PostProcessing.HudVisor);
                    Debug("INIT.SHADER: Film Grain          - " + init.PostProcessing.FilmGrain);
                    Debug("INIT.SHADER: Motion Blur         - " + init.PostProcessing.MotionBlur);
                    Debug("INIT.SHADER: MXAO                - " + init.PostProcessing.MXAO);
                    Debug("INIT.SHADER: DOF                 - " + init.PostProcessing.DOF);
                }

                /**
                 * Indeed, SPV3.1 had some DRM I wasn't quite a fan of. This routine unlocks the 3.1 campaigns. Is this a crack?
                 * I should have a demo screen playing here, along with greetings to friends all over the world.
                 *
                 * Idea: Release 3.2 with an NFO file with ANSI art.
                 */

                void Unlock()
                {
                    if (configuration.Mode != Configuration.ConfigurationMode.SPV31)
                    {
                        return;
                    }

                    init.Unlock = true;

                    Core("INIT.UNLOCK: SPV3.1 campaign has been unlocked for subsequent invocation.");
                }
            }

            /**
             * We enhance the player's profile by applying the highest video & audio quality settings, along with forcing the
             * resolution declared in video parameters of the inbound executable.
             *
             * The enhancements are applied based on the provided configuration, and also the on the success rate of inferring
             * the last used profile in the specified profiles directory.
             */

            void Blam()
            {
                Profile blam;

                try
                {
                    blam = Profile.Detect(executable.Profile.Path);

                    Video();
                    Audio();
                    Input();

                    blam.Save();

                    Core("MAIN.BLAM: Profile enhancements have been successfully applied and saved.");
                }
                catch (Exception e)
                {
                    Error(e.Message + " -- MAIN.BLAM HALTED");
                }

                /**
                 * Apply the resolution specified in video parameters of the inbound executable OR apply the primary screen's
                 * current resolution. This enforces HCE to run at the desired or native resolution, and also obsoletes Ecran.
                 *
                 * Additionally, effects and qualities are enabled and set to the maximum level, respectively. Of course, this
                 * also depends on the provided configuration.
                 */

                void Video()
                {
                    if (configuration.Video.Resolution)
                    {
                        if (executable.Video.Width == 0 || executable.Video.Height == 0)
                        {
                            executable.Video.Width  = (ushort)PrimaryScreen.Bounds.Width;
                            executable.Video.Height = (ushort)PrimaryScreen.Bounds.Height;

                            Core("BLAM.VIDEO.RESOLUTION: No resolution provided. Applied native resolution to executable.");
                        }

                        if (executable.Video.Width > (ushort)PrimaryScreen.Bounds.Width ||
                            executable.Video.Height > (ushort)PrimaryScreen.Bounds.Height)
                        {
                            executable.Video.Width  = (ushort)PrimaryScreen.Bounds.Width;
                            executable.Video.Height = (ushort)PrimaryScreen.Bounds.Height;

                            Core("BLAM.VIDEO.RESOLUTION: Resolution out of bounds. Applied native resolution to executable.");
                        }

                        blam.Video.Resolution.Width  = executable.Video.Width;
                        blam.Video.Resolution.Height = executable.Video.Height;

                        Core("BLAM.VIDEO.RESOLUTION: Executable resolution has been assigned to the inferred profile.");

                        Debug("BLAM.VIDEO.RESOLUTION: Width  - " + blam.Video.Resolution.Width);
                        Debug("BLAM.VIDEO.RESOLUTION: Height - " + blam.Video.Resolution.Height);
                    }

                    if (configuration.Video.Bless)
                    {
                        executable.Video.Width  -= 10;
                        executable.Video.Height -= 10;
                        Core("BLAM.VIDEO.BLESS: Tweaked executable resolution for border-less support.");
                    }

                    if (configuration.Video.Quality)
                    {
                        blam.Video.Effects.Specular = true;
                        blam.Video.Effects.Shadows  = true;
                        blam.Video.Effects.Decals   = true;

                        blam.Video.Quality   = VideoQuality.High;
                        blam.Video.Particles = VideoParticles.High;

                        Core("BLAM.VIDEO.QUALITY: Patched effects and quality to the highest levels.");

                        Debug("BLAM.VIDEO.QUALITY: Specular  - " + blam.Video.Effects.Specular);
                        Debug("BLAM.VIDEO.QUALITY: Shadows   - " + blam.Video.Effects.Shadows);
                        Debug("BLAM.VIDEO.QUALITY: Decals    - " + blam.Video.Effects.Decals);
                        Debug("BLAM.VIDEO.QUALITY: Quality   - " + blam.Video.Quality);
                        Debug("BLAM.VIDEO.QUALITY: Particles - " + blam.Video.Particles);
                    }

                    if (configuration.Video.Uncap)
                    {
                        blam.Video.FrameRate = VideoFrameRate.VsyncOff;

                        Core("BLAM.VIDEO.UNCAP: Applied V-Sync off for framerate uncap.");

                        Debug("BLAM.VIDEO.UNCAP: Framerate - " + blam.Video.FrameRate);
                    }

                    Core("BLAM.VIDEO: Video enhancements have been applied accordingly.");
                }

                /**
                 * Apply the highest audio settings and toggle Hardware Acceleration & EAX. The latter will require a compatible
                 * library such as DSOAL for it to actually work.
                 */

                void Audio()
                {
                    if (configuration.Audio.Quality)
                    {
                        blam.Audio.Quality = AudioQuality.High;
                        blam.Audio.Variety = AudioVariety.High;

                        Core("BLAM.AUDIO.QUALITY: Patched audio quality to the highest level.");

                        Debug("BLAM.AUDIO.QUALITY: Quality - " + blam.Audio.Quality);
                        Debug("BLAM.AUDIO.QUALITY: Variety - " + blam.Audio.Variety);
                    }

                    if (configuration.Audio.Enhancements)
                    {
                        if (System.IO.File.Exists(DSOAL))
                        {
                            blam.Audio.HWA = true;
                            blam.Audio.EAX = true;

                            Core("BLAM.AUDIO.ENHANCEMENTS: Enabled Hardware Acceleration & EAX.");
                        }
                        else
                        {
                            blam.Audio.HWA = false;
                            blam.Audio.EAX = false;

                            Core("BLAM.AUDIO.ENHANCEMENTS: DSOAL not found. Refusing to enable HWA & EAX..");
                        }

                        Debug("BLAM.AUDIO.ENHANCEMENTS: HWA - " + blam.Audio.HWA);
                        Debug("BLAM.AUDIO.ENHANCEMENTS: EAX - " + blam.Audio.EAX);
                    }

                    Core("BLAM.AUDIO: Audio enhancements have been applied accordingly.");
                }

                /**
                 * Apply SPV3.2's preset input to the controller.
                 */

                void Input()
                {
                    if (!configuration.Input.Override)
                    {
                        return;
                    }

                    blam.Input.Mapping = new Dictionary <Profile.ProfileInput.Action, Profile.ProfileInput.Button>
                    {
                        { Profile.ProfileInput.Action.MoveForward, Profile.ProfileInput.Button.LSU },
                        { Profile.ProfileInput.Action.MoveBackward, Profile.ProfileInput.Button.LSD },
                        { Profile.ProfileInput.Action.MoveLeft, Profile.ProfileInput.Button.LSL },
                        { Profile.ProfileInput.Action.MoveRight, Profile.ProfileInput.Button.LSR },
                        { Profile.ProfileInput.Action.Crouch, Profile.ProfileInput.Button.LSM },
                        { Profile.ProfileInput.Action.Reload, Profile.ProfileInput.Button.DPU },
                        { Profile.ProfileInput.Action.Jump, Profile.ProfileInput.Button.A },
                        { Profile.ProfileInput.Action.SwitchGrenade, Profile.ProfileInput.Button.B },
                        { Profile.ProfileInput.Action.Action, Profile.ProfileInput.Button.X },
                        { Profile.ProfileInput.Action.SwitchWeapon, Profile.ProfileInput.Button.Y },
                        { Profile.ProfileInput.Action.LookUp, Profile.ProfileInput.Button.RSU },
                        { Profile.ProfileInput.Action.LookDown, Profile.ProfileInput.Button.RSD },
                        { Profile.ProfileInput.Action.LookLeft, Profile.ProfileInput.Button.RSL },
                        { Profile.ProfileInput.Action.LookRight, Profile.ProfileInput.Button.RSR },
                        { Profile.ProfileInput.Action.ScopeZoom, Profile.ProfileInput.Button.RSM },
                        { Profile.ProfileInput.Action.ThrowGrenade, Profile.ProfileInput.Button.LB },
                        { Profile.ProfileInput.Action.Flashlight, Profile.ProfileInput.Button.LT },
                        { Profile.ProfileInput.Action.MeleeAttack, Profile.ProfileInput.Button.RB },
                        { Profile.ProfileInput.Action.FireWeapon, Profile.ProfileInput.Button.RT }
                    };

                    Core("BLAM.INPUT: Input overrides have been applied accordingly.");
                }
            }

            /**
             * For SPV3.2, we will tweak the OpenSauce settings to ensure full compatibility with 3.2's specifications and
             * post-processing effects.
             */

            void Open()
            {
                var open = (OpenSauce)Custom.OpenSauce(executable.Profile.Path);

                if (open.Exists())
                {
                    open.Load();
                }

                try
                {
                    if (configuration.Mode != Configuration.ConfigurationMode.SPV32)
                    {
                        return;
                    }

                    open.Rasterizer.PostProcessing.MotionBlur.Enabled = configuration.Shaders.MotionBlur == BuiltIn;
                    open.HUD.ScaleHUD = true;                                 /* fixes user interface    */
                    open.Camera.IgnoreFOVChangeInCinematics           = true; /* fixes user interface    */
                    open.Camera.IgnoreFOVChangeInMainMenu             = true; /* fixes user interface    */
                    open.Rasterizer.ShaderExtensions.Effect.DepthFade = true; /* shader optimisations    */

                    open.Save();

                    Core("MAIN.OPEN: Conditionally applied SPV3.2 fixes - enabled HUD scaling, FOV ignoreing, and depth fade.");

                    Debug("MAIN.OPEN: Motion Blur          - " + open.Rasterizer.PostProcessing.MotionBlur.Enabled);
                    Debug("MAIN.OPEN: HUD Scaling          - " + open.HUD.ScaleHUD);
                    Debug("MAIN.OPEN: Cinematic FOV Ignore - " + open.Camera.IgnoreFOVChangeInCinematics);
                    Debug("MAIN.OPEN: Main Menu FOV Ignore - " + open.Camera.IgnoreFOVChangeInMainMenu);
                    Debug("MAIN.OPEN: Depth Fade Effects   - " + open.Rasterizer.ShaderExtensions.Effect.DepthFade);
                }
                catch (Exception e)
                {
                    Error(e.Message + " -- MAIN.OPEN HALTED");
                }
            }

            /**
             * Gracefully halt any potentially hanging HCE processes, conditionally patch the HCE executable with LAA flag,
             * and start the executable.
             */

            void Exec()
            {
                Reset();
                Patch();
                Start();
                Bless();

                Core("MAIN.EXEC: All HCE execution routines have been successfully resolved.");

                /**
                 * This method encourages the kernel to wait for a potential HCE process to end before proceeding with any
                 * subsequent routines. For some odd reason, there are cases where HCE runs in the background after the end-user
                 * exits it, thus prohibiting any additional processes from being invoked. To mitigate that, we gracefully kill
                 * any existing ones.
                 */

                void Reset()
                {
                    Info("Killing existing HCE processes");

                    try
                    {
                        foreach (var process in Process.GetProcessesByName("haloce"))
                        {
                            process.Kill();
                        }
                    }
                    catch (Exception e)
                    {
                        Info(e.Message);
                    }

                    var tries = 0;

                    Wait("Waiting for existing HCE process to end ");

                    while (Process.GetProcessesByName("haloce").Length > 0 && tries <= 25)
                    {
                        System.Console.Write(Resources.Progress);
                        tries++;
                    }

                    if (tries == 25)
                    {
                        Error("Could not kill HCE process. Process initiation errors may occur.");
                    }

                    Core("EXEC.RESET: Finalised attempts of killing potential HCE processes.");
                }

                /**
                 * If the HCE executable is not already patched with the LAA flag, this method will take care of modifying the
                 * byte's value to enable the respective LAA flag.
                 */

                void Patch()
                {
                    const byte value  = 0x2F;  /* LAA flag   */
                    const long offset = 0x136; /* LAA offset */

                    try
                    {
                        using (var fs = new FileStream(executable.Path, FileMode.Open, FileAccess.ReadWrite))
                            using (var ms = new MemoryStream(0x24B000))
                                using (var bw = new BinaryWriter(ms))
                                    using (var br = new BinaryReader(ms))
                                    {
                                        ms.Position = 0;
                                        fs.Position = 0;
                                        fs.CopyTo(ms);

                                        ms.Position = offset;

                                        if (br.ReadByte() != value)
                                        {
                                            ms.Position -= 1; /* restore position */
                                            bw.Write(value);  /* patch LAA flag   */

                                            fs.Position = 0;
                                            ms.Position = 0;
                                            ms.CopyTo(fs);

                                            Info("Applied LAA patch to the HCE executable");
                                        }
                                        else
                                        {
                                            Info("HCE executable already patched with LAA");
                                        }
                                    }

                        Core("EXEC.PATCH: Conditional LAA patching has been handled.");
                    }
                    catch (Exception e)
                    {
                        Error(e.Message + " -- EXEC.PATCH HALTED");
                    }
                }

                /**
                 * God is on my side if this method actually gets called.
                 */

                void Start()
                {
                    try
                    {
                        executable.Start();

                        Core("EXEC.START: Successfully started the inferred HCE executable.");
                    }
                    catch (Exception e)
                    {
                        Error(e.Message + " -- EXEC.START HALTED");
                    }
                }

                /**
                 * Bless for border-less!
                 */

                void Bless()
                {
                    if (!configuration.Video.Bless)
                    {
                        return;
                    }

                    const int GWL_STYLE      = -16;
                    const int SWP_NOMOVE     = 0X2;
                    const int SWP_NOSIZE     = 1;
                    const int SWP_NOZORDER   = 0X4;
                    const int SWP_SHOWWINDOW = 0x0040;
                    const int WS_SYSMENU     = 0x00080000;
                    const int WS_MAXIMIZEBOX = 0x00010000;
                    const int WS_MINIMIZEBOX = 0x00020000;
                    const int WS_SIZEBOX     = 0x00040000;
                    const int WS_BORDER      = 0x00800000;
                    const int WS_DLGFRAME    = 0x00400000;
                    const int WS_CAPTION     =
                        SWP_NOMOVE | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_BORDER | WS_DLGFRAME | WS_SIZEBOX;

                    Thread.Sleep(5000);

                    try
                    {
                        var processes = Process.GetProcesses();

                        foreach (var process in processes)
                        {
                            if (!process.ProcessName.StartsWith("haloce"))
                            {
                                continue;
                            }
                            process.WaitForInputIdle();
                            var pFoundWindow = process.MainWindowHandle;
                            var style        = GetWindowLong(pFoundWindow, GWL_STYLE);
                            SetWindowLong(pFoundWindow, GWL_STYLE, style & ~WS_CAPTION);
                            SetWindowPos(pFoundWindow, 0, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
                            Core("EXEC.BLESS: Applied border-less hack to the HCE process window.");
                        }
                    }
                    catch (Exception e)
                    {
                        Error(e.Message + " -- EXEC.BLESS HALTED");
                    }
                }
            }
        }