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>"); } } }
/// <summary> /// Toggles some of the elements of that car, depneding on the of player to Satsuma. /// </summary> /// <param name="distance"></param> public void ToggleElements(float distance) { if (Toggle == IgnoreToggle) { distance = 0; } try { bool onEngine = distance < 2; bool onClose = distance <= 10 * MopSettings.ActiveDistanceMultiplicationValue; bool onFar = distance <= 20 * MopSettings.ActiveDistanceMultiplicationValue; if (IsKeyInserted() || IsSatsumaInInspectionArea || IsMoving()) { onEngine = true; onClose = true; onFar = true; } for (int i = 0; i < onEngineOffToggle.Count; i++) { onEngineOffToggle[i].SetActive(onEngine); } for (int i = 0; i < onCloseToggle.Count; i++) { onCloseToggle[i].SetActive(onClose); } for (int i = 0; i < onCloseTogglePlayMaker.Count; i++) { onCloseTogglePlayMaker[i].enabled = onClose; } for (int i = 0; i < onFarToggle.Count; i++) { onFarToggle[i].SetActive(onFar); } // This script fixes the issue with bolts staying unbolted, with parts internally being fully bolted. if (onEngine && maskedFixStages < 2) { switch (maskedFixStages) { case 0: for (int i = 0; i < maskedElements.Count; i++) { maskedElements.ElementAt(i).Key.SetActive(true); } break; case 1: for (int i = 0; i < maskedElements.Count; i++) { maskedElements.ElementAt(i).Key.SetActive(maskedElements.ElementAt(i).Value); } break; } maskedFixStages++; } } catch (System.Exception ex) { ExceptionManager.New(ex, "SATSUMA_TOGGLE_ELEMENTS_ERROR"); } }
/// <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"); } }
/// <summary> /// Toggles on all objects. /// </summary> public void ToggleAll(bool enabled, ToggleAllMode mode = ToggleAllMode.Default) { // World objects for (int i = 0; i < worldObjectManager.Count; i++) { try { worldObjectManager[i].Toggle(enabled); } catch (Exception ex) { ExceptionManager.New(ex, false, "TOGGLE_ALL_WORLD_OBJECTS_ERROR"); } } if (MopSettings.Mode == PerformanceMode.Safe) { return; } // Items for (int i = 0; i < ItemsManager.Instance.Count; i++) { try { ItemBehaviour item = ItemsManager.Instance[i]; item.Toggle(enabled); // We're freezing the object on save, so it won't move at all. if (mode == ToggleAllMode.OnSave) { item.gameObject.SetActive(true); item.Freeze(); item.SaveGame(); } } catch (Exception ex) { ExceptionManager.New(ex, false, "TOGGLE_ALL_ITEMS_ERROR"); } } // Find all kilju, emptyca, empty juice container, and force empty them if applicable try { IEnumerable <GameObject> bottles = Resources.FindObjectsOfTypeAll <GameObject>().Where(g => g.name.ContainsAny("kilju", "emptyca", "empty plastic can")); foreach (GameObject bottle in bottles) { bottle.GetComponent <ItemBehaviour>()?.ResetKiljuContainer(); if (mode == ToggleAllMode.OnSave) { bottle.SetActive(true); bottle.GetComponent <ItemBehaviour>()?.SaveGame(); } } } catch (Exception ex) { ExceptionManager.New(ex, false, "KILJU_RESET_FORCE_ERROR"); } // Vehicles for (int i = 0; i < vehicleManager.Count; i++) { try { vehicleManager[i].Toggle(enabled); if (mode == ToggleAllMode.OnLoad) { vehicleManager[i].ForceToggleUnityCar(false); } else if (mode == ToggleAllMode.OnSave) { vehicleManager[i].ToggleUnityCar(enabled); vehicleManager[i].Freeze(); } } catch (Exception ex) { ExceptionManager.New(ex, false, $"TOGGLE_ALL_VEHICLE_ERROR_{i}"); } } // Places for (int i = 0; i < placeManager.Count; i++) { try { placeManager[i].ToggleActive(enabled); } catch (Exception ex) { ExceptionManager.New(ex, false, $"TOGGLE_ALL_PLACES_{i}"); } } // Force teleport kilju bottles. try { if (mode == ToggleAllMode.OnSave) { GameObject canTrigger = ItemsManager.Instance.GetCanTrigger(); if (canTrigger) { if (!canTrigger.transform.parent.gameObject.activeSelf) { canTrigger.transform.parent.gameObject.SetActive(true); } canTrigger.GetComponent <PlayMakerFSM>().SendEvent("STOP"); } } } catch (Exception ex) { ExceptionManager.New(ex, false, "TOGGLE_ALL_JOBS_DRUNK"); } // ToggleElements class of Satsuma. try { Satsuma.Instance.ToggleElements((mode == ToggleAllMode.OnSave) ? 0 : (enabled ? 0 : 10000)); } catch (Exception ex) { ExceptionManager.New(ex, false, "TOGGLE_ALL_SATSUMA_TOGGLE_ELEMENTS"); } }
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 SectorManager() { instance = this; ModConsole.Print("[MOP] Loading sectors..."); activeSectors = new List <Sector>(); DisabledObjects = new List <GameObject> { GameObject.Find("ELEC_POLES"), GameObject.Find("ELEC_POLES_COLL"), GameObject.Find("TREES_MEDIUM3"), GameObject.Find("TREES_SMALL1"), GameObject.Find("TREES1_COLL"), GameObject.Find("TREES2_COLL"), GameObject.Find("TREES3_COLL"), GameObject.Find("BUSHES3"), GameObject.Find("BUSHES6"), GameObject.Find("BUSHES7"), GameObject.Find("BusStop"), GameObject.Find("BusStop 1"), GameObject.Find("MachineHall"), GameObject.Find("YARD/UNCLE/Shed"), GameObject.Find("YARD/UNCLE/Greenhouse"), GameObject.Find("YARD/UNCLE/LOD"), GameObject.Find("YARD/UNCLE/Home"), GameObject.Find("YARD/UNCLE/Building"), GameObject.Find("MAP/RadioMast"), GameObject.Find("MAP/PierHome"), GameObject.Find("MAP/MESH/FOLIAGE/LAKE_VEGETATION") }; GameObject lakeSimpleTile = GameObject.Find("MAP/LakeSimple/Tile"); if (lakeSimpleTile != null) { DisabledObjects.Add(lakeSimpleTile); } GameObject lakeNice = GameObject.Find("MAP/LakeNice"); if (lakeNice != null) { DisabledObjects.Add(lakeNice); } sectors = new List <GameObject>(); // Load rule files if (Rules.instance.IgnoreRules.Count > 0) { List <GameObject> newList = new List <GameObject>(); foreach (GameObject obj in DisabledObjects) { try { if (obj == null) { continue; } if (!Rules.instance.IgnoreRules.Any(f => f.ObjectName == obj.name)) { newList.Add(obj); } } catch (System.Exception ex) { ExceptionManager.New(ex, "SECTOR_RULES_LOAD_ERROR"); } } DisabledObjects = newList; } // Garage CreateNewSector(new Vector3(-16.77627f, -0.5062422f, 1.559867f), new Vector3(5, 5, 9), "PierHome"); // Teimo CreateNewSector(new Vector3(-1547.3f, 4, 1183.35f), new Vector3(9.6f, 5, 5.5f), new Vector3(0, 328, 0), "StreetLights", "HUMANS", "TRAFFIC", "NPC_CARS", "PERAJARVI", "TrafficSigns", "StreetLights", "ELEC_POLES", "TREES_SMALL1"); CreateNewSector(new Vector3(-1551.7f, 4, 1185.8f), new Vector3(4.6f, 5, 2.5f), new Vector3(0, 328, 0), "StreetLights", "HUMANS", "TRAFFIC", "NPC_CARS", "PERAJARVI", "TrafficSigns", "StreetLights", "ELEC_POLES", "TREES_SMALL1"); // Repair shop CreateNewSector(new Vector3(1562.49f, 4.8f, 733.8835f), new Vector3(15, 5, 20), new Vector3(0, 335, 0), "TRAFFIC", "ELEC_POLES", "Buildings", "HUMANS", "TrafficSigns", "StreetLights"); // Yard Machine Hall CreateNewSector(new Vector3(54.7f, -0.5062422f, -73.9f), new Vector3(6, 5, 5.2f), "YARD", "MachineHall", "BUSHES3", "BUSHES6", "TREES_SMALL1"); // Home CreateNewSector(new Vector3(-7.2f, -0.5062422f, 9.9f), new Vector3(11, 5, 9.5f), "PierHome", "TREES_SMALL1", "BUSHES7", "Building"); // Living room, kitchen, bedrooms. CreateNewSector(new Vector3(-12.5f, -0.5062422f, 1), new Vector3(3, 5, 7.7f), "PierHome", "TREES_SMALL1", "BUSHES7", "Building"); // Sauna, bathroom. CreateNewSector(new Vector3(-13.5f, -0.5062422f, 6.4f), new Vector3(1.3f, 5, 1.7f), "PierHome", "TREES_SMALL1", "BUSHES7", "Building"); // Storage room (kitchen). // Jail CreateNewSector(new Vector3(-655, 5, -1156), new Vector3(5, 5, 9f)); // Cottage CreateNewSector(new Vector3(-848.2f, -2, 505.6f), new Vector3(5, 3, 5.2f), new Vector3(0, 342, -1.07f), "BUSHES7", "TREES_SMALL4", "TREES_MEDIUM3", "LakeNice", "TRAFFIC", "Tile"); // Cabin CreateNewSector(new Vector3(-165.55f, -3.7f, 1020.7f), new Vector3(5, 4, 3.5f), "LakeNice", "Tile", "BUSHES7", "TREES_SMALL1"); // Driveway sector if (Rules.instance.SpecialRules.DrivewaySector) { CreateNewSector(new Vector3(-18.5f, -0.5062422f, 11.9f), new Vector3(11f, 5, 9.5f), "PierHome", "TREES_SMALL1", "BUSHES7", "BUSHES3", "BUSHES6", "TREES_MEDIUM3", "YARD", "LakeNice", "Tile"); } // Generating sectors from rule files. if (Rules.instance.NewSectors.Count > 0) { foreach (NewSector sector in Rules.instance.NewSectors) { CreateNewSector(sector.Position, sector.Scale, sector.Rotation, sector.Whitelist); } } ModConsole.Print($"[MOP] Loaded {loadedSectors} sectors"); }
/// <summary> /// Lists all the game objects in the game's world and that are on the whitelist, /// then it adds ObjectHook to them /// </summary> void InitializeList() { // Get all minor objects from the game world (like beer cases, sausages) // Only items that are in the listOfMinorObjects list, and also contain "(itemx)" in their name will be loaded GameObject[] items = Object.FindObjectsOfType <GameObject>() .Where(gm => gm.name.ContainsAny(BlackList) && gm.name.ContainsAny("(itemx)", "(Clone)") && gm.activeSelf).ToArray(); for (int i = 0; i < items.Length; i++) { try { items[i].AddComponent <ItemHook>(); // Hook the TriggerMinorObjectRefresh to Confirm and Spawn all actions if (items[i].name.Equals("shopping bag(itemx)")) { FsmHook.FsmInject(items[i], "Confirm", cashRegisterHook.TriggerMinorObjectRefresh); FsmHook.FsmInject(items[i], "Spawn all", cashRegisterHook.TriggerMinorObjectRefresh); } else if (items[i].name.EqualsAny("spark plug box(Clone)", "car light bulb box(Clone)")) { FsmHook.FsmInject(items[i], "Create Plug", cashRegisterHook.WipeUseLoadOnSparkPlugs); } else if (items[i].name.EqualsAny("alternator belt(Clone)", "oil filter(Clone)", "battery(Clone)")) { PlayMakerFSM fanbeltUse = items[i].GetPlayMakerByName("Use"); FsmState loadFanbelt = fanbeltUse.FindFsmState("Load"); List <FsmStateAction> emptyActions = new List <FsmStateAction> { new CustomNullState() }; loadFanbelt.Actions = emptyActions.ToArray(); loadFanbelt.SaveActions(); } } catch (System.Exception ex) { ExceptionManager.New(ex, "ITEM_LIST_LOAD_ERROR"); } } cashRegisterHook.WipeUseLoadOnSparkPlugs(); // CD Player Enhanced compatibility if (ModLoader.IsModPresent("CDPlayer")) { GameObject[] cdEnchancedObjects = Object.FindObjectsOfType <GameObject>() .Where(gm => gm.name.ContainsAny("cd case(itemy)", "CD Rack(itemy)", "cd(itemy)") && gm.activeSelf).ToArray(); for (int i = 0; i < cdEnchancedObjects.Length; i++) { cdEnchancedObjects[i].AddComponent <ItemHook>(); } // Create shop table check, for when the CDs are bought GameObject itemCheck = new GameObject("MOP_ItemAreaCheck"); itemCheck.transform.position = GameObject.Find("SpawnItemStore").transform.position; itemCheck.AddComponent <ShopModItemSpawnCheck>(); } else { GameObject[] cdItems = Resources.FindObjectsOfTypeAll <GameObject>().Where(g => g.name.ContainsAny("cd case(item", "cd(item")).ToArray(); foreach (GameObject cd in cdItems) { cd.AddComponent <ItemHook>(); } } // Get items from ITEMS object. GameObject itemsObject = GameObject.Find("ITEMS"); for (int i = 0; i < itemsObject.transform.childCount; i++) { GameObject item = itemsObject.transform.GetChild(i).gameObject; if (item.name == "CDs") { continue; } try { if (item.GetComponent <ItemHook>() != null) { continue; } item.AddComponent <ItemHook>(); } catch (System.Exception ex) { ExceptionManager.New(ex, "ITEM_LIST_AT_ITEMS_LOAD_ERROR"); } } // Also disable the restart for that sunnuva bitch. itemsObject.GetComponent <PlayMakerFSM>().Fsm.RestartOnEnable = false; // F*****g wheels. GameObject[] wheels = Object.FindObjectsOfType <GameObject>(). Where(gm => gm.name.EqualsAny("wheel_regula", "wheel_offset") && gm.activeSelf).ToArray(); foreach (GameObject wheel in wheels) { wheel.AddComponent <ItemHook>(); } // Tires trigger at Fleetari's. GameObject wheelTrigger = new GameObject("MOP_WheelTrigger"); wheelTrigger.transform.localPosition = new Vector3(1555.49f, 4.8f, 737); wheelTrigger.transform.localEulerAngles = new Vector3(1.16f, 335, 1.16f); wheelTrigger.AddComponent <WheelRepairJobTrigger>(); // Hook up the envelope. GameObject[] envelopes = Resources.FindObjectsOfTypeAll <GameObject>().Where(g => g.name.EqualsAny("envelope(xxxxx)", "lottery ticket(xxxxx)")).ToArray(); foreach (var g in envelopes) { g.AddComponent <ItemHook>(); } // Unparent all childs of CDs object. Transform cds = GameObject.Find("ITEMS").transform.Find("CDs"); if (cds != null) { for (int i = 0; i < cds.childCount; i++) { cds.GetChild(i).parent = null; } } }