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 ); } }; }
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; } }
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>"); }
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>"); }
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); }
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); }
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()); }
// メソッド // ステージ(バレンエクスパンスなど)に初めて入った時に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); }
/// <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!"); }
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("==============="); }
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(); }
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); } } }
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();*/ }
/// <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); }
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"); } }
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; } }
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)); }); }
/// <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"); } }
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>"); } } }
public override void OnNewGame() { // Delete save data on new game ModConsole.Log("[Actual Mop] Resetting save data."); ModSave.Delete(SaveFile); }
public void LogMessage(string message) { ModConsole.Log(message); }
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 :)"); } }
/// <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)); }
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"); }); } }
// 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 :("); } }
/// <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"); } }
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(); }