Пример #1
0
 public BlockID()
 {
     StatMaster.SelectedBlockChanged += (id) =>
     {
         try
         {
             PluginManager.Instance.UpdateDataAndUI(
                 this,
                 new XDataHolderFactory()
             {
                 { "BlockID", (int)id }
             }.Create()
                 );
         }
         catch (Exception e)
         {
             ModConsole.Log(
                 "Failed to update UI of BlockID:\n" +
                 "BlockID: {0}\n" +
                 "Exception: {1}",
                 id,
                 e
                 );
         }
     };
 }
Пример #2
0
        private void Update()
        {
            var pluginQueue =
                new List <KeyValuePair <Plugin, bool> >(_pluginQueue);

            _pluginQueue.Clear();
            foreach (var pair in pluginQueue)
            {
                try
                {
                    if (pair.Value)
                    {
                        RegisterInternal(pair.Key);
                    }
                    else
                    {
                        UnRegisterInternal(pair.Key);
                    }
                }
                catch (Exception e)
                {
                    ModConsole.Log(
                        "Failed to load plugin {0} ({1}):\n{2}",
                        pair.Key.Name,
                        pair.Key.Key,
                        e
                        );
                }
            }

            var manager = UIManager.Instance;

            foreach (var data in _plugins)
            {
                manager.AddInterface(
                    data.UIContainer
                    );

                if (!data.Plugin.Enabled)
                {
                    data.ValueInfo.WasApplied = false;
                    continue;
                }
                var rule = (ApplyRule)(
                    (int)data.Plugin.ApplyRule % (int)ApplyRule.NoEnable
                    );
                if (
                    (rule == ApplyRule.Constant) ||
                    (rule == ApplyRule.OnApply && data.ValueInfo.WasApplied) ||
                    (rule == ApplyRule.OnChange && data.ValueInfo.ValueChanged)
                    )
                {
                    data.ValueInfo.ValueChanged = false;
                    data.Plugin.Apply(data.Input);
                }
                data.ValueInfo.WasApplied = false;
            }
        }
Пример #3
0
 void WrongArgumentWarning(string reason, string fileName, int lines, string content)
 {
     ModConsole.Log($"\n=================================" +
                    $"\n\n<color=cyan>[MOP] {reason}.\n\n" +
                    $"File: {fileName}\n" +
                    $"Line: {lines}\n" +
                    $"Context: {content}\n\n" +
                    $"You can ignore that message.</color>");
 }
Пример #4
0
 void ObsoleteWarning(string flag, string fileName, int lines, string content, string alternative)
 {
     ModConsole.Log($"\n=================================" +
                    $"\n\n<color=cyan>[MOP] Flag '{flag}' is obsolete.\n" +
                    $"Please use '{alternative}' instead!\n\n" +
                    $"File: {fileName}\n" +
                    $"Line: {lines}\n" +
                    $"Context: {content}\n\n" +
                    $"You can ignore that message.</color>");
 }
Пример #5
0
        public override void OnSimulateStart()
        {
            printCount    = 0;
            lastPrint     = Time.time;
            lastError     = 0;
            PrevState     = PIO.ToDictionary(x => x.Key, x => false);
            TriggerValues = PIO.ToDictionary(x => x.Key, x => 0.0f);
            TriggetMode   = PIO.ToDictionary(x => x.Key, x => 0);
            timeoutId     = 1;
            Timeouts      = new Dictionary <long, float>();

            var script = new JavaScriptParser(Script.Value, Jint.Engine.DefaultParserOptions).ParseScript();

            //Interp.SetValue("print", PrintCb);
            //engine.SetValue("irqv", irqv);
            Interp.SetScript(script);
            Interp.Executor.OnLog           = (x) => ModConsole.Log(x?.ToString());
            Interp.Executor.OnNextStatement = () =>
            {
                if (!InterruptsEnabled)
                {
                    return;
                }

                Cli();
                try
                {
                    while (Interrupts.Count > 0)
                    {
                        var irq = Interrupts.Dequeue();
                        if (InterruptHandlers.ContainsKey(irq))
                        {
                            var args = InterruptArgs.ContainsKey(irq) ? InterruptArgs[irq] : new object[] { irq };
                            InterruptArgs.Remove(irq);
                            try
                            {
                                Interp.Invoke(InterruptHandlers[irq], args);
                            }
                            catch (JavaScriptException e)
                            {
                                Interp.Executor.PauseThread((d) => OnCoreException(irq, e), null);
                            }
                            Interp.Executor.PauseThread((d) => AfterInterrupt(irq), null);
                        }
                    }
                }
                finally
                {
                    Sti();
                }
            };
            SingleInstance <Api.CpuApi> .Instance.Attach(this);
        }
Пример #6
0
        private void ScaleBlock(Block block)
        {
            var blockBehaviour =
                block.GameObject.GetComponent <BlockBehaviour>();

            if (blockBehaviour == null)
            {
                ModConsole.Log($"BlockBehaviour Was missing from {block}!");
                return;
            }
            blockBehaviour.SetScale(_scale);
        }
Пример #7
0
        public void Initialize(bool overrideUpdateCheck)
        {
            lastModListPath          = $"{MOP.ModConfigPath}/LastModList.mop";
            lastDateFilePath         = $"{MOP.ModConfigPath}/LastUpdate.mop";
            this.overrideUpdateCheck = overrideUpdateCheck;

            if (GameObject.Find("MOP_Messager") != null)
            {
                message = GameObject.Find("MOP_Messager").GetComponent <TextMesh>();
                shadow  = message.gameObject.transform.GetChild(0).gameObject.GetComponent <TextMesh>();
            }
            else
            {
                float div = (float)Screen.width / (float)Screen.height;
                float x   = div < 1.3f ? 4f : div < 1.6f ? 4.5f : 6f;

                GameObject text = GameObject.Instantiate(GameObject.Find("Interface/Songs/Text"));
                text.transform.localPosition = new Vector3(x, 2.6f, 0.01f);
                text.name         = "MOP_Messager";
                message           = text.GetComponent <TextMesh>();
                message.alignment = TextAlignment.Right;
                message.anchor    = TextAnchor.UpperRight;
                shadow            = text.transform.GetChild(0).gameObject.GetComponent <TextMesh>();
                shadow.alignment  = TextAlignment.Right;
                shadow.anchor     = TextAnchor.UpperRight;
                NewMessage("");
            }

            if (!MOP.RulesAutoUpdate.Value && !overrideUpdateCheck)
            {
                ModConsole.Log("<color=orange>[MOP] Rule files auto update is disabled.</color>");
                GetAndReadRules();
                return;
            }

            // Don't check if the server is online, if the update check has been done already.
            if (RulesManager.Instance.UpdateChecked)
            {
                GetAndReadRules();
                return;
            }

            // If server or user is offline, skip downloading and simply load available files.
            if (!IsServerOnline())
            {
                ModConsole.Log("<color=red>[MOP] Connection error. Check your Internet connection.</color>");
                GetAndReadRules();
                return;
            }

            StartCoroutine(DownloadAndUpdateRoutine());
        }
Пример #8
0
        // メソッド
        // ステージ(バレンエクスパンスなど)に初めて入った時にmodがロードされ、同時にOnLoad()が呼び出される。
        public override void OnLoad()
        {
            // コンソールに「Hello World!」と表示させる。
            ModConsole.Log("Hello World!");

            // modゲームオブジェクトを初期化し、GUI等で使うクラスのインスタンスを子に指定する。
            mod = new GameObject("WikiTutorialController");
            SingleInstance <Gui> .Instance.transform.parent           = mod.transform;
            SingleInstance <BlockSelector> .Instance.transform.parent = mod.transform;

            // シーンをまたいでもmodが消されないようにする。
            UnityEngine.Object.DontDestroyOnLoad(mod);
        }
Пример #9
0
        /// <summary>
        /// This void is initialized before the player decides to save the game.
        /// </summary>
        void PreSaveGame()
        {
            ModConsole.Log("[MOP] Initializing Pre-Save Actions...");
            SaveManager.ReleaseSave();
            MopSettings.IsModActive = false;
            StopCoroutine(currentLoop);
            StopCoroutine(currentControlCoroutine);

            SaveManager.RemoveReadOnlyAttribute();
            ItemsManager.Instance.OnSave();

            ToggleAll(true, ToggleAllMode.OnSave);
            ModConsole.Log("[MOP] Pre-Save Actions Completed!");
        }
Пример #10
0
 public void Print()
 {
     ModConsole.Log("===============");
     ModConsole.Log("Name = " + Name);
     ModConsole.Log("Comp = " + Comp);
     ModConsole.Log("Guid = " + Guid);
     ModConsole.Log("---------------");
     ModConsole.Log("Type".PadRight(16) + " | " + "Key".PadRight(32) + " | " + "DisplayName");
     foreach (var mt in _block.InternalObject.MapperTypes)
     {
         ModConsole.Log(mt.GetType().Name.PadRight(16) + " | " + mt.Key.PadRight(32) + " | " + mt.DisplayName);
     }
     ModConsole.Log("===============");
 }
Пример #11
0
 public void SaveAll()
 {
     ModConsole.Log("Saving PBP4 Plugins..");
     foreach (var pluginData in _plugins)
     {
         try
         {
             Save(pluginData);
         }
         catch (Exception e)
         {
             ModConsole.Log("Failed to save \"{0}\":\n{1}", pluginData.Name, e);
         }
     }
     Configuration.Save();
 }
Пример #12
0
 private void ReloadAll()
 {
     //Tell modloader to reload configuration here
     for (int i = 0; i < _plugins.Count; i++)
     {
         try
         {
             var data = _plugins[i];
             data.Input  = Load(_plugins[i].Plugin);
             _plugins[i] = data;
         }
         catch (Exception e)
         {
             ModConsole.Log("Failed to reload plugin \"{0}\":\n{1}", _plugins[i].Name, e);
         }
     }
 }
Пример #13
0
        void PrintAntennaList()
        {
            string info = "";

            foreach (int i in legalBlocks)
            {
                var prefab   = Modding.Blocks.BlockPrefabInfo.FromId(i);
                var rigibody = prefab.InternalObject.gameObject.GetComponent <Rigidbody>();
                info += i.ToString() + " " + prefab.Name + " mass:" + rigibody.mass + "\n";
            }
            ModConsole.Log(info);

            /*var blockPrefabInfo = BlockPrefabInfo.FromId(0);
             * StringBuilder sb = new StringBuilder("");
             * printGo(blockPrefabInfo.InternalObject.gameObject, sb);
             * TextWriter tw = ModIO.CreateText("treeOutput.txt");
             * tw.Write(sb.ToString());
             * tw.Close();*/
        }
Пример #14
0
        /// <summary>
        /// Dumps the info about the mod and lists all installed mods into MOP_REPORT.txt
        /// </summary>
        public static void GenerateReport()
        {
            string gameInfo = GetGameInfo();

            int reportsInFolder = 0;

            while (File.Exists($"{LogFolder}/{DefaultReportLogName}_{reportsInFolder}.txt"))
            {
                reportsInFolder++;
            }

            string path = $"{LogFolder}/{DefaultReportLogName}_{reportsInFolder}.txt";

            using (StreamWriter sw = new StreamWriter(path))
            {
                sw.Write(gameInfo);
                sw.Close();
                sw.Dispose();
            }

            ModConsole.Log("[MOP] Mod report has been successfully generated.");
            Process.Start(path);
        }
Пример #15
0
        void Initialize()
        {
            instance = this;

            ModConsole.Log("[MOP] Loading MOP...");

            // Initialize the worldObjectManager list
            worldObjectManager = new WorldObjectManager();

            // Looking for player and yard
            player = GameObject.Find("PLAYER").transform;

            // Add GameFixes MonoBehaviour.
            try
            {
                gameObject.AddComponent <GameFixes>();
            }
            catch (Exception ex)
            {
                ExceptionManager.New(ex, false, $"GAME_FIXES_INITIALIZAITON | {ex}");
            }

            // Loading vehicles
            vehicleManager = new VehicleManager();

            // World Objects
            try
            {
                worldObjectManager.Add("CABIN", DisableOn.Distance | DisableOn.IgnoreInQualityMode);
                worldObjectManager.Add("COTTAGE", DisableOn.Distance, 400);
                worldObjectManager.Add("DANCEHALL", DisableOn.Distance, 500);
                worldObjectManager.Add("PERAJARVI", DisableOn.Distance | DisableOn.IgnoreInQualityMode, 400);
                worldObjectManager.Add("SOCCER", DisableOn.Distance);
                worldObjectManager.Add("WATERFACILITY", DisableOn.Distance, 300);
                worldObjectManager.Add("DRAGRACE", DisableOn.Distance, 1100);
                worldObjectManager.Add("StrawberryField", DisableOn.Distance, 400);
                worldObjectManager.Add("MAP/Buildings/DINGONBIISI", DisableOn.Distance, 400);
                worldObjectManager.Add("RALLY/PartsSalesman", DisableOn.Distance, 400);
                worldObjectManager.Add("LakeSmallBottom1", DisableOn.Distance, 500);
                worldObjectManager.Add("machine", DisableOn.Distance, 200, silent: true);

                ModConsole.Log("[MOP] World objects (1) loaded");
            }
            catch (Exception ex)
            {
                ExceptionManager.New(ex, false, "WORLD_OBJECTS_1_INITIALIZAITON_FAIL");
            }

            // Initialize places.
            placeManager = new PlaceManager();

            // Fixes
            GameFixes.Instance.MainFixes();

            //Things that should be enabled when out of proximity of the house
            try
            {
                worldObjectManager.Add("NPC_CARS", DisableOn.PlayerInHome);
                worldObjectManager.Add("TRAFFIC", DisableOn.PlayerInHome);
                worldObjectManager.Add("TRAIN", DisableOn.PlayerInHome | DisableOn.IgnoreInQualityMode);
                worldObjectManager.Add("Buildings", DisableOn.PlayerInHome);
                worldObjectManager.Add("TrafficSigns", DisableOn.PlayerInHome);
                worldObjectManager.Add("StreetLights", DisableOn.PlayerInHome);
                worldObjectManager.Add("HUMANS", DisableOn.PlayerInHome);
                worldObjectManager.Add("TRACKFIELD", DisableOn.PlayerInHome);
                worldObjectManager.Add("SkijumpHill", DisableOn.PlayerInHome | DisableOn.IgnoreInQualityMode);
                worldObjectManager.Add("Factory", DisableOn.PlayerInHome);
                worldObjectManager.Add("WHEAT", DisableOn.PlayerInHome);
                worldObjectManager.Add("RAILROAD", DisableOn.PlayerInHome);
                worldObjectManager.Add("AIRPORT", DisableOn.PlayerInHome);
                worldObjectManager.Add("RAILROAD_TUNNEL", DisableOn.PlayerInHome);
                worldObjectManager.Add("PierDancehall", DisableOn.PlayerInHome);
                worldObjectManager.Add("PierRiver", DisableOn.PlayerInHome);
                worldObjectManager.Add("PierStore", DisableOn.PlayerInHome);
                worldObjectManager.Add("BRIDGE_dirt", DisableOn.PlayerInHome);
                worldObjectManager.Add("BRIDGE_highway", DisableOn.PlayerInHome);
                worldObjectManager.Add("BirdTower", DisableOn.Distance, 400);
                worldObjectManager.Add("RYKIPOHJA", DisableOn.PlayerInHome);
                worldObjectManager.Add("COMPUTER", DisableOn.PlayerAwayFromHome);

                ModConsole.Log("[MOP] World objects (2) loaded");
            }
            catch (Exception ex)
            {
                ExceptionManager.New(ex, false, "WORLD_OBJECTS_2_INITIALIZAITON_FAIL");
            }

            // Adding area check if Satsuma is in the inspection's area
            try
            {
                SatsumaInArea inspectionArea = GameObject.Find("INSPECTION").AddComponent <SatsumaInArea>();
                inspectionArea.Initialize(new Vector3(20, 20, 20));
            }
            catch (Exception ex)
            {
                ExceptionManager.New(ex, false, "SATSUMA_AREA_CHECK_INSPECTION_FAIL");
            }

            // Check for when Satsuma is on the lifter
            try
            {
                SatsumaInArea lifterArea = GameObject.Find("REPAIRSHOP/Lifter/Platform").AddComponent <SatsumaInArea>();
                lifterArea.Initialize(new Vector3(5, 5, 5));
            }
            catch (Exception ex)
            {
                ExceptionManager.New(ex, false, "SATSUMA_AREA_CHECK_REPAIRSHOP_FAIL");
            }

            // Area for the parc ferme.
            try
            {
                GameObject parcFermeTrigger = new GameObject("MOP_ParcFermeTrigger");
                parcFermeTrigger.transform.parent   = GameObject.Find("RALLY").transform.Find("Scenery");
                parcFermeTrigger.transform.position = new Vector3(-1383f, 3f, 1260f);
                SatsumaInArea parcFerme = parcFermeTrigger.AddComponent <SatsumaInArea>();
                parcFerme.Initialize(new Vector3(41, 12, 35));
            }
            catch (Exception ex)
            {
                ExceptionManager.New(ex, false, "PARC_FERME_TRIGGER_FAIL");
            }

            ModConsole.Log("[MOP] Satsuma triggers loaded");

            // Jokke's furnitures.
            // Only renderers are going to be toggled.
            try
            {
                if (GameObject.Find("tv(Clo01)"))
                {
                    string[] furnitures = { "tv(Clo01)",    "chair(Clo02)", "chair(Clo05)", "bench(Clo01)",
                                            "bench(Clo02)", "table(Clo02)", "table(Clo03)", "table(Clo04)",
                                            "table(Clo05)", "desk(Clo01)",  "arm chair(Clo01)" };

                    foreach (string furniture in furnitures)
                    {
                        GameObject g = GameObject.Find(furniture);
                        if (g)
                        {
                            g.transform.parent = null;
                            worldObjectManager.Add(g, DisableOn.Distance, 100, ToggleModes.Renderer);
                        }
                    }

                    ModConsole.Log("[MOP] Jokke's furnitures found and loaded");
                }
            }
            catch (Exception ex)
            {
                ExceptionManager.New(ex, false, "JOKKE_FURNITURE_ERROR");
            }

            // Haybales.
            // First we null out the prevent it from reloading the position of haybales.
            try
            {
                GameObject haybalesParent = GameObject.Find("JOBS/HayBales");
                if (haybalesParent != null)
                {
                    haybalesParent.GetComponent <PlayMakerFSM>().Fsm.RestartOnEnable = false;
                    // And now we add all child haybale to world objects.
                    foreach (Transform haybale in haybalesParent.transform.GetComponentInChildren <Transform>())
                    {
                        worldObjectManager.Add(haybale.gameObject.name, DisableOn.Distance | DisableOn.IgnoreInQualityMode, 120);
                    }
                }
            }
            catch (Exception ex)
            {
                ExceptionManager.New(ex, false, "HAYBALES_FIX_ERROR");
            }

            // Logwalls
            try
            {
                foreach (GameObject wall in Resources.FindObjectsOfTypeAll <GameObject>().Where(g => g.name == "LogwallLarge"))
                {
                    worldObjectManager.Add(wall, DisableOn.Distance, 300);
                }
            }
            catch (Exception ex)
            {
                ExceptionManager.New(ex, false, "LOGWALL_LOAD_ERROR");
            }

            // Perajarvi Church.
            try
            {
                if (MopSettings.Mode != PerformanceMode.Performance)
                {
                    GameObject church = GameObject.Find("PERAJARVI").transform.Find("CHURCH").gameObject;
                    church.transform.parent = null;
                    GameObject churchLOD = church.transform.Find("LOD").gameObject;
                    church.GetComponent <PlayMakerFSM>().enabled = false;
                    worldObjectManager.Add(churchLOD, DisableOn.Distance, 300);
                }
            }
            catch (Exception ex)
            {
                ExceptionManager.New(ex, false, "CHURCH_LOD_ERROR");
            }

            // Lake houses.
            try
            {
                if (MopSettings.Mode == PerformanceMode.Quality)
                {
                    GameObject.Find("PERAJARVI").transform.Find("TerraceHouse").transform.parent = null;
                }
            }
            catch (Exception ex)
            {
                ExceptionManager.New(ex, false, "LAKE_HOUSE_ERROR");
            }

            // VehiclesHighway renderers.
            try
            {
                Transform vehiclesHighway = GameObject.Find("TRAFFIC").transform.Find("VehiclesHighway");
                foreach (var f in vehiclesHighway.GetComponentsInChildren <Transform>(true).Where(f => f.parent == vehiclesHighway))
                {
                    worldObjectManager.Add(f.gameObject, DisableOn.Distance, 600, ToggleModes.MultipleRenderers);
                }

                // Also we gonna fix the lag on initial traffic load.
                vehiclesHighway.gameObject.SetActive(true);
            }
            catch (Exception ex)
            {
                ExceptionManager.New(ex, false, "TRAFFIC_VEHICLES_ERROR");
            }

            // FITTAN renderers.
            try
            {
                worldObjectManager.Add(GameObject.Find("TRAFFIC").transform.Find("VehiclesDirtRoad/Rally/FITTAN").gameObject, DisableOn.Distance, 600, ToggleModes.MultipleRenderers);
            }
            catch (Exception ex)
            {
                ExceptionManager.New(ex, false, "FITTAN_RENDERERS_ERROR");
            }

            // Initialize Items class
            try
            {
                new ItemsManager();
                ItemsManager.Instance.Initialize();
                ModConsole.Log("[MOP] Items class initialized");
            }
            catch (Exception ex)
            {
                ExceptionManager.New(ex, true, "ITEMS_CLASS_ERROR");
            }

            try
            {
                DateTime now = DateTime.Now;
                if (now.Day == 1 && now.Month == 4)
                {
                    GameObject     fpsObject = GameObject.Find("GUI").transform.Find("HUD/FPS/HUDValue").gameObject;
                    PlayMakerFSM[] fsms      = fpsObject.GetComponents <PlayMakerFSM>();
                    foreach (var fsm in fsms)
                    {
                        fsm.enabled = false;
                    }
                    fpsObject.GetComponent <TextMesh>().text = "99999999 :)";
                    fpsObject.transform.Find("HUDValueShadow").GetComponent <TextMesh>().text = "99999999 :)";
                }
            }
            catch { }

            HookPreSaveGame();

            ModConsole.Log("[MOP] Loading rules...");
            foreach (ToggleRule v in RulesManager.Instance.ToggleRules)
            {
                try
                {
                    switch (v.ToggleMode)
                    {
                    default:
                        ModConsole.LogError($"[MOP] Unrecognized toggle mode for {v.ObjectName}: {v.ToggleMode}.");
                        break;

                    case ToggleModes.Simple:
                        if (GameObject.Find(v.ObjectName) == null)
                        {
                            ModConsole.LogError($"[MOP] Couldn't find world object {v.ObjectName}");
                            continue;
                        }

                        worldObjectManager.Add(v.ObjectName, DisableOn.Distance);
                        break;

                    case ToggleModes.Renderer:
                        if (GameObject.Find(v.ObjectName) == null)
                        {
                            ModConsole.LogError($"[MOP] Couldn't find world object {v.ObjectName}");
                            continue;
                        }

                        worldObjectManager.Add(v.ObjectName, DisableOn.Distance, 200, ToggleModes.Renderer);
                        break;

                    case ToggleModes.Item:
                        GameObject g = GameObject.Find(v.ObjectName);

                        if (g == null)
                        {
                            ModConsole.LogError($"[MOP] Couldn't find item {v.ObjectName}");
                            continue;
                        }

                        if (g.GetComponent <ItemBehaviour>() == null)
                        {
                            g.AddComponent <ItemBehaviour>();
                        }
                        break;

                    case ToggleModes.Vehicle:
                        if (RulesManager.Instance.SpecialRules.IgnoreModVehicles)
                        {
                            continue;
                        }

                        if (GameObject.Find(v.ObjectName) == null)
                        {
                            ModConsole.LogError($"[MOP] Couldn't find vehicle {v.ObjectName}");
                            continue;
                        }

                        vehicleManager.Add(new Vehicle(v.ObjectName));
                        break;

                    case ToggleModes.VehiclePhysics:
                        if (RulesManager.Instance.SpecialRules.IgnoreModVehicles)
                        {
                            continue;
                        }

                        if (GameObject.Find(v.ObjectName) == null)
                        {
                            ModConsole.LogError($"[MOP] Couldn't find vehicle {v.ObjectName}");
                            continue;
                        }
                        vehicleManager.Add(new Vehicle(v.ObjectName));
                        Vehicle veh = vehicleManager[vehicleManager.Count - 1];
                        veh.Toggle = veh.ToggleUnityCar;
                        break;
                    }
                }
                catch (Exception ex)
                {
                    ExceptionManager.New(ex, false, "TOGGLE_RULES_LOAD_ERROR");
                }
            }

            ModConsole.Log("[MOP] Rules loading complete!");

            // Initialzie sector manager
            try
            {
                gameObject.AddComponent <SectorManager>();
            }
            catch (Exception ex)
            {
                ExceptionManager.New(ex, true, "SECTOR_MANAGER_ERROR");
            }

            // Add DynamicDrawDistance component.
            try
            {
                gameObject.AddComponent <DynamicDrawDistance>();
            }
            catch (Exception ex)
            {
                ExceptionManager.New(ex, false, "DYNAMIC_DRAW_DISTANCE_ERROR");
            }

            try
            {
                if (MopSettings.Mode != PerformanceMode.Safe)
                {
                    ToggleAll(false, ToggleAllMode.OnLoad);
                }
            }
            catch (Exception ex)
            {
                ExceptionManager.New(ex, true, "TOGGLE_ALL_ERROR");
            }

            // Initialize the coroutines.
            currentLoop = LoopRoutine();
            StartCoroutine(currentLoop);
            currentControlCoroutine = ControlCoroutine();
            StartCoroutine(currentControlCoroutine);

            ModConsole.Log("<color=green>[MOP] MOD LOADED SUCCESFULLY!</color>");
            Resources.UnloadUnusedAssets();
            GC.Collect();

            // If generate-list command is set to true, generate the list of items that are disabled by MOP.
            if (MopSettings.GenerateToggledItemsListDebug)
            {
                if (System.IO.File.Exists("world.txt"))
                {
                    System.IO.File.Delete("world.txt");
                }
                string world = "";
                foreach (var w in worldObjectManager.GetList())
                {
                    if (world.Contains(w.GetName()))
                    {
                        continue;
                    }
                    world += w.GetName() + ", ";
                }
                System.IO.File.WriteAllText("world.txt", world);
                System.Diagnostics.Process.Start("world.txt");

                if (System.IO.File.Exists("vehicle.txt"))
                {
                    System.IO.File.Delete("vehicle.txt");
                }
                string vehiclez = "";
                foreach (var w in vehicleManager.List())
                {
                    vehiclez += w.gameObject.name + ", ";
                }
                System.IO.File.WriteAllText("vehicle.txt", vehiclez);
                System.Diagnostics.Process.Start("vehicle.txt");

                if (System.IO.File.Exists("items.txt"))
                {
                    System.IO.File.Delete("items.txt");
                }
                string items = "";
                foreach (var w in ItemsManager.Instance.All())
                {
                    if (items.Contains(w.gameObject.name))
                    {
                        continue;
                    }
                    items += w.gameObject.name + ", ";
                }
                System.IO.File.WriteAllText("items.txt", items);
                System.Diagnostics.Process.Start("items.txt");

                if (System.IO.File.Exists("place.txt"))
                {
                    System.IO.File.Delete("place.txt");
                }
                string place = "";
                foreach (var w in placeManager.GetList())
                {
                    place += w.GetName() + ": ";
                    foreach (var f in w.GetDisableableChilds())
                    {
                        if (place.Contains(f.gameObject.name))
                        {
                            continue;
                        }
                        place += f.gameObject.name + ", ";
                    }

                    place += "\n\n";
                }
                System.IO.File.WriteAllText("place.txt", place);
                System.Diagnostics.Process.Start("place.txt");
            }
        }
Пример #16
0
        public override void Run(string[] args)
        {
            if (args.Length == 0)
            {
                ModConsole.Log("See \"mop help\" for command list.");
                return;
            }

            switch (args[0])
            {
            default:
                ModConsole.Log("Invalid command. Type \"mop help\" for command list.");
                break;

            case "help":
                if (args.Length > 1)
                {
                    string[] helpList      = HelpList.Split('\n');
                    bool     commandsFound = false;
                    foreach (string s in helpList)
                    {
                        if (s.Split('-')[0].Contains(args[1]))
                        {
                            ModConsole.Log(s);
                            commandsFound = true;
                        }
                    }
                    if (!commandsFound)
                    {
                        ModConsole.Log($"Command {args[1]} not found.");
                    }
                    return;
                }
                ModConsole.Log(HelpList);
                break;

            case "rules":
                if (args.Length > 1 && args[1] == "roll")
                {
                    ModConsole.Log("\n<color=yellow>You know the rules and so do I\n" +
                                   "A full commitment's what I'm thinking of\n" +
                                   "You wouldn't get this from any other guy\n" +
                                   "I just wanna tell you how I'm feeling\n" +
                                   "Gotta make you understand\n" +
                                   "Never gonna give you up\n" +
                                   "Never gonna let you down\n" +
                                   "Never gonna run around and desert you\n" +
                                   "Never gonna make you cry\n" +
                                   "Never gonna say goodbye\n" +
                                   "Never gonna tell a lie and hurt you</color>\n\n");
                    return;
                }

                if (RulesManager.Instance.IgnoreRules.Count > 0)
                {
                    ModConsole.Log("<color=yellow><b>Ignore Rules</b></color>");
                    foreach (IgnoreRule r in RulesManager.Instance.IgnoreRules)
                    {
                        ModConsole.Log($"<b>Object:</b> {r.ObjectName}");
                    }
                }

                if (RulesManager.Instance.IgnoreRulesAtPlaces.Count > 0)
                {
                    ModConsole.Log("\n<color=yellow><b>Ignore Rules At Place</b></color>");
                    foreach (IgnoreRuleAtPlace r in RulesManager.Instance.IgnoreRulesAtPlaces)
                    {
                        ModConsole.Log($"<b>Place:</b> {r.Place} <b>Object:</b> {r.ObjectName}");
                    }
                }

                if (RulesManager.Instance.ToggleRules.Count > 0)
                {
                    ModConsole.Log("\n<color=yellow><b>Toggle Rules</b></color>");
                    foreach (ToggleRule r in RulesManager.Instance.ToggleRules)
                    {
                        ModConsole.Log($"<b>Object:</b> {r.ObjectName} <b>Toggle Mode:</b> {r.ToggleMode}");
                    }
                }

                if (RulesManager.Instance.NewSectors.Count > 0)
                {
                    ModConsole.Log("\n<color=yellow><b>New Sectors</b></color>");
                    foreach (NewSector r in RulesManager.Instance.NewSectors)
                    {
                        ModConsole.Log($"<b>Pos:</b> {r.Position} <b>Scale:</b> {r.Scale} <b>Rot:</b> {r.Rotation} <b>Ignore:</b> {string.Join(", ", r.Whitelist)}");
                    }
                }

                ModConsole.Log("\n<color=yellow><b>Special Rules</b></color>");
                // Obtain all fields
                FieldInfo[] fields = typeof(SpecialRules).GetFields();
                // Loop through fields
                foreach (var field in fields)
                {
                    ModConsole.Log($"<b>{field.Name}</b>: {field.GetValue(RulesManager.Instance.SpecialRules)}");
                }

                // List rule files.
                string output = "\n<color=yellow><b>Rule Files</b></color>\n";
                foreach (string ruleFile in RulesManager.Instance.RuleFileNames)
                {
                    output += $"{ruleFile}\n";
                }

                ModConsole.Log(output);
                break;

            case "reload":
                if (ModLoader.CurrentScene != CurrentScene.MainMenu)
                {
                    ModConsole.Log("You can only reload rule files in the main menu");
                    return;
                }

                RulesManager.Instance.WipeAll(false);
                break;

            case "new":
                string path = $"{MOP.ModConfigPath}/Custom.txt";

                if (args.Length > 1)
                {
                    path = $"{MOP.ModConfigPath}/{args[1]}.mopconfig";
                }

                if (File.Exists(path))
                {
                    ModConsole.Log("Custom file already exists. Use \"mop open\" to edit it now.");
                    return;
                }

                File.WriteAllText(path, "## Every line which starts with ## will be ignored.\n" +
                                  "## All new flags MUST be written in a new line.\n" +
                                  "## Visit http://athlon.kkmr.pl/mop/wiki/#/rulefiles_commands for documentation.\n" +
                                  "## WARNING: Using custom rule files may cause issues. Use only at your own risk!");

                Process.Start(path);
                if (path.EndsWith("Custom.txt"))
                {
                    ModConsole.Log("A custom rule file has been created. You can find it as Custom.txt.\n" +
                                   "<color=red>Careless use of rule files may cause bugs and glitchess. Use only at yout own risk!</color>");
                }
                else
                {
                    ModConsole.Log($"A rule file for {args[1]} mod has been created.");
                }
                break;

            case "version":
                ModConsole.Log(MOP.ModVersion);
                break;

            case "cowsay":
                string say = string.Join(" ", args, 1, args.Length - 1);

                switch (say.ToLower())
                {
                case "tell me your secrets":
                    say = "all pls fix and no appreciation makes Athlon an angry boy";
                    break;

                case "tell me your wisdoms":
                    say = "people saying that MOP is just improved KruFPS are straight up wrong";
                    break;

                case "wieski":
                    say = "it really do be like dat doe sometimes";
                    break;

                case "embu":
                    say = "pee vee good";
                    break;

                case "owo":
                    say = "UwU";
                    break;

                case "uwu":
                    say = "OwO";
                    break;

                case "mop sucks":
                    say = "no u";
                    Process.Start("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
                    break;
                }

                ModConsole.Log($"< {say} >\n" +
                               "        \\   ^__^\n" +
                               "         \\  (oo)\\____\n" +
                               "            (__)\\          )\\/\\\n" +
                               "                ||  ----w  |\n" +
                               "                ||           || ");
                break;

            case "open-config":
                Process.Start(MOP.ModConfigPath);
                break;

            case "open":
                if (args.Length == 1)
                {
                    ModConsole.Log($"Missing argument.");
                    return;
                }

                if (args[1].StartsWith("Custom") || args[1].StartsWith("custom"))
                {
                    if (!args[1].EndsWith(".txt"))
                    {
                        args[1] += ".txt";
                    }
                }
                else
                {
                    if (!args[1].EndsWith(".mopconfig"))
                    {
                        args[1] += ".mopconfig";
                    }
                }

                if (!File.Exists($"{MOP.ModConfigPath}/{args[1]}"))
                {
                    ModConsole.Log($"File {args[1]} doesn't exist.");
                    return;
                }

                Process.Start($"{MOP.ModConfigPath}/{args[1]}");
                break;

            case "delete":
                if (args.Length == 1)
                {
                    ModConsole.Log($"Missing argument.");
                    return;
                }

                if (args[1].StartsWith("Custom") && !args[1].EndsWith(".txt"))
                {
                    args[1] += ".txt";
                }
                else
                {
                    if (!args[1].EndsWith(".mopconfig"))
                    {
                        args[1] += ".mopconfig";
                    }
                }

                if (!File.Exists($"{MOP.ModConfigPath}/{args[1]}"))
                {
                    ModConsole.Log($"File {args[1]} doesn't exist.");
                    return;
                }

                File.Delete($"{MOP.ModConfigPath}/{args[1]}");
                break;

            case "cat":
                if (args.Length == 1)
                {
                    ModConsole.Log($"Missing argument.");
                    return;
                }

                if (args[1].StartsWith("Custom") && !args[1].EndsWith(".txt"))
                {
                    args[1] += ".txt";
                }
                else
                {
                    if (!args[1].EndsWith(".mopconfig"))
                    {
                        args[1] += ".mopconfig";
                    }
                }

                if (!File.Exists($"{MOP.ModConfigPath}/{args[1]}"))
                {
                    ModConsole.Log($"File {args[1]} doesn't exist.");
                    return;
                }

                ModConsole.Log(File.ReadAllText($"{MOP.ModConfigPath}/{args[1]}"));
                break;

            case "generate-list":
                if (args.Length > 1)
                {
                    if (RulesManager.Instance.LoadRules &&
                        (RulesManager.Instance.IgnoreRules.Count > 0 || RulesManager.Instance.IgnoreRulesAtPlaces.Count > 0 ||
                         RulesManager.Instance.NewSectors.Count > 0 || RulesManager.Instance.ToggleRules.Count > 0)
                        )
                    {
                        ModConsole.Log("<color=red>WARNING:</color> For accurate results, use \"mop load-rules false\" to prevent MOP from using rule files.");
                    }

                    MopSettings.GenerateToggledItemsListDebug = args[1].ToLower() == "true";
                }

                ModConsole.Log($"Generating toggled elements list is set to " +
                               $"<color={(MopSettings.GenerateToggledItemsListDebug ? "green" : "red")}>{MopSettings.GenerateToggledItemsListDebug}</color>");
                break;

            case "load-rules":
                if (args.Length > 1)
                {
                    RulesManager.Instance.LoadRules = args[1].ToLower() == "true";
                    if (!RulesManager.Instance.LoadRules)
                    {
                        ModConsole.Log("\n\n<color=red>WARNING:</color>\nDisabling rule files may cause serious issues with game, or even break your game save.\n\n" +
                                       "<b><color=red>!!! USE ONLY AT YOUR OWN RISK !!!</color></b>\n\n");
                    }
                }

                ModConsole.Log($"Loading rule files is set to " +
                               $"<color={(RulesManager.Instance.LoadRules ? "green" : "red")}>{RulesManager.Instance.LoadRules}</color>");
                break;

            case "force-crash":
                bool isCritical = false;
                if (args.Length > 1 && args[1].ToLower() == "critical")
                {
                    isCritical = true;
                }
                ExceptionManager.New(new System.Exception("Test exception"), isCritical, "Test exception: " + System.Guid.NewGuid());
                break;

            case "resolution":
                try
                {
                    int width  = int.Parse(args[1]);
                    int height = int.Parse(args[2]);

                    Screen.SetResolution(width, height, false);
                }
                catch
                {
                    ModConsole.LogError("Failed setting resolution.");
                }
                break;

            case "quality-settings":
                try
                {
                    QualitySettings.SetQualityLevel(int.Parse(args[1]), true);
                }
                catch
                {
                    ModConsole.LogError("Failed setting quality settings.");
                }
                break;
            }
        }
Пример #17
0
        public void Awake()
        {
            // Loading
            var engine = new Jint.Engine();

            //var logic = new Interpreter();
            Registers   = new Dictionary <Type, Action <BlockBehaviour, KeyInputController> >();
            Unregisters = new Dictionary <Type, Action <BlockBehaviour> >();

            ModConsole.RegisterCommand("script", args => {
                var text = string.Join(" ", args);
                //var func = logic.PrepareScript(text);
                //logic.AddExtFunc(func, "print", (ctx, x) => { ModConsole.Log(x[0]?.ToString()); return null; }, true);
                //logic.SetScript(func);
                //var res = logic.ContinueScript(1000);
                Func <JsValue, JsValue[], JsValue> printCb = (thiz, x) => {
                    ModConsole.Log(x[0]?.ToObject().ToString());
                    return(x[0]);
                };

                JsValue curV = null;
                Func <JsValue, JsValue[], JsValue> irqv = (thiz, x) => {
                    curV = x[0];
                    return(null);
                };
                var script = new JavaScriptParser(text, Jint.Engine.DefaultParserOptions).ParseScript();
                engine.SetValue("print", printCb);
                engine.SetValue("irqv", irqv);
                engine.SetScript(script);
                engine.Executor.OnLog = (x) => ModConsole.Log(x?.ToString());
                bool cli = false;
                engine.Executor.OnNextStatement = () =>
                {
                    if (cli)
                    {
                        return;
                    }
                    cli = true;
                    try
                    {
                        if (curV != null)
                        {
                            engine.Invoke(curV);
                        }
                    }
                    finally
                    {
                        cli = false;
                    }
                };
                var res = engine.ContinueScript(1000);
                ModConsole.Log(res?.ToString());
            }, "exec script");

            ModConsole.RegisterCommand("cpuapi", args =>
            {
                foreach (var line in SingleInstance <Blocks.Api.CpuApi> .Instance.GetHelp())
                {
                    ModConsole.Log(line);
                }
            }, "print cpu api list");

            ModConsole.RegisterCommand("sensordbg", args =>
            {
                DrawSensorDebug = args.Length < 1 ? false : args[0] == "true";
            }, "print sensor debug points");

            CpuBlock.Create(this);
            // These creator functions find corresponding block in game prefabs
            // and replace it with inheritor
            ExtLogicGate.Create(this);
            ExtAltimeterBlock.Create(this);
            ExtSpeedometerBlock.Create(this);
            ExtAnglometerBlock.Create(this);
            ExtSensorBlock.Create(this);
            ModConsole.Log($"Logic mod Awake");

            Events.OnMachineSimulationToggle += Events_OnMachineSimulationToggle;
            LineMaterial           = new Material(Shader.Find("Hidden/Internal-Colored"));
            LineMaterial.hideFlags = HideFlags.HideAndDontSave;
            LineMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
            LineMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
            LineMaterial.SetInt("_Cull", (int)UnityEngine.Rendering.CullMode.Off);
            LineMaterial.SetInt("_ZWrite", 0);

            Camera.onPostRender += DrawConnectingLines;
            Events.OnBlockInit  += InitBlock;

            CpuInfoMessage = ModNetworking.CreateMessageType(new DataType[]
            {
                DataType.Block,
                DataType.ByteArray
            });

            CpuLogMessage = ModNetworking.CreateMessageType(new DataType[]
            {
                DataType.Block,
                DataType.String
            });

            ModNetworking.Callbacks[CpuInfoMessage] += (Action <Message>)((msg) =>
            {
                Player localPlayer = Player.GetLocalPlayer();
                if (msg == null || localPlayer == null || !localPlayer.IsHost)
                {
                    return;
                }

                var block = msg.GetData(0) as Modding.Blocks.Block;
                if (!(block?.BlockScript is CpuBlock cpu))
                {
                    return;
                }

                if (block.Machine == localPlayer.Machine)
                {
                    return; // don't read updates for MY machine!
                }
                cpu.AfterEdit_ServerRecv((byte[])msg.GetData(1));
            });

            ModNetworking.Callbacks[CpuLogMessage] += (Action <Message>)((msg) =>
            {
                if (msg == null)
                {
                    return;
                }

                var block = msg.GetData(0) as Modding.Blocks.Block;
                if (!(block?.BlockScript is CpuBlock cpu))
                {
                    return;
                }

                cpu.LogMessage((string)msg.GetData(1));
            });
        }
Пример #18
0
        /// <summary>
        /// Looks for gamobject named SAVEGAME, and hooks PreSaveGame into them.
        /// </summary>
        void HookPreSaveGame()
        {
            try
            {
                GameObject[] saveGames = Resources.FindObjectsOfTypeAll <GameObject>()
                                         .Where(obj => obj.name.Contains("SAVEGAME")).ToArray();

                int i = 0;
                for (; i < saveGames.Length; i++)
                {
                    bool useInnactiveFix = false;
                    bool isJail          = false;

                    if (!saveGames[i].activeSelf)
                    {
                        useInnactiveFix = true;
                        saveGames[i].SetActive(true);
                    }

                    if (saveGames[i].transform.parent != null && saveGames[i].transform.parent.name == "JAIL" && saveGames[i].transform.parent.gameObject.activeSelf == false)
                    {
                        useInnactiveFix = true;
                        isJail          = true;
                        saveGames[i].transform.parent.gameObject.SetActive(true);
                    }

                    FsmHook.FsmInject(saveGames[i], "Mute audio", PreSaveGame);

                    if (useInnactiveFix)
                    {
                        if (isJail)
                        {
                            saveGames[i].transform.parent.gameObject.SetActive(false);
                            continue;
                        }

                        saveGames[i].SetActive(false);
                    }
                }

                // Hooking up on death save.
                GameObject onDeathSaveObject = new GameObject("MOP_OnDeathSave");
                onDeathSaveObject.transform.parent = GameObject.Find("Systems").transform.Find("Death/GameOverScreen");
                OnDeathBehaviour behaviour = onDeathSaveObject.AddComponent <OnDeathBehaviour>();
                behaviour.Initialize(PreSaveGame);
                i++;

                // Adding custom action to state that will trigger PreSaveGame, if the player picks up the phone with large Suski.
                PlayMakerFSM          useHandleFSM     = GameObject.Find("Telephone").transform.Find("Logic/UseHandle").GetComponent <PlayMakerFSM>();
                FsmState              phoneFlip        = useHandleFSM.GetState("Pick phone");
                List <FsmStateAction> phoneFlipActions = phoneFlip.Actions.ToList();
                phoneFlipActions.Insert(0, new CustomSuskiLargeFlip());
                phoneFlip.Actions = phoneFlipActions.ToArray();
                i++;

                ModConsole.Log($"[MOP] Hooked {i} save points!");
            }
            catch (Exception ex)
            {
                ExceptionManager.New(ex, true, "SAVE_HOOK_ERROR");
            }
        }
Пример #19
0
        IEnumerator LoopRoutine()
        {
            MopSettings.IsModActive = true;

            FramerateRecorder rec = gameObject.AddComponent <FramerateRecorder>();

            rec.Initialize();

            while (MopSettings.IsModActive)
            {
                // Ticks make sure that MOP is still up and running.
                // If the ticks didn't update, that means this routine stopped.
                ++ticks;

                if (!itemInitializationDelayDone)
                {
                    // We are slightly delaying the initialization, so all items have chance to set in place, because f**k MSC and its physics.
                    waitTime++;
                    if (waitTime >= WaitDone)
                    {
                        FinishLoading();
                    }
                }

                isPlayerAtYard = MOP.ActiveDistance.Value == 0 ? Vector3.Distance(player.position, placeManager[0].transform.position) < 100
                    : Vector3.Distance(player.position, placeManager[0].transform.position) < 100 * MopSettings.ActiveDistanceMultiplicationValue;

                // When player is in any of the sectors, MOP will act like the player is at yard.
                if (SectorManager.Instance.IsPlayerInSector())
                {
                    inSectorMode   = true;
                    isPlayerAtYard = true;
                }
                else
                {
                    inSectorMode = false;
                }

                yield return(null);

                int  i;
                long half = worldObjectManager.Count >> 1;
                // World Objects.
                for (i = 0; i < worldObjectManager.Count; ++i)
                {
                    if (i == half)
                    {
                        yield return(null);
                    }

                    try
                    {
                        GenericObject worldObject = worldObjectManager[i];

                        // Check if object was destroyed (mostly intended for AI pedastrians).
                        if (worldObject.GameObject == null)
                        {
                            worldObjectManager.Remove(worldObject);
                            continue;
                        }

                        if (SectorManager.Instance.IsPlayerInSector() && SectorManager.Instance.SectorRulesContains(worldObject.GameObject.name))
                        {
                            worldObject.GameObject.SetActive(true);
                            continue;
                        }

                        // Should the object be disabled when the player leaves the house?
                        if (worldObject.DisableOn.HasFlag(DisableOn.PlayerAwayFromHome) || worldObject.DisableOn.HasFlag(DisableOn.PlayerInHome))
                        {
                            if (worldObject.GameObject.name == "NPC_CARS" && inSectorMode)
                            {
                                continue;
                            }

                            if (worldObject.GameObject.name == "COMPUTER" && worldObject.GameObject.transform.Find("SYSTEM").gameObject.activeSelf)
                            {
                                continue;
                            }

                            worldObject.Toggle(worldObject.DisableOn.HasFlag(DisableOn.PlayerAwayFromHome) ? isPlayerAtYard : !isPlayerAtYard);
                        }
                        else if (worldObject.DisableOn.HasFlag(DisableOn.Distance))
                        {
                            // The object will be disabled, if the player is in the range of that object.
                            worldObject.Toggle(IsEnabled(worldObject.transform, worldObject.Distance));
                        }
                    }
                    catch (Exception ex)
                    {
                        ExceptionManager.New(ex, false, "WORLD_OBJECT_TOGGLE_ERROR");
                    }
                }

                // Safe mode prevents toggling elemenets that MAY case some issues (vehicles, items, etc.)
                if (MopSettings.Mode == PerformanceMode.Safe)
                {
                    yield return(new WaitForSeconds(.7f));

                    continue;
                }

                // So we create two separate lists - one is meant to enable, and second is ment to disable them,
                // Why?
                // If we enable items before enabling vehicle inside of which these items are supposed to be, they'll fall through to ground.
                // And the opposite happens if we disable vehicles before disabling items.
                // So if we are disabling items, we need to do that BEFORE we disable vehicles.
                // And we need to enable items AFTER we enable vehicles.
                itemsToEnable.Clear();
                itemsToDisable.Clear();
                half = ItemsManager.Instance.Count >> 1;
                for (i = 0; i < ItemsManager.Instance.Count; ++i)
                {
                    if (i == half)
                    {
                        yield return(null);
                    }

                    // Safe check if somehow the i gets bigger than array length.
                    if (i >= ItemsManager.Instance.Count)
                    {
                        break;
                    }

                    try
                    {
                        ItemBehaviour item = ItemsManager.Instance[i];

                        if (item == null || item.gameObject == null)
                        {
                            itemsToRemove.Add(item);
                            continue;
                        }

                        // Check the mode in what MOP is supposed to run and adjust to it.
                        bool toEnable = true;
                        if (MopSettings.Mode == 0)
                        {
                            toEnable = IsEnabled(item.transform, FsmManager.IsPlayerInCar() && !isPlayerAtYard ? 20 : 150);
                        }
                        else
                        {
                            toEnable = IsEnabled(item.transform, 150);
                        }

                        if (toEnable)
                        {
                            item.ToggleChangeFix();
                            if (item.ActiveSelf)
                            {
                                continue;
                            }
                            itemsToEnable.Add(item);
                        }
                        else
                        {
                            if (!item.ActiveSelf)
                            {
                                continue;
                            }
                            itemsToDisable.Add(item);
                        }

                        if (item.rb != null && item.rb.IsSleeping())
                        {
                            if (item.IsPartMagnetAttached())
                            {
                                continue;
                            }
                            if (CompatibilityManager.IsInBackpack(item))
                            {
                                continue;
                            }
                            item.rb.isKinematic = true;
                        }
                    }
                    catch (Exception ex)
                    {
                        ExceptionManager.New(ex, false, "ITEM_TOGGLE_GATHER_ERROR");
                    }
                }

                // Items To Disable
                int full = itemsToDisable.Count;
                if (full > 0)
                {
                    half = itemsToDisable.Count >> 1;
                    for (i = 0; i < full; ++i)
                    {
                        if (half != 0 && i == half)
                        {
                            yield return(null);
                        }

                        try
                        {
                            itemsToDisable[i].Toggle(false);
                        }
                        catch (Exception ex)
                        {
                            ExceptionManager.New(ex, false, "ITEM_TOGGLE_DISABLE_ERROR - " + itemsToDisable[i] != null ? itemsToDisable[i].gameObject.name : "null");
                        }
                    }
                }

                // Vehicles (new)
                half = vehicleManager.Count >> 1;
                for (i = 0; i < vehicleManager.Count; ++i)
                {
                    if (half != 0 && i == half)
                    {
                        yield return(null);
                    }

                    try
                    {
                        if (vehicleManager[i] == null)
                        {
                            vehicleManager.RemoveAt(i);
                            continue;
                        }

                        float distance       = Vector3.Distance(player.transform.position, vehicleManager[i].transform.position);
                        float toggleDistance = MOP.ActiveDistance.Value == 0
                            ? MopSettings.UnityCarActiveDistance : MopSettings.UnityCarActiveDistance * MopSettings.ActiveDistanceMultiplicationValue;

                        switch (vehicleManager[i].VehicleType)
                        {
                        case VehiclesTypes.Satsuma:
                            Satsuma.Instance.ToggleElements(distance);
                            vehicleManager[i].ToggleEventSounds(distance < 3);
                            break;

                        case VehiclesTypes.Jonnez:
                            vehicleManager[i].ToggleEventSounds(distance < 2);
                            break;
                        }

                        vehicleManager[i].ToggleUnityCar(IsVehiclePhysicsEnabled(distance, toggleDistance));
                        vehicleManager[i].Toggle(IsVehicleEnabled(distance));
                    }
                    catch (Exception ex)
                    {
                        ExceptionManager.New(ex, false, $"VEHICLE_TOGGLE_ERROR_{i}");
                    }
                }

                // Items To Enable
                full = itemsToEnable.Count;
                if (full > 0)
                {
                    half = full >> 1;
                    for (i = 0; i < full; ++i)
                    {
                        if (half != 0 && i == half)
                        {
                            yield return(null);
                        }

                        try
                        {
                            itemsToEnable[i].Toggle(true);
                        }
                        catch (Exception ex)
                        {
                            ExceptionManager.New(ex, false, "ITEM_TOGGLE_ENABLE_ERROR - " + itemsToEnable[i] != null ? itemsToDisable[i].gameObject.name : "null");
                        }
                    }
                }

                // Places (New)
                full = placeManager.Count;
                half = full >> 1;
                for (i = 0; i < full; ++i)
                {
                    if (i == half)
                    {
                        yield return(null);
                    }

                    try
                    {
                        if (SectorManager.Instance.IsPlayerInSector() && SectorManager.Instance.SectorRulesContains(placeManager[i].GetName()))
                        {
                            continue;
                        }

                        placeManager[i].ToggleActive(IsPlaceEnabled(placeManager[i].transform, placeManager[i].GetToggleDistance()));
                    }
                    catch (Exception ex)
                    {
                        ExceptionManager.New(ex, false, $"PLACE_TOGGLE_ERROR_{i}");
                    }
                }

                // Remove items that don't exist anymore.
                if (itemsToRemove.Count > 0)
                {
                    for (i = itemsToRemove.Count - 1; i >= 0; --i)
                    {
                        ItemsManager.Instance.RemoveAt(i);
                    }

                    itemsToRemove.Clear();
                }

                yield return(new WaitForSeconds(.7f));

                if (retries > 0 && !restartSucceedMessaged)
                {
                    restartSucceedMessaged = true;
                    ModConsole.Log("<color=green>[MOP] Restart succeeded!</color>");
                }
            }
        }
Пример #20
0
 public override void OnNewGame()
 {
     // Delete save data on new game
     ModConsole.Log("[Actual Mop] Resetting save data.");
     ModSave.Delete(SaveFile);
 }
Пример #21
0
 public void LogMessage(string message)
 {
     ModConsole.Log(message);
 }
Пример #22
0
        public static void VerifySave()
        {
            if (!File.Exists(SavePath))
            {
                return;
            }

            // Passenger bucket seat.
            // Check if driver bucket seat is bought and check the same for passenger one.
            // If they do not match, fix it.
            try
            {
                saveBugs = new List <SaveBugs>();

                bool bucketPassengerSeat = ES2.Load <bool>(SavePath + "?tag=bucket seat passenger(Clone)Purchased", setting);
                bool bucketDriverSeat    = ES2.Load <bool>(SavePath + "?tag=bucket seat driver(Clone)Purchased", setting);
                if (bucketDriverSeat != bucketPassengerSeat)
                {
                    saveBugs.Add(SaveBugs.New("Bucket Seats", "One bucket seat is present in the game world, while the other isn't - both should be in game world.", () =>
                    {
                        ES2.Save(true, SavePath + "?tag=bucket seat passenger(Clone)Purchased");
                        ES2.Save(true, SavePath + "?tag=bucket seat driver(Clone)Purchased");
                    }));
                }
            }
            catch (Exception e)
            {
                ExceptionManager.New(e, false, "VERIFY_SAVE_BUCKET_SEAT");
            }

            try
            {
                bool      tractorTrailerAttached = ES2.Load <bool>(SavePath + "?tag=TractorTrailerAttached", setting);
                Transform flatbedTransform       = ES2.Load <Transform>(SavePath + "?tag=FlatbedTransform", setting);
                Transform kekmetTransform        = ES2.Load <Transform>(SavePath + "?tag=TractorTransform", setting);
                if (tractorTrailerAttached && Vector3.Distance(flatbedTransform.position, kekmetTransform.position) > 5.5f)
                {
                    saveBugs.Add(SaveBugs.New("Flatbed Trailer Attached", "Trailer and tractor are too far apart from each other - impossible for them to be attached.", () =>
                    {
                        ES2.Save(false, SavePath + "?tag=TractorTrailerAttached", new ES2Settings());
                    }));
                }
            }
            catch (Exception ex)
            {
                ExceptionManager.New(ex, false, "VERIFY_SAVE_FLATBED");
            }

            try
            {
                // This one applies fix quietly, as it happens so often,
                // it would be annoying to nag player about that error.
                if (SaveFileExists)
                {
                    MopSaveData save = ModSave.Load <MopSaveData>(mopSavePath);
                    bool        bumperRearInstalled = ES2.Load <bool>(SavePath + "?tag=bumper rear(Clone)Installed", setting);
                    float       bumperTightness     = ES2.Load <float>(SavePath + "?tag=Bumper_RearTightness", setting);
                    if (bumperRearInstalled && bumperTightness != save.rearBumperTightness)
                    {
                        ES2.Save(save.rearBumperTightness, SavePath + "?tag=Bumper_RearTightness");
                        ES2.Save(save.rearBumperBolts, SavePath + "?tag=Bumper_RearBolts");
                    }
                }
            }
            catch (Exception ex)
            {
                ExceptionManager.New(ex, false, "VERIFY_BUMPER_REAR");
            }

            if (saveBugs.Count > 0)
            {
                ModPrompt.CreateYesNoPrompt($"MOP found <color=yellow>{saveBugs.Count}</color> problem{(saveBugs.Count > 1 ? "s" : "")} with your save:\n\n" +
                                            $"<color=yellow>{string.Join(", ", saveBugs.Select(f => f.BugName).ToArray())}</color>\n\n" +
                                            $"Would you like MOP to try and fix {((saveBugs.Count > 1) ? "them" : "it")}?", "MOP - Save Integrity Verification", FixAllProblems);
            }
            else
            {
                ModConsole.Log("[MOP] MOP didn't find any problems with your save :)");
            }
        }
Пример #23
0
        /// <summary>
        /// Reps modapi print-to-console function
        /// </summary>
        public static void print(string format, params object[] args)
        {
            // Written, 09.10.2021

            ModConsole.Log(string.Format("<color=grey>[ModAPI] - " + format + "</color>", args));
        }
Пример #24
0
        public void BugReport()
        {
            if (Directory.Exists(BugReportPath))
            {
                Directory.Delete(BugReportPath, true);
            }

            Directory.CreateDirectory(BugReportPath);

            // Get output_log.txt
            if (File.Exists($"{ExceptionManager.RootPath}/output_log.txt"))
            {
                File.Copy($"{ExceptionManager.RootPath}/output_log.txt", $"{BugReportPath}/output_log.txt");
            }

            // Now we are getting logs generated today.
            string today = DateTime.Now.ToString("yyyy-MM-dd");

            foreach (string log in Directory.GetFiles(ExceptionManager.LogFolder, $"*{today}*.txt"))
            {
                string pathToFile = log.Replace("\\", "/");
                string nameOfFile = log.Split('\\')[1];
                ModConsole.Log(nameOfFile);
                File.Copy(pathToFile, $"{BugReportPath}/{nameOfFile}");
            }

            // Generate a MOP report.
            using (StreamWriter sw = new StreamWriter($"{BugReportPath}/MOP_REPORT.txt"))
            {
                sw.WriteLine(ExceptionManager.GetGameInfo());
            }

            // Now we are packing up everything.
            string lastZipFilePath = $"{BugReportPath}/MOP Bug Report - {DateTime.Now:yyyy-MM-dd_HH-mm}.zip";

            using (ZipFile zip = new ZipFile())
            {
                foreach (string file in Directory.GetFiles(BugReportPath, "*.txt"))
                {
                    zip.AddFile(file, "");
                }

                zip.Save(lastZipFilePath);
            }

            // Now we are deleting all .txt files.
            foreach (string file in Directory.GetFiles(BugReportPath, "*.txt"))
            {
                File.Delete(file);
            }

            // Create the tutorial.
            using (StreamWriter sw = new StreamWriter($"{BugReportPath}/README.txt"))
            {
                sw.WriteLine("A MOP report archive has been successfully generated.\n");
                sw.WriteLine("Upload .zip file to some file hosting site, such as https://www.mediafire.com/. \n\n" +
                             "Remember to describe how you stumbled uppon the error!");
            }

            // We are asking the user if he wants to add his game save to the zip file.
            if (File.Exists(SaveManager.SavePath))
            {
                ModPrompt.CreateYesNoPrompt("Would you like to your include save file?\n\n" +
                                            "This may greatly improve finding and fixing the bug.", "MOP - Bug Report",
                                            () => {
                    using (ZipFile zip = ZipFile.Read(lastZipFilePath))
                    {
                        // Create folder called Save in the zip and get defaultES2Save.txt and items.txt.
                        zip.AddDirectoryByName("Save");
                        if (File.Exists(SaveManager.SavePath))
                        {
                            zip.AddFile(SaveManager.SavePath, "Save");
                        }

                        if (File.Exists(SaveManager.ItemsPath))
                        {
                            zip.AddFile(SaveManager.ItemsPath, "Save");
                        }

                        zip.Save();
                    }
                },
                                            onPromptClose: () => { Process.Start(BugReportPath); Process.Start($"{BugReportPath}/README.txt"); });
            }
        }
Пример #25
0
        // You know the rules and so do I
        // A full commitment's what I'm thinking of
        // You wouldn't get this from any other guy
        // I just wanna tell you how I'm feeling
        // Gotta make you understand
        // Never gonna give you up
        // Never gonna let you down
        // Never gonna run around and desert you
        // Never gonna make you cry
        // Never gonna say goodbye
        // Never gonna tell a lie and hurt you

        void ReadRulesFromFile(string rulePath)
        {
            try
            {
                string[] content     = File.ReadAllLines(rulePath).Where(s => s.Length > 0 && !s.StartsWith("##")).ToArray();
                string   fileName    = Path.GetFileName(rulePath);
                int      lines       = File.ReadAllLines(rulePath).Where(s => s.StartsWith("##")).ToArray().Length;
                int      currentLine = 0;
                foreach (string s in content)
                {
                    lines++;
                    currentLine++;
                    string[] splitted = s.Split(':');

                    // Read flag and rules.
                    string   flag    = splitted[0];
                    string[] objects = new string[0];
                    if (splitted.Length > 1)
                    {
                        // Support for object names that have space in it, using quotation mark, instead of using %20.
                        if (splitted[1].Contains("\""))
                        {
                            // Check if there is an odd number of quotation marks.
                            if (splitted[1].Count(f => f == '\"') % 2 != 0)
                            {
                                ModConsole.LogError($"[MOP] Quote hasn't been closed properly: {s} in rule file {fileName}({lines}).");
                                continue;
                            }

                            splitted[1] = Regex.Match(splitted[1], "\"[^\"]*\"").Value.Replace(" ", "%20").Replace("\"", "");
                        }

                        // Split all objects with space char.
                        objects = splitted[1].Trim().Split(' ');

                        // Replace the %20 in object names to space.
                        for (int i = 0; i < objects.Length; i++)
                        {
                            objects[i] = objects[i].Replace("%20", " ");
                        }
                    }

                    if (objects.Length > 0 && objects.ContainsAny(illegalValues))
                    {
                        ModConsole.LogError($"[MOP] Illegal object: {objects[0]} in rule file {fileName}.");
                        continue;
                    }

                    // Apply these rules
                    switch (flag)
                    {
                    default:
                        ModConsole.LogError($"[MOP] Unrecognized flag '{flag}' in {fileName} ({lines}).");
                        break;

                    case "ignore":
                        // Ignore at place
                        bool fullIgnore = false;
                        if (objects.Length > 1)
                        {
                            if (objects[1].ToLower() == "fullignore")
                            {
                                fullIgnore = true;
                            }
                            else
                            {
                                RulesManager.Instance.IgnoreRulesAtPlaces.Add(new IgnoreRuleAtPlace(objects[0], objects[1]));
                                break;
                            }
                        }

                        // Disabling some of the root object is pointless, so we inform abot that the user.

                        RulesManager.Instance.IgnoreRules.Add(new IgnoreRule(objects[0], fullIgnore));
                        break;

                    case "ignore_full":
                        ObsoleteWarning(flag, fileName, lines, s, "ignore: <object_name> fullIgnore");
                        RulesManager.Instance.IgnoreRules.Add(new IgnoreRule(objects[0], true));
                        break;

                    case "toggle":
                        ToggleModes mode = ToggleModes.Simple;
                        if (objects.Length > 1)
                        {
                            switch (objects[1])
                            {
                            default:
                                ModConsole.LogError($"[MOP] Unrecognized method '{objects[1]}' in {fileName} ({lines}).");
                                break;

                            case "renderer":
                                mode = ToggleModes.Renderer;
                                break;

                            case "item":
                                mode = ToggleModes.Item;
                                break;

                            case "vehicle":
                                mode = ToggleModes.Vehicle;
                                break;

                            case "vehicle_physics":
                                mode = ToggleModes.VehiclePhysics;
                                break;
                            }
                        }

                        RulesManager.Instance.ToggleRules.Add(new ToggleRule(objects[0], mode));
                        break;

                    case "satsuma_ignore_renderer":
                        RulesManager.Instance.SpecialRules.SatsumaIgnoreRenderers = true;
                        break;

                    case "dont_destroy_empty_beer_bottles":
                        ObsoleteWarning(flag, fileName, lines, s, "dont_destroy_empty_bottles");
                        RulesManager.Instance.SpecialRules.DontDestroyEmptyBeerBottles = true;
                        break;

                    case "dont_destroy_empty_bottles":
                        RulesManager.Instance.SpecialRules.DontDestroyEmptyBeerBottles = true;
                        break;

                    case "sector":
                        Vector3  pos       = ParseToVector3(objects[0]);
                        Vector3  scale     = ParseToVector3(objects[1]);
                        Vector3  rot       = ParseToVector3(objects[2]);
                        string[] whitelist = GetWhitelist(objects);
                        RulesManager.Instance.NewSectors.Add(new NewSector(pos, scale, rot, whitelist));
                        break;

                    case "min_ver":
                        if (fileName == CustomFile)
                        {
                            break;
                        }

                        if (currentLine != 1)
                        {
                            ModConsole.Log($"\n=================================" +
                                           $"\n\n<color=cyan>[MOP] Flag '{flag}' must be first in the order!\n\n" +
                                           $"File: {fileName}\n" +
                                           $"Line: {lines}\n" +
                                           $"You can ignore that message.</color>");
                        }

                        int      major, minor, revision = 0;
                        string[] verSplitted = objects[0].Split('.');
                        major = int.Parse(verSplitted[0]);
                        minor = int.Parse(verSplitted[1]);
                        if (verSplitted.Length == 3)
                        {
                            revision = int.Parse(verSplitted[2]);
                        }

                        int      modMajor, modMinor, modRevision = 0;
                        string[] modVersionSpliited = MOP.ModVersionShort.Split('.');
                        modMajor = int.Parse(modVersionSpliited[0]);
                        modMinor = int.Parse(modVersionSpliited[1]);
                        if (modVersionSpliited.Length == 3)
                        {
                            modRevision = int.Parse(modVersionSpliited[2]);
                        }

                        bool isOutdated = false;
                        if (major > modMajor)
                        {
                            isOutdated = true;
                        }
                        else
                        {
                            if (minor > modMinor && major == modMajor)
                            {
                                isOutdated = true;
                            }
                            else
                            {
                                if (revision > modRevision && minor == modMinor && major == modMajor)
                                {
                                    isOutdated = true;
                                }
                            }
                        }

                        if (isOutdated)
                        {
                            ModConsole.LogError($"[MOP] Rule file {fileName} is for the newer version of MOP. Please update MOP right now!\n\n" +
                                                $"Your MOP version: {modMajor}.{modMinor}.{modRevision}\n" +
                                                $"Required version: {major}.{minor}.{revision}");

                            return;
                        }

                        break;

                    // Custom.txt exclusives.
                    case "ignore_mod_vehicles":
                        if (fileName != CustomFile)
                        {
                            ModConsole.LogError($"[MOP] Flag: {flag} is only allowed to be used in custom rule file.");
                            continue;
                        }
                        RulesManager.Instance.SpecialRules.IgnoreModVehicles = true;
                        break;

                    case "toggle_all_vehicles_physics_only":
                        if (fileName != CustomFile)
                        {
                            ModConsole.LogError($"[MOP] Flag: {flag} is only allowed to be used in custom rule file.");
                            continue;
                        }
                        RulesManager.Instance.SpecialRules.ToggleAllVehiclesPhysicsOnly = true;
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                ModConsole.LogError($"[MOP] Error loading rule {Path.GetFileName(rulePath)}: {ex}.");
                NewMessage($"<color=red>MOP: Error loading rule :(");
            }
        }
Пример #26
0
        /// <summary>
        /// Seeks for rule files (.mopconfig) in MOP config folder.
        /// </summary>
        void GetAndReadRules()
        {
            overrideUpdateCheck = false;

            try
            {
                // Find and .mopconfig files.
                DirectoryInfo   dir   = new DirectoryInfo(MOP.ModConfigPath);
                List <FileInfo> files = dir.GetFiles().Where(d => d.Name.EndsWith(RuleExtension)).ToList();
                // Load custom rule file.
                if (File.Exists($"{dir}/{CustomFile}"))
                {
                    files.Add(new FileInfo($"{dir}/{CustomFile}"));
                    ModConsole.Log("[MOP] User custom rule file found!");
                }

                if (files.Count == 0)
                {
                    ModConsole.Log($"[MOP] No rule files found.");
                    NewMessage("");
                    return;
                }

                string message = $"[MOP] Found {files.Count} rule file{(files.Count > 1 ? "s" : "")}!";
                if (files.Count == 69)
                {
                    message = message.Rainbowmize();
                }

                ModConsole.Log(message);

                int removed = 0;

                // Read rule files.
                foreach (FileInfo file in files)
                {
                    // Delete rules for mods that don't exist.
                    if (ModLoader.LoadedMods.Find(m => m.ID == Path.GetFileNameWithoutExtension(file.Name)) == null && file.Name != CustomFile)
                    {
                        removed++;
                        if (MOP.DeleteUnusedRules.Value)
                        {
                            File.Delete(file.FullName);
                            ModConsole.Log($"<color=yellow>[MOP] Rule file {file.Name} has been deleted, " +
                                           $"because corresponding mod is not present.</color>");
                            removed++;
                            continue;
                        }
                        ModConsole.Log($"<color=yellow>[MOP] Skipped {file.Name} rule, " +
                                       $"because the corresponding mod is not present.</color>");
                        RulesManager.Instance.UnusedRules.Add(file.Name);
                        continue;
                    }

                    // Verify if the servercontent has that rule file.
                    // Some mod makers may include poorly configured rule files,
                    // that's why they have to be only provided by the server.
                    if (serverContent != null && MOP.VerifyRuleFiles.Value && file.Name != CustomFile)
                    {
                        if (serverContent.Find(m => m.ID == Path.GetFileNameWithoutExtension(file.Name)) == null)
                        {
                            ModConsole.LogWarning($"[MOP] Rule file {file.Name} has been skipped, because it couldn't be verified.");
                            removed++;
                            continue;
                        }
                    }

                    RulesManager.Instance.RuleFileNames.Add(file.Name);
                    ReadRulesFromFile(file.FullName);
                }

                int loaded = files.Count - removed;
                ModConsole.Log($"<color=green>[MOP] Loading {loaded}/{files.Count} rule files done!</color>");
                if (loaded == 0)
                {
                    NewMessage($"MOP: No rules have been loaded ({removed} rule{(removed == 1 ? "" : "s")} skipped).");
                }
                else
                {
                    NewMessage($"MOP: Succesfully loaded {loaded} rule file{(loaded == 1 ? "" : "s")}! {(removed > 0 ? $"({removed} rule{(removed == 1 ? "" : "s")} skipped)" : "" )}");
                }
            }
            catch (Exception ex)
            {
                ExceptionManager.New(ex, false, "RULE_FILES_READ_ERROR");
            }
        }
Пример #27
0
        IEnumerator DownloadAndUpdateRoutine()
        {
            string lastModList = File.Exists(lastModListPath) ? File.ReadAllText(lastModListPath) : "";

            Mod[]  mods          = ModLoader.LoadedMods.Where(m => !m.ID.ContainsAny("MSCLoader_", "MOP")).ToArray();
            string modListString = "";

            ModConsole.Log("[MOP] Checking for new mods...");

            bool isUpdateTime = !File.Exists(lastDateFilePath) || IsUpdateTime();

            if (isUpdateTime)
            {
                ModConsole.Log("[MOP] Looking for updates...");
            }

            foreach (Mod mod in mods)
            {
                string modId = mod.ID;
                modListString += $"{modId}\n";

                string ruleUrl  = $"{RemoteServer}/{modId}{RuleExtension}";
                string filePath = $"{MOP.ModConfigPath}/{modId}{RuleExtension}";

                // Continue if it's not time for an update, and the mod is in the list of last mods.
                if (lastModList.Contains(mod.ID) && !isUpdateTime)
                {
                    continue;
                }

                // Check if rule file for mod is on the server.
                // If not, continue.
                if (!IsFileOnServer(modId))
                {
                    continue;
                }

                // Check if the newer file is available on the server.
                if (!overrideUpdateCheck)
                {
                    if (serverContent == null)
                    {
                        GetServerContent();
                    }

                    DateTime          lastLocalFileWrite = GetFileWriteTime(filePath);
                    ServerContentData data = serverContent.First(t => t.ID == modId);
                    DateTime          lastRemoteFileWrite = data.UpdateTime;
                    if (lastRemoteFileWrite <= lastLocalFileWrite)
                    {
                        ModConsole.Log($"<color=orange>[MOP] Skipping {modId}, because local file and remote file are the same.</color>");
                        continue;
                    }
                }

                // Check if file actually exists on remote server.
                if (!RemoteFileExists(ruleUrl))
                {
                    ModConsole.LogError($"[MOP] Rule file for mod doesn't exist!\nID: {modId}\nURL: {ruleUrl}");
                    continue;
                }

                fileDownloadCompleted = false;
                using (WebClient web = new WebClient())
                {
                    ModConsole.Log($"<color=yellow>[MOP] Downloading new rule file for {mod.Name}...</color>");
                    NewMessage($"MOP: Downloading new rule file for {mod.Name}...");
#if DEBUG
                    web.Headers.Add("user-agent", $"MOP/{MOP.ModVersion}_DEBUG {ExceptionManager.GetSystemInfo()}");
#else
                    web.Headers.Add("user-agent", $"MOP/{MOP.ModVersion} {ExceptionManager.GetSystemInfo()}");
#endif
                    if (File.Exists(filePath))
                    {
                        File.Delete(filePath);
                    }

                    web.DownloadFileCompleted += DownloadFileCompleted;
                    web.DownloadFileAsync(new Uri(ruleUrl), filePath);

                    int waitTime = 0;
                    while (!fileDownloadCompleted)
                    {
                        yield return(new WaitForSeconds(.5f));

                        waitTime++;

                        // If wait time is longer than 30 seconds, abandon downloading.
                        if (waitTime > 60)
                        {
                            ModConsole.LogError("[MOP] Downloading failed. Skipping downloading.");
                            NewMessage("MOP: Downloading failed. Skipping downloading.");
                            GetAndReadRules();
                            yield break;
                        }
                    }
                }

                ModConsole.Log("<color=green>[MOP] Downloading completed!</color>");
            }

            File.WriteAllText(lastModListPath, modListString);
            if (isUpdateTime)
            {
                File.WriteAllText(lastDateFilePath, DateTime.Now.ToString());
            }

            // File downloading and updating completed!
            // Start reading those files.
            GetAndReadRules();
        }