public static MemoryDomainProxy[] GetInterfaces()
        {
            try
            {
                Console.WriteLine($" getInterfaces()");

                List <MemoryDomainProxy> interfaces = new List <MemoryDomainProxy>();

                foreach (var md in Program.MemoryDomains)
                {
                    interfaces.Add(new MemoryDomainProxy(md));
                }

                return(interfaces.ToArray());
            }
            catch (Exception ex)
            {
                if (VanguardCore.ShowErrorDialog(ex, true) == DialogResult.Abort)
                {
                    throw new RTCV.NetCore.AbortEverythingException();
                }

                return(new MemoryDomainProxy[] { });
            }
        }
        public static void MAIN_TESTCLIENT(string[] args)
        {
            //MessageBox.Show("ATTACH DEBUGGER NOW");

            if (!System.Environment.Is64BitOperatingSystem)
            {
                MessageBox.Show("32-bit operating system detected. Bizhawk requires 64-bit to run. Program will shut down");
                Application.Exit();
            }

            try
            {
                VanguardCore.args = args;

                disableRTC = VanguardCore.args.Contains("-DISABLERTC");

                //VanguardCore.attached = true;
                VanguardCore.attached = VanguardCore.args.Contains("-ATTACHED");
                //RTC_E.isStandaloneEmu = VanguardCore.args.Contains("-REMOTERTC");

                //RTC_Unispec.RTCSpec.Update(Spec.HOOKS_SHOWCONSOLE.ToString(), RTC_Core.args.Contains("-CONSOLE"));
            }
            catch (Exception ex)
            {
                if (VanguardCore.ShowErrorDialog(ex, true) == DialogResult.Abort)
                {
                    throw new RTCV.NetCore.AbortEverythingException();
                }
            }
        }
        public static bool RefreshDomains(bool updateSpecs = true)
        {
            try
            {
                //Compare the old to the new. If the name and sizes are all the same, don't push that there were changes.
                //We need to compare like this because the domains can change from syncsettings.
                //We only check name and size as those are the only things that can change on the fly
                var  oldInterfaces  = VanguardCore.MemoryInterfacees;
                var  newInterfaces  = GetInterfaces();
                bool domainsChanged = false;

                if (oldInterfaces.Length != newInterfaces.Length)
                {
                    domainsChanged = true;
                }

                for (int i = 0; i < oldInterfaces.Length; i++)
                {
                    if (domainsChanged)
                    {
                        break;
                    }
                    if (oldInterfaces[i].Name != newInterfaces[i].Name)
                    {
                        domainsChanged = true;
                    }
                    if (oldInterfaces[i].Size != newInterfaces[i].Size)
                    {
                        domainsChanged = true;
                    }
                }

                //We gotta push this no matter what since it's new underlying objects
                if (updateSpecs)
                {
                    VanguardCore.VanguardSpec.Update(VSPEC.MEMORYDOMAINS_INTERFACES.ToString(), GetInterfaces());
                    LocalNetCoreRouter.Route(CORRUPTCORE, REMOTE_EVENT_DOMAINSUPDATED, domainsChanged, true);
                }


                return(domainsChanged);
            }
            catch (Exception ex)
            {
                if (VanguardCore.ShowErrorDialog(ex) == DialogResult.Abort)
                {
                    throw new RTCV.NetCore.AbortEverythingException();
                }

                return(false);
            }
        }
        public static void EMU_CRASH(string msg)
        {
            if (disableRTC)
            {
                return;
            }

            //MessageBox.Show("SORRY EMULATOR CRASHED\n\n" + msg);

            if (VanguardCore.ShowErrorDialog(new CustomException("SORRY EMULATOR CRASHED", msg), true) == DialogResult.Abort)
            {
                throw new RTCV.NetCore.AbortEverythingException();
            }
        }
        public static void LOAD_GAME_DONE()
        {
            try
            {
                if (disableRTC)
                {
                    return;
                }


                //Glitch Harvester warning for archives



                //prepare memory domains in advance on bizhawk side
                bool domainsChanged = RefreshDomains(false);

                PartialSpec gameDone = new PartialSpec("VanguardSpec");
                gameDone[VSPEC.SYSTEM]          = EMU_GET_CURRENTLYLOADEDSYSTEMNAME().ToUpper();
                gameDone[VSPEC.GAMENAME]        = EMU_GET_FILESYSTEMGAMENAME();
                gameDone[VSPEC.SYSTEMPREFIX]    = EMU_GET_SAVESTATEPREFIX();
                gameDone[VSPEC.SYSTEMCORE]      = EMU_GET_SYSTEMCORENAME("");
                gameDone[VSPEC.SYNCSETTINGS]    = EMU_GETSET_SYNCSETTINGS;
                gameDone[VSPEC.OPENROMFILENAME] = Program.RomFilename;
                gameDone[VSPEC.MEMORYDOMAINS_BLACKLISTEDDOMAINS] = VanguardCore.GetBlacklistedDomains(EMU_GET_CURRENTLYLOADEDSYSTEMNAME().ToUpper());
                gameDone[VSPEC.MEMORYDOMAINS_INTERFACES]         = GetInterfaces();
                VanguardCore.VanguardSpec.Update(gameDone);

                //This is local. If the domains changed it propgates over netcore
                LocalNetCoreRouter.Route(CORRUPTCORE, REMOTE_EVENT_DOMAINSUPDATED, domainsChanged, true);


                if (VanguardCore.GameName != lastGameName)
                {
                }
                else
                {
                }

                lastGameName = VanguardCore.GameName;
            }
            catch (Exception ex)
            {
                if (VanguardCore.ShowErrorDialog(ex) == DialogResult.Abort)
                {
                    throw new RTCV.NetCore.AbortEverythingException();
                }
            }
        }
        public static void EMU_OPEN_HEXEDITOR_ADDRESS(MemoryDomainProxy mdp, long address)
        {
            try
            {
            }
            catch (Exception ex)
            {
                if (VanguardCore.ShowErrorDialog(ex, true) == DialogResult.Abort)
                {
                    throw new RTCV.NetCore.AbortEverythingException();
                }

                return;
            }
        }
        public static string EMU_GET_CURRENTLYOPENEDROM()
        {
            try
            {
                return(Path.GetFileName(Program.RomFilename));
            }
            catch (Exception ex)
            {
                if (VanguardCore.ShowErrorDialog(ex, true) == DialogResult.Abort)
                {
                    throw new RTCV.NetCore.AbortEverythingException();
                }

                return(null);
            }
        }
        public static bool EMU_ISMAINFORMVISIBLE()
        {
            try
            {
                return(true);
            }
            catch (Exception ex)
            {
                if (VanguardCore.ShowErrorDialog(ex, true) == DialogResult.Abort)
                {
                    throw new RTCV.NetCore.AbortEverythingException();
                }

                return(false);
            }
        }
        public static bool EMU_ISNULLEMULATORCORE()
        {
            try
            {
                return(false);
            }
            catch (Exception ex)
            {
                if (VanguardCore.ShowErrorDialog(ex) == DialogResult.Abort)
                {
                    throw new RTCV.NetCore.AbortEverythingException();
                }

                return(false);
            }
        }
        public static string EMU_GET_CURRENTLYLOADEDSYSTEMNAME()
        {
            try
            {
                return("DEFAULTSYSTEMNAME");
            }
            catch (Exception ex)
            {
                if (VanguardCore.ShowErrorDialog(ex, true) == DialogResult.Abort)
                {
                    throw new RTCV.NetCore.AbortEverythingException();
                }

                return(null);
            }
        }
        public static void CPU_STEP(bool isRewinding, bool isFastForwarding, bool isBeforeStep = false)
        {
            try
            {
                if (disableRTC)
                {
                    return;
                }

                //Return out if it's being called from before the step and we're not on frame 0. If we're on frame 0, then we go as normal
                //If we can't get runbefore, just assume we don't want to run before
                if (isBeforeStep && CPU_STEP_Count != 0 && ((bool)(RTCV.NetCore.AllSpec.CorruptCoreSpec?[RTCSPEC.STEP_RUNBEFORE.ToString()] ?? false)) == false)
                {
                    return;
                }

                isNormalAdvance = !(isRewinding || isFastForwarding);

                // Unique step hooks
                if (!isRewinding && !isFastForwarding)
                {
                    STEP_FORWARD();
                }
                else if (isRewinding)
                {
                    STEP_REWIND();
                }
                else if (isFastForwarding)
                {
                    STEP_FASTFORWARD();
                }

                //Any step hook for corruption
                STEP_CORRUPT(isRewinding, isFastForwarding);
            }
            catch (Exception ex)
            {
                if (VanguardCore.ShowErrorDialog(ex, true) == DialogResult.Abort)
                {
                    throw new RTCV.NetCore.AbortEverythingException();
                }
                MessageBox.Show("Clearing all step blastunits due to an exception within Core_Step().");
                StepActions.ClearStepBlastUnits();
            }
        }
 public static void EMU_LOADROM(string RomFile)
 {
     try
     {
         LOAD_GAME_BEGIN();
         Program.LoadRom(RomFile);
         LOAD_GAME_DONE();
     }
     catch (Exception ex)
     {
         if (VanguardCore.ShowErrorDialog(ex, true) == DialogResult.Abort)
         {
             throw new RTCV.NetCore.AbortEverythingException();
         }
         LOAD_GAME_FAILED();
         return;
     }
 }
        public static void MAINFORM_RESIZEEND()
        {
            try
            {
                if (disableRTC)
                {
                    return;
                }

                VanguardCore.SaveBizhawkWindowState();
            }
            catch (Exception ex)
            {
                if (VanguardCore.ShowErrorDialog(ex, true) == DialogResult.Abort)
                {
                    throw new RTCV.NetCore.AbortEverythingException();
                }
            }
        }
        public static void MAINFORM_FORM_LOAD_END()
        {
            try
            {
                if (disableRTC)
                {
                    return;
                }

                VanguardCore.Start();
            }
            catch (Exception ex)
            {
                if (VanguardCore.ShowErrorDialog(ex, true) == DialogResult.Abort)
                {
                    throw new RTCV.NetCore.AbortEverythingException();
                }
            }
        }
        public static void CLOSE_GAME(bool loadDefault = false)
        {
            try
            {
                if (disableRTC)
                {
                    return;
                }

                if (CLOSE_GAME_loop_flag == true)
                {
                    return;
                }

                CLOSE_GAME_loop_flag = true;

                //RTC_Core.AutoCorrupt = false;

                StepActions.ClearStepBlastUnits();

                MemoryDomains.Clear();

                VanguardCore.OpenRomFilename = null;

                if (loadDefault)
                {
                    VanguardCore.LoadDefaultRom();
                }

                //RTC_RPC.SendToKillSwitch("UNFREEZE");

                CLOSE_GAME_loop_flag = false;
            }
            catch (Exception ex)
            {
                if (VanguardCore.ShowErrorDialog(ex) == DialogResult.Abort)
                {
                    throw new RTCV.NetCore.AbortEverythingException();
                }
            }
        }
        public static void StartClient()
        {
            try
            {
                ConsoleEx.WriteLine("Starting Vanguard Client");
                Thread.Sleep(500);                 //When starting in Multiple Startup Project, the first try will be uncessful since
                //the server takes a bit more time to start then the client.

                var spec = new NetCoreReceiver();
                spec.Attached         = VanguardCore.attached;
                spec.MessageReceived += OnMessageReceived;

                connector = new RTCV.Vanguard.VanguardConnector(spec);
            }
            catch (Exception ex)
            {
                if (VanguardCore.ShowErrorDialog(ex, true) == DialogResult.Abort)
                {
                    throw new RTCV.NetCore.AbortEverythingException();
                }
            }
        }
        public static void LOAD_GAME_BEGIN()
        {
            try
            {
                if (disableRTC)
                {
                    return;
                }

                isNormalAdvance = false;

                StepActions.ClearStepBlastUnits();
                CPU_STEP_Count = 0;
            }
            catch (Exception ex)
            {
                if (VanguardCore.ShowErrorDialog(ex) == DialogResult.Abort)
                {
                    throw new RTCV.NetCore.AbortEverythingException();
                }
            }
        }
        private static void OnMessageReceived(object sender, NetCoreEventArgs e)
        {
            try
            {
                // This is where you implement interaction.
                // Warning: Any error thrown in here will be caught by NetCore and handled by being displayed in the console.

                var message         = e.message;
                var simpleMessage   = message as NetCoreSimpleMessage;
                var advancedMessage = message as NetCoreAdvancedMessage;

                ConsoleEx.WriteLine(message.Type);
                switch (message.Type)                 //Handle received messages here
                {
                case "INFINITELOOP":
                    SyncObjectSingleton.FormExecute((o, ea) =>
                    {
                        while (true)
                        {
                            Thread.Sleep(10);
                        }
                    });
                    break;


                case REMOTE_ALLSPECSSENT:
                    SyncObjectSingleton.FormExecute((o, ea) =>
                    {
                        VanguardCore.LoadDefaultRom();
                        Program.SpecsSent = true;
                    });
                    break;

                case SAVESAVESTATE:
                    SyncObjectSingleton.FormExecute((o, ea) =>
                    {
                        e.setReturnValue(VanguardCore.SaveSavestate_NET(advancedMessage.objectValue as string));
                    });
                    break;

                case LOADSAVESTATE:
                {
                    var cmd      = advancedMessage.objectValue as object[];
                    var path     = cmd[0] as string;
                    var location = (StashKeySavestateLocation)cmd[1];
                    SyncObjectSingleton.FormExecute((o, ea) =>
                        {
                            e.setReturnValue(VanguardCore.LoadSavestate_NET(path, location));
                        });
                    break;
                }

                case REMOTE_LOADROM:
                {
                    var fileName = advancedMessage.objectValue as String;
                    SyncObjectSingleton.FormExecute((o, ea) =>
                        {
                            VanguardCore.LoadRom_NET(fileName);
                        });
                }
                break;

                case REMOTE_DOMAIN_GETDOMAINS:
                    SyncObjectSingleton.FormExecute((o, ea) =>
                    {
                        e.setReturnValue(Hooks.GetInterfaces());
                    });
                    break;

                case REMOTE_KEY_SETSYNCSETTINGS:
                    SyncObjectSingleton.FormExecute((o, ea) =>
                    {
                        Hooks.EMU_GETSET_SYNCSETTINGS = (string)advancedMessage.objectValue;
                    });
                    break;

                case REMOTE_KEY_SETSYSTEMCORE:
                {
                    var cmd        = advancedMessage.objectValue as object[];
                    var systemName = (string)cmd[0];
                    var systemCore = (string)cmd[1];
                    SyncObjectSingleton.FormExecute((o, ea) =>
                        {
                            Hooks.EMU_SET_SYSTEMCORE(systemName, systemCore);
                        });
                }
                break;

                case EMU_OPEN_HEXEDITOR_ADDRESS:
                {
                    var    temp    = advancedMessage.objectValue as object[];
                    string domain  = (string)temp[0];
                    long   address = (long)temp[1];

                    MemoryDomainProxy mdp = MemoryDomains.GetProxy(domain, address);
                    long realAddress      = MemoryDomains.GetRealAddress(domain, address);

                    SyncObjectSingleton.FormExecute((o, ea) =>
                        {
                            Hooks.EMU_OPEN_HEXEDITOR_ADDRESS(mdp, realAddress);
                        });

                    break;
                }

                case REMOTE_EVENT_EMU_MAINFORM_CLOSE:
                    SyncObjectSingleton.FormExecute((o, ea) =>
                    {
                        Hooks.EMU_MAINFORM_CLOSE();
                    });
                    break;

                case REMOTE_EVENT_SAVEBIZHAWKCONFIG:
                    SyncObjectSingleton.FormExecute((o, ea) =>
                    {
                        Hooks.EMU_MAINFORM_SAVECONFIG();
                    });
                    break;


                case REMOTE_IMPORTKEYBINDS:
                    SyncObjectSingleton.FormExecute((o, ea) =>
                    {
                        Hooks.EMU_IMPORTCONFIGINI(CorruptCore.bizhawkDir + Path.DirectorySeparatorChar + "import_config.ini", CorruptCore.bizhawkDir + Path.DirectorySeparatorChar + "stockpile_config.ini");
                    });
                    break;

                case REMOTE_MERGECONFIG:
                    SyncObjectSingleton.FormExecute((o, ea) =>
                    {
                        Hooks.EMU_MERGECONFIGINI(CorruptCore.bizhawkDir + Path.DirectorySeparatorChar + "backup_config.ini", CorruptCore.bizhawkDir + Path.DirectorySeparatorChar + "stockpile_config.ini");
                    });
                    break;

                case REMOTE_RESTOREBIZHAWKCONFIG:
                    SyncObjectSingleton.FormExecute((o, ea) =>
                    {
                        Process.Start(CorruptCore.bizhawkDir + Path.DirectorySeparatorChar + $"RestoreConfigDETACHED.bat");
                    });
                    break;

                case REMOTE_ISNORMALADVANCE:
                    e.setReturnValue(Hooks.isNormalAdvance);
                    break;
                }
            }
            catch (Exception ex)
            {
                if (VanguardCore.ShowErrorDialog(ex, true) == DialogResult.Abort)
                {
                    throw new RTCV.NetCore.AbortEverythingException();
                }
            }
        }