Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of Rains Car Mod v1.0.6
RainsCarMod.dll
Decompiled 10 months agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using FishNet; using FishNet.Connection; using FishNet.Managing; using FishNet.Managing.Object; using FishNet.Object; using HarmonyLib; using MelonLoader; using MelonLoader.Utils; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using RainsCarMod; using RainsCarMod.Logging; using ScheduleOne.DevUtilities; using ScheduleOne.Interaction; using ScheduleOne.Money; using ScheduleOne.PlayerScripts; using ScheduleOne.Vehicles; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(CarModLoader), "RainsCarMod", "1.0.6", "RainingDeath", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("RainsCarMod")] [assembly: AssemblyConfiguration("DebugMelon")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("RainsCarMod")] [assembly: AssemblyTitle("RainsCarMod")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace RainsCarMod { public class CarDealerInterface : MonoBehaviour { [Header("References")] public Transform cameraPosition; public InteractableObject intObj; public Canvas canvas; public static Action OnUIRequested; private bool isOpen = false; private PlayerMovement playerMovement; private PlayerCamera playerCamera; private PlayerInventory playerInventory; private void Start() { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)intObj == (Object)null) { intObj = ((Component)this).GetComponent<InteractableObject>(); if ((Object)(object)intObj == (Object)null) { MelonLogger.Warning("[RainsCarMod][CarDealerInterface] No InteractableObject found on CarDealerComputer."); } } if ((Object)(object)intObj != (Object)null) { intObj.onInteractStart.AddListener(new UnityAction(Interacted)); } if ((Object)(object)cameraPosition == (Object)null) { Transform val = ((Component)this).transform.Find("CameraPosition"); if ((Object)(object)val != (Object)null) { cameraPosition = val; } else { MelonLogger.Warning("[RainsCarMod][CarDealerInterface] CameraPosition child not found."); } } if ((Object)(object)cameraPosition != (Object)null) { cameraPosition.position = new Vector3(-59.7f, -1.03f, -16.8f); cameraPosition.rotation = Quaternion.Euler(0f, 330f, 0f); } TryResolvePlayerRefs(); if ((Object)(object)canvas == (Object)null) { canvas = ((Component)this).GetComponentInChildren<Canvas>(true); } if ((Object)(object)canvas != (Object)null) { Transform val2 = ((Component)canvas).transform.Find("Panel"); if ((Object)(object)val2 != (Object)null) { ((Component)val2).gameObject.SetActive(true); } else { MelonLogger.Warning("[RainsCarMod][CarDealerInterface] Panel not found under Canvas."); } } else { MelonLogger.Warning("[RainsCarMod][CarDealerInterface] Canvas reference is missing."); } UIManager.OnUICloseRequested = Close; } private void TryResolvePlayerRefs() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) GameObject val = null; GameObject val2 = GameObject.Find("Player_Local"); if ((Object)(object)val2 != (Object)null) { val = ((Component)val2.transform.root).gameObject; } if ((Object)(object)val == (Object)null) { Scene activeScene = SceneManager.GetActiveScene(); GameObject[] rootGameObjects = ((Scene)(ref activeScene)).GetRootGameObjects(); for (int i = 0; i < rootGameObjects.Length; i++) { if (!((Object)(object)val == (Object)null)) { break; } Transform val3 = FindChildByName(rootGameObjects[i].transform, "Player_Local"); if ((Object)(object)val3 != (Object)null) { val = ((Component)val3.root).gameObject; } } } if ((Object)(object)val == (Object)null) { PlayerMovement[] array = Object.FindObjectsOfType<PlayerMovement>(); if (array != null && array.Length != 0) { val = ((Component)array[0]).gameObject; } } if ((Object)(object)val != (Object)null) { if ((Object)(object)playerMovement == (Object)null) { playerMovement = val.GetComponentInChildren<PlayerMovement>(true); } if ((Object)(object)playerCamera == (Object)null) { playerCamera = val.GetComponentInChildren<PlayerCamera>(true); } if ((Object)(object)playerInventory == (Object)null) { playerInventory = val.GetComponentInChildren<PlayerInventory>(true); } } } private Transform FindChildByName(Transform parent, string name) { if (((Object)parent).name == name) { return parent; } for (int i = 0; i < parent.childCount; i++) { Transform val = FindChildByName(parent.GetChild(i), name); if ((Object)(object)val != (Object)null) { return val; } } return null; } public void Interacted() { if (!isOpen) { Open(); } } public void Open() { //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)playerMovement == (Object)null || (Object)(object)playerCamera == (Object)null || (Object)(object)playerInventory == (Object)null) { TryResolvePlayerRefs(); } isOpen = true; OnUIRequested?.Invoke(); if ((Object)(object)playerMovement != (Object)null) { playerMovement.CanMove = false; } else { MelonLogger.Warning("[RainsCarMod][CarDealerInterface] PlayerMovement is null in Open()."); } if ((Object)(object)playerInventory != (Object)null) { playerInventory.SetInventoryEnabled(false); } if ((Object)(object)playerCamera != (Object)null && (Object)(object)cameraPosition != (Object)null) { playerCamera.FreeMouse(); playerCamera.OverrideTransform(cameraPosition.position, cameraPosition.rotation, 0.15f, false); playerCamera.OverrideFOV(65f, 0.15f); playerCamera.AddActiveUIElement(((Object)this).name); } else { MelonLogger.Warning("[RainsCarMod][CarDealerInterface] Cannot override camera (missing playerCamera or cameraPosition)."); } } public void Close() { isOpen = false; if ((Object)(object)playerMovement != (Object)null) { playerMovement.CanMove = true; } if ((Object)(object)playerInventory != (Object)null) { playerInventory.SetInventoryEnabled(true); } if ((Object)(object)playerCamera != (Object)null) { playerCamera.StopTransformOverride(0.15f, true, true); playerCamera.StopFOVOverride(0.15f); playerCamera.LockMouse(); playerCamera.RemoveActiveUIElement(((Object)this).name); } } } public class Core : MelonMod { public override void OnInitializeMelon() { Log.LogInfo("Initializing RainsCarMod..."); } } public class DealerConfig { public bool enableDealership = true; public static DealerConfig Instance; public static void Load() { string text = Path.Combine(MelonEnvironment.UserDataDirectory, "RainsCarMod"); string path = Path.Combine(text, "Dealer_Config.json"); if (!Directory.Exists(text)) { Directory.CreateDirectory(text); } if (!File.Exists(path)) { Instance = new DealerConfig(); File.WriteAllText(path, JsonConvert.SerializeObject((object)Instance, (Formatting)1)); MelonLogger.Msg("[RainsCarMod] Created default Dealer_Config.json"); return; } try { string text2 = File.ReadAllText(path); Instance = JsonConvert.DeserializeObject<DealerConfig>(text2) ?? new DealerConfig(); MelonLogger.Msg("[RainsCarMod] Loaded Dealer_Config.json"); } catch { MelonLogger.Warning("[RainsCarMod] Failed to parse Dealer_Config.json, using defaults."); Instance = new DealerConfig(); } } } public class CarModLoader : MelonMod { [HarmonyPatch(typeof(VehicleManager), "Awake")] private static class Patch_VehicleManager_Awake { private static void Postfix(VehicleManager __instance) { try { TryRegisterVehiclesInto(__instance); } catch (Exception arg) { MelonLogger.Error($"[Early Vehicle Register] {arg}"); } } } [HarmonyPatch(typeof(NetworkManager), "Awake")] private static class Patch_NetworkManager_Awake { private static void Postfix(NetworkManager __instance) { try { TryRegisterAllSpawnables(); } catch (Exception arg) { MelonLogger.Error($"[Early Spawnable Register] {arg}"); } } } [CompilerGenerated] private sealed class <InjectAndAssignCarDealerInterface>d__20 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public CarModLoader <>4__this; private GameObject <go>5__1; private Type <type>5__2; private Component <comp>5__3; private Component <intObj>5__4; private Component <canvas>5__5; private Transform <camPos>5__6; private FieldInfo <field>5__7; private EventInfo <eventInfo>5__8; private EventInfo <onEnd>5__9; private MethodInfo <method>5__10; private Delegate <del>5__11; private MethodInfo <method>5__12; private Delegate <del>5__13; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <InjectAndAssignCarDealerInterface>d__20(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <go>5__1 = null; <type>5__2 = null; <comp>5__3 = null; <intObj>5__4 = null; <canvas>5__5 = null; <camPos>5__6 = null; <field>5__7 = null; <eventInfo>5__8 = null; <onEnd>5__9 = null; <method>5__10 = null; <del>5__11 = null; <method>5__12 = null; <del>5__13 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; <go>5__1 = GameObject.Find("CarDealerComputer"); if ((Object)(object)<go>5__1 == (Object)null) { MelonLogger.Error("❌ Could not find CarDealerComputer in scene."); return false; } if ((Object)(object)<go>5__1.GetComponent<UIManager>() == (Object)null) { <go>5__1.AddComponent<UIManager>(); MelonLogger.Msg("\ud83e\udde9 Attached UIManager to CarDealerComputer."); } <type>5__2 = Type.GetType("RainsCarMod.CarDealerInterface, RainsCarMod"); if (<type>5__2 == null) { MelonLogger.Error("❌ CarDealerInterface type not found."); return false; } <comp>5__3 = <go>5__1.AddComponent(<type>5__2); <intObj>5__4 = <go>5__1.GetComponent("InteractableObject"); <canvas>5__5 = <go>5__1.GetComponentInChildren(typeof(Canvas), true); <camPos>5__6 = <go>5__1.transform.Find("CameraPosition"); <type>5__2.GetField("intObj")?.SetValue(<comp>5__3, <intObj>5__4); <type>5__2.GetField("canvas")?.SetValue(<comp>5__3, <canvas>5__5); <type>5__2.GetField("cameraPosition")?.SetValue(<comp>5__3, <camPos>5__6); if ((Object)(object)<intObj>5__4 != (Object)null) { <eventInfo>5__8 = ((object)<intObj>5__4).GetType().GetEvent("onInteractStart"); if (<eventInfo>5__8 != null) { <method>5__10 = <type>5__2.GetMethod("Interacted"); <del>5__11 = Delegate.CreateDelegate(<eventInfo>5__8.EventHandlerType, <comp>5__3, <method>5__10); <eventInfo>5__8.AddEventHandler(<intObj>5__4, <del>5__11); <method>5__10 = null; <del>5__11 = null; } <onEnd>5__9 = ((object)<intObj>5__4).GetType().GetEvent("onInteractEnd"); if (<onEnd>5__9 != null) { <method>5__12 = <type>5__2.GetMethod("Close"); <del>5__13 = Delegate.CreateDelegate(<onEnd>5__9.EventHandlerType, <comp>5__3, <method>5__12); <onEnd>5__9.AddEventHandler(<intObj>5__4, <del>5__13); <method>5__12 = null; <del>5__13 = null; } <eventInfo>5__8 = null; <onEnd>5__9 = null; } <field>5__7 = <type>5__2.GetField("OnUIRequested"); if (<field>5__7 != null) { <field>5__7.SetValue(null, (Action)delegate { GameObject val = GameObject.Find("CarDealerComputer"); if ((Object)(object)val == (Object)null) { MelonLogger.Warning("⚠\ufe0f Could not find CarDealerComputer."); } else { UIManager componentInChildren = val.GetComponentInChildren<UIManager>(true); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.ShowUI(); } else { MelonLogger.Warning("⚠\ufe0f UIManager not found on CarDealerComputer."); } } }); } MelonLogger.Msg("✅ Fully injected CarDealerInterface and interaction events."); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <InjectMapExtension>d__17 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public CarModLoader <>4__this; private GameObject <buildingPrefab>5__1; private GameObject <building>5__2; private GameObject <computerPrefab>5__3; private GameObject <computer>5__4; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <InjectMapExtension>d__17(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <buildingPrefab>5__1 = null; <building>5__2 = null; <computerPrefab>5__3 = null; <computer>5__4 = null; <>1__state = -2; } private bool MoveNext() { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; if (!LoadedPrefabs.TryGetValue("CarDealership", out <buildingPrefab>5__1)) { MelonLogger.Error("❌ CarDealership prefab not found."); return false; } <building>5__2 = Object.Instantiate<GameObject>(<buildingPrefab>5__1, mapExtensionPosition, mapExtensionRotation); ((Object)<building>5__2).name = "CarDealership"; <>4__this.SetAllChildrenActive(<building>5__2, state: true); MelonLogger.Msg("\ud83c\udfd7\ufe0f Injected CarDealership into scene."); if (!LoadedPrefabs.TryGetValue("CarDealerComputer", out <computerPrefab>5__3)) { MelonLogger.Error("❌ CarDealerComputer prefab not found."); return false; } <computer>5__4 = Object.Instantiate<GameObject>(<computerPrefab>5__3, new Vector3(-60.05f, -1.05f, -16.22f), Quaternion.Euler(0f, 150f, 0f)); ((Object)<computer>5__4).name = "CarDealerComputer"; <computer>5__4.SetActive(true); MelonLogger.Msg("\ud83d\udcbb Injected CarDealerComputer."); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <RegisterModdedVehicles>d__16 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public CarModLoader <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <RegisterModdedVehicles>d__16(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (_didEarlyVehicleRegister && _didEarlySpawnableRegister) { return false; } <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; if ((Object)(object)NetworkSingleton<VehicleManager>.Instance == (Object)null) { MelonLogger.Warning("⚠\ufe0f Fallback: VehicleManager.Instance is null; waiting a frame."); <>2__current = null; <>1__state = 2; return true; } break; case 2: <>1__state = -1; break; } if ((Object)(object)NetworkSingleton<VehicleManager>.Instance != (Object)null) { TryRegisterVehiclesInto(NetworkSingleton<VehicleManager>.Instance); } TryRegisterAllSpawnables(); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public static readonly Dictionary<string, GameObject> LoadedPrefabs = new Dictionary<string, GameObject>(); private GameObject carUIRoot; public static readonly Vector3 mapExtensionPosition = new Vector3(-51.5491f, 19.9f, -27.9102f); public static readonly Quaternion mapExtensionRotation = Quaternion.Euler(270f, 150f, 0f); public static readonly Vector3 carSpawnPosition = new Vector3(-46.45f, -1.5f, -31.62f); public static readonly Quaternion carSpawnRotation = Quaternion.Euler(0f, 210f, 0f); private static bool _didEarlyVehicleRegister; private static bool _didEarlySpawnableRegister; private static Harmony _h; public override void OnApplicationStart() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown DealerConfig.Load(); LoadEmbeddedBundle(); _h = new Harmony("RainsCarMod.EarlyHooks"); _h.PatchAll(); MelonLogger.Msg("[RainsCarMod] Harmony early hooks installed."); } public override void OnSceneWasLoaded(int buildIndex, string sceneName) { if (!(sceneName != "Main")) { if (!DealerConfig.Instance.enableDealership) { MelonLogger.Msg("[RainsCarMod] \ud83d\udeab Dealership injection disabled by config."); return; } MelonCoroutines.Start(InjectMapExtension()); MelonCoroutines.Start(RegisterModdedVehicles()); MelonCoroutines.Start(InjectAndAssignCarDealerInterface()); } } private static void TryRegisterVehiclesInto(VehicleManager vm) { if ((Object)(object)vm == (Object)null) { return; } int num = 0; foreach (KeyValuePair<string, GameObject> loadedPrefab in LoadedPrefabs) { string prefabKey = loadedPrefab.Key; GameObject value = loadedPrefab.Value; if (!((Object)(object)value == (Object)null) && !vm.VehiclePrefabs.Any((LandVehicle v) => (Object)(object)v != (Object)null && ((Object)v).name == prefabKey)) { LandVehicle component = value.GetComponent<LandVehicle>(); if (!((Object)(object)component == (Object)null)) { ((Object)value).name = prefabKey; component.vehicleName = prefabKey; vm.VehiclePrefabs.Add(component); num++; TryRegisterSpawnable(value); } } } if (num > 0) { _didEarlyVehicleRegister = true; MelonLogger.Msg($"✅ Early-registered {num} modded vehicles into VehicleManager."); } else { MelonLogger.Msg("ℹ\ufe0f Early vehicle registration: nothing new to add."); } } private static bool SpawnablesContains(NetworkManager nm, NetworkObject no) { if ((Object)(object)nm == (Object)null || (Object)(object)no == (Object)null) { return false; } PrefabObjects spawnablePrefabs = nm.SpawnablePrefabs; if ((Object)(object)spawnablePrefabs == (Object)null) { return false; } Type type = ((object)spawnablePrefabs).GetType(); MethodInfo method = type.GetMethod("ContainsObject", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(NetworkObject) }, null); if (method != null) { return (bool)method.Invoke(spawnablePrefabs, new object[1] { no }); } method = type.GetMethod("Contains", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(NetworkObject) }, null); if (method != null) { return (bool)method.Invoke(spawnablePrefabs, new object[1] { no }); } PropertyInfo property = type.GetProperty("Prefabs", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.GetValue(spawnablePrefabs) is IEnumerable enumerable) { foreach (object item in enumerable) { if (item == no) { return true; } NetworkObject val = (NetworkObject)((item is NetworkObject) ? item : null); if (val != null && (Object)(object)val == (Object)(object)no) { return true; } NetworkObject val2 = (NetworkObject)((item is NetworkObject) ? item : null); if (val2 != null && ((Object)val2).name == ((Object)no).name) { return true; } } } return false; } private static bool SpawnablesAdd(NetworkManager nm, NetworkObject no) { if ((Object)(object)nm == (Object)null || (Object)(object)no == (Object)null) { return false; } PrefabObjects spawnablePrefabs = nm.SpawnablePrefabs; if ((Object)(object)spawnablePrefabs == (Object)null) { return false; } Type type = ((object)spawnablePrefabs).GetType(); MethodInfo method = type.GetMethod("AddObject", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(NetworkObject) }, null); if (method != null) { method.Invoke(spawnablePrefabs, new object[1] { no }); return true; } method = type.GetMethod("Add", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(NetworkObject) }, null); if (method != null) { method.Invoke(spawnablePrefabs, new object[1] { no }); return true; } PropertyInfo property = type.GetProperty("Prefabs", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null) { object value = property.GetValue(spawnablePrefabs); if (value is IList list) { list.Add(no); return true; } } MelonLogger.Warning("[RainsCarMod] Could not add spawnable via known FishNet APIs."); return false; } private static void TryRegisterSpawnable(GameObject prefab) { if (!((Object)(object)prefab == (Object)null)) { NetworkObject component = prefab.GetComponent<NetworkObject>(); NetworkManager networkManager = InstanceFinder.NetworkManager; if ((Object)(object)component != (Object)null && (Object)(object)networkManager != (Object)null && !SpawnablesContains(InstanceFinder.NetworkManager, component) && SpawnablesAdd(InstanceFinder.NetworkManager, component)) { _didEarlySpawnableRegister = true; } } } private static void TryRegisterAllSpawnables() { NetworkManager networkManager = InstanceFinder.NetworkManager; if ((Object)(object)networkManager == (Object)null) { return; } int num = 0; foreach (GameObject value in LoadedPrefabs.Values) { NetworkObject val = (((Object)(object)value != (Object)null) ? value.GetComponent<NetworkObject>() : null); if (!((Object)(object)val == (Object)null) && !SpawnablesContains(networkManager, val) && SpawnablesAdd(networkManager, val)) { num++; } } if (num > 0) { _didEarlySpawnableRegister = true; MelonLogger.Msg($"✅ Early-registered {num} spawnable prefabs in FishNet."); } } [IteratorStateMachine(typeof(<RegisterModdedVehicles>d__16))] private IEnumerator RegisterModdedVehicles() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <RegisterModdedVehicles>d__16(0) { <>4__this = this }; } [IteratorStateMachine(typeof(<InjectMapExtension>d__17))] private IEnumerator InjectMapExtension() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <InjectMapExtension>d__17(0) { <>4__this = this }; } private void SetAllChildrenActive(GameObject parent, bool state) { Transform[] componentsInChildren = parent.GetComponentsInChildren<Transform>(true); foreach (Transform val in componentsInChildren) { ((Component)val).gameObject.SetActive(state); } } private void LoadEmbeddedBundle() { Assembly executingAssembly = Assembly.GetExecutingAssembly(); using Stream stream = executingAssembly.GetManifestResourceStream("RainsCarMod.Resources.carmod"); if (stream == null) { MelonLogger.Error("❌ Could not find embedded carmod bundle."); return; } using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); AssetBundle val = AssetBundle.LoadFromMemory(memoryStream.ToArray()); GameObject[] array = val.LoadAllAssets<GameObject>(); foreach (GameObject val2 in array) { if (!LoadedPrefabs.ContainsKey(((Object)val2).name)) { LoadedPrefabs[((Object)val2).name] = val2; } } MelonLogger.Msg("✅ Loaded car prefabs from bundle."); } [IteratorStateMachine(typeof(<InjectAndAssignCarDealerInterface>d__20))] private IEnumerator InjectAndAssignCarDealerInterface() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <InjectAndAssignCarDealerInterface>d__20(0) { <>4__this = this }; } } [Serializable] public class VehiclePriceEntry { public string name; public int price; } [Serializable] public class VehiclePriceWrapper { public List<VehiclePriceEntry> Entries; public Dictionary<string, int> ToDictionary() { Dictionary<string, int> dictionary = new Dictionary<string, int>(); if (Entries != null) { foreach (VehiclePriceEntry entry in Entries) { if (!string.IsNullOrEmpty(entry.name)) { dictionary[entry.name.Replace(" ", "_")] = entry.price; } } } return dictionary; } } public class UIManager : MonoBehaviour { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static UnityAction <>9__15_0; internal void <AddCloseListener>b__15_0() { OnUICloseRequested?.Invoke(); Cursor.lockState = (CursorLockMode)1; Cursor.visible = false; } } private string pendingPrefabKey = null; private GameObject confirmPopup; private TextMeshProUGUI confirmText; private static TMP_FontAsset liberationFont; private static Dictionary<string, int> VehiclePrices = new Dictionary<string, int>(); public static Action OnUICloseRequested; private Transform uiRoot; private Image vehicleIconImage; private void Start() { if (!DealerConfig.Instance.enableDealership) { MelonLogger.Msg("\ud83d\udee1\ufe0f UIManager.Start skipped because dealership is disabled."); return; } uiRoot = ((Component)this).transform.Find("Panel"); if ((Object)(object)uiRoot == (Object)null) { MelonLogger.Error("❌ UI root panel not found under CarDealerComputer."); return; } liberationFont = Resources.Load<TMP_FontAsset>("Fonts & Materials/LiberationSans SDF"); if ((Object)(object)liberationFont == (Object)null) { MelonLogger.Warning("❌ Could not load LiberationSans SDF font."); } FixInsufficientFundsPopupFont(); SetupConfirmPopup(); LoadVehiclePricesFromJson(); AddButtonListener("Buy Bugatti Tourbillon", "Bugatti_Tourbillon"); AddButtonListener("Buy GTR R35", "GTR_R35"); AddButtonListener("Buy GTR R34", "GTR_R34"); AddButtonListener("Buy Demon", "Demon"); AddButtonListener("Buy Rolls Royce Ghost", "Rolls_Royce_Ghost"); AddButtonListener("Buy Driftcar", "driftcar"); AddButtonListener("Buy Supercar", "supercar"); AddButtonListener("Buy Soup Car", "canofsoupcar"); AddButtonListener("Buy Lamborghini Veneno", "Lamborghini_Veneno"); AddButtonListener("Buy Cyber Truck", "Cyber_Truck"); AddButtonListener("Buy Koenigsegg CC850", "Koenigsegg_CC850"); AddButtonListener("Buy Lancia Delta", "Lancia_Delta"); AddButtonListener("Buy El Camino", "El_Camino"); AddCloseListener("Close"); } private void SetupConfirmPopup() { //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Expected O, but got Unknown //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Expected O, but got Unknown Transform obj = FindDeepChild(((Component)this).transform, "PurchaseConfirmPopup"); confirmPopup = ((obj != null) ? ((Component)obj).gameObject : null); if ((Object)(object)confirmPopup == (Object)null) { MelonLogger.Error("❌ PurchaseConfirmPopup not found."); return; } confirmPopup.SetActive(false); Transform obj2 = FindDeepChild(confirmPopup.transform, "ConfirmPurchaseText"); confirmText = ((obj2 != null) ? ((Component)obj2).GetComponent<TextMeshProUGUI>() : null); if ((Object)(object)confirmText != (Object)null && (Object)(object)liberationFont != (Object)null) { ((TMP_Text)confirmText).font = liberationFont; ((TMP_Text)confirmText).fontSize = 28f; } Transform obj3 = FindDeepChild(confirmPopup.transform, "VehicleIcon"); vehicleIconImage = ((obj3 != null) ? ((Component)obj3).GetComponent<Image>() : null); if ((Object)(object)vehicleIconImage == (Object)null) { MelonLogger.Warning("⚠\ufe0f VehicleIcon image not found inside PurchaseConfirmPopup."); } Transform obj4 = FindDeepChild(confirmPopup.transform, "ConfirmPurchaseButton"); Button val = ((obj4 != null) ? ((Component)obj4).GetComponent<Button>() : null); if ((Object)(object)val != (Object)null) { ((UnityEvent)val.onClick).AddListener(new UnityAction(ConfirmPurchase)); TextMeshProUGUI componentInChildren = ((Component)val).GetComponentInChildren<TextMeshProUGUI>(true); if ((Object)(object)componentInChildren != (Object)null && (Object)(object)liberationFont != (Object)null) { ((TMP_Text)componentInChildren).font = liberationFont; ((TMP_Text)componentInChildren).text = "Confirm Purchase"; } } Transform obj5 = FindDeepChild(confirmPopup.transform, "CancelPurchaseButton"); Button val2 = ((obj5 != null) ? ((Component)obj5).GetComponent<Button>() : null); if ((Object)(object)val2 != (Object)null) { ((UnityEvent)val2.onClick).AddListener((UnityAction)delegate { confirmPopup.SetActive(false); pendingPrefabKey = null; }); TextMeshProUGUI componentInChildren2 = ((Component)val2).GetComponentInChildren<TextMeshProUGUI>(true); if ((Object)(object)componentInChildren2 != (Object)null && (Object)(object)liberationFont != (Object)null) { ((TMP_Text)componentInChildren2).font = liberationFont; ((TMP_Text)componentInChildren2).text = "Cancel Purchase"; } } } private void ConfirmPurchase() { confirmPopup.SetActive(false); if (!string.IsNullOrEmpty(pendingPrefabKey)) { if (!VehiclePrices.TryGetValue(pendingPrefabKey, out var value)) { value = 500; } MoneyManager instance = NetworkSingleton<MoneyManager>.Instance; if (instance.cashBalance < (float)value) { ShowInsufficientFundsMessage(); return; } TrySpawnVehicle(pendingPrefabKey, InstanceFinder.ClientManager.Connection); OnUICloseRequested?.Invoke(); pendingPrefabKey = null; } } public void ShowUI() { Cursor.visible = true; Cursor.lockState = (CursorLockMode)0; } private void ShowInsufficientFundsMessage() { Transform val = FindDeepChild(((Component)this).transform, "InsufficientFundsPopup"); if (!((Object)(object)val == (Object)null)) { ((Component)val).gameObject.SetActive(true); ((Component)val).transform.SetAsLastSibling(); Canvas val2 = ((Component)val).GetComponent<Canvas>() ?? ((Component)val).gameObject.AddComponent<Canvas>(); val2.overrideSorting = true; val2.sortingOrder = 10000; ((MonoBehaviour)this).Invoke("HideInsufficientFundsMessage", 1f); } } private void HideInsufficientFundsMessage() { Transform val = FindDeepChild(((Component)this).transform, "InsufficientFundsPopup"); if ((Object)(object)val != (Object)null) { ((Component)val).gameObject.SetActive(false); } } private void AddButtonListener(string buttonName, string prefabKey) { //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Expected O, but got Unknown Transform buttonGO = FindDeepChild(((Component)this).transform, buttonName); Button val = default(Button); if ((Object)(object)buttonGO == (Object)null || !((Component)buttonGO).TryGetComponent<Button>(ref val)) { MelonLogger.Error("❌ Button not found: " + buttonName); return; } TextMeshProUGUI componentInChildren = ((Component)buttonGO).GetComponentInChildren<TextMeshProUGUI>(); if ((Object)(object)componentInChildren != (Object)null && (Object)(object)liberationFont != (Object)null) { ((TMP_Text)componentInChildren).font = liberationFont; ((TMP_Text)componentInChildren).text = buttonName; } ((UnityEvent)val.onClick).AddListener((UnityAction)delegate { //IL_009d: Unknown result type (might be due to invalid IL or missing references) if (!VehiclePrices.TryGetValue(prefabKey, out var value)) { value = 500; } pendingPrefabKey = prefabKey; Transform obj = FindDeepChild(((Component)buttonGO).transform, "VehicleIcon"); Image val2 = ((obj != null) ? ((Component)obj).GetComponent<Image>() : null); if ((Object)(object)val2 != (Object)null && (Object)(object)vehicleIconImage != (Object)null) { vehicleIconImage.sprite = val2.sprite; ((Graphic)vehicleIconImage).color = Color.white; vehicleIconImage.preserveAspect = true; } if ((Object)(object)confirmText != (Object)null) { ((TMP_Text)confirmText).text = string.Format("Purchase {0} for ${1:N0}?", prefabKey.Replace("_", " "), value); } GameObject obj2 = confirmPopup; if (obj2 != null) { obj2.SetActive(true); } confirmPopup.transform.SetAsLastSibling(); }); } private void AddCloseListener(string name) { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown Transform val = FindDeepChild(uiRoot, name); Button val2 = default(Button); if ((Object)(object)val == (Object)null || !((Component)val).TryGetComponent<Button>(ref val2)) { MelonLogger.Error("❌ Close button not found."); return; } TextMeshProUGUI componentInChildren = ((Component)val).GetComponentInChildren<TextMeshProUGUI>(); if ((Object)(object)componentInChildren != (Object)null && (Object)(object)liberationFont != (Object)null) { ((TMP_Text)componentInChildren).font = liberationFont; ((TMP_Text)componentInChildren).text = name; } ButtonClickedEvent onClick = val2.onClick; object obj = <>c.<>9__15_0; if (obj == null) { UnityAction val3 = delegate { OnUICloseRequested?.Invoke(); Cursor.lockState = (CursorLockMode)1; Cursor.visible = false; }; <>c.<>9__15_0 = val3; obj = (object)val3; } ((UnityEvent)onClick).AddListener((UnityAction)obj); } private void LoadVehiclePricesFromJson() { try { string text = Path.Combine(MelonEnvironment.UserDataDirectory, "RainsCarMod"); string path = Path.Combine(text, "VehiclePrices.json"); if (!Directory.Exists(text)) { Directory.CreateDirectory(text); } if (!File.Exists(path)) { VehiclePriceWrapper vehiclePriceWrapper = new VehiclePriceWrapper { Entries = new List<VehiclePriceEntry> { new VehiclePriceEntry { name = "GTR R34", price = 60000 }, new VehiclePriceEntry { name = "GTR R35", price = 75000 }, new VehiclePriceEntry { name = "Demon", price = 70000 }, new VehiclePriceEntry { name = "Bugatti Tourbillon", price = 500000 }, new VehiclePriceEntry { name = "driftcar", price = 15000 }, new VehiclePriceEntry { name = "supercar", price = 100000 }, new VehiclePriceEntry { name = "canofsoupcar", price = 500 }, new VehiclePriceEntry { name = "Rolls Royce Ghost", price = 200000 }, new VehiclePriceEntry { name = "Lamborghini Veneno", price = 300000 }, new VehiclePriceEntry { name = "Cyber Truck", price = 55000 }, new VehiclePriceEntry { name = "Koenigsegg CC850", price = 360000 }, new VehiclePriceEntry { name = "Lancia_Delta", price = 80000 }, new VehiclePriceEntry { name = "El_Camino", price = 25000 } } }; File.WriteAllText(path, JsonConvert.SerializeObject((object)vehiclePriceWrapper, (Formatting)1)); VehiclePrices = vehiclePriceWrapper.ToDictionary(); MelonLogger.Msg("✅ Created default VehiclePrices.json"); } else { VehiclePriceWrapper vehiclePriceWrapper2 = JsonConvert.DeserializeObject<VehiclePriceWrapper>(File.ReadAllText(path)); if (vehiclePriceWrapper2?.Entries != null) { VehiclePrices = vehiclePriceWrapper2.ToDictionary(); MelonLogger.Msg($"✅ Loaded {VehiclePrices.Count} vehicle prices."); } } } catch (Exception arg) { MelonLogger.Error($"❌ Error parsing VehiclePrices.json: {arg}"); } } private void FixInsufficientFundsPopupFont() { //IL_005d: Unknown result type (might be due to invalid IL or missing references) Transform val = FindDeepChild(((Component)this).transform, "InsufficientFundsPopup"); if (!((Object)(object)val == (Object)null)) { TextMeshProUGUI componentInChildren = ((Component)val).GetComponentInChildren<TextMeshProUGUI>(true); if ((Object)(object)componentInChildren != (Object)null && (Object)(object)liberationFont != (Object)null) { ((TMP_Text)componentInChildren).font = liberationFont; ((TMP_Text)componentInChildren).fontSize = 32f; ((Graphic)componentInChildren).color = Color.black; } } } public static void TrySpawnVehicle(string prefabKey, NetworkConnection conn) { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) if (!InstanceFinder.IsServer) { return; } NetworkObject firstObject = conn.FirstObject; if ((Object)(object)firstObject == (Object)null) { return; } if (!VehiclePrices.TryGetValue(prefabKey, out var value)) { value = 500; } MoneyManager instance = NetworkSingleton<MoneyManager>.Instance; if (!(instance.cashBalance < (float)value) && CarModLoader.LoadedPrefabs.TryGetValue(prefabKey, out var value2)) { instance.ChangeCashBalance((float)(-value), true, false); GameObject val = Object.Instantiate<GameObject>(value2, CarModLoader.carSpawnPosition, CarModLoader.carSpawnRotation); InstanceFinder.ServerManager.Spawn(val, conn, default(Scene)); LandVehicle component = val.GetComponent<LandVehicle>(); if ((Object)(object)component != (Object)null && !NetworkSingleton<VehicleManager>.Instance.PlayerOwnedVehicles.Contains(component)) { NetworkSingleton<VehicleManager>.Instance.PlayerOwnedVehicles.Add(component); } MelonLogger.Msg($"\ud83d\ude97 Spawned {prefabKey} for {conn.ClientId}"); } } private Transform FindDeepChild(Transform parent, string name) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown foreach (Transform item in parent) { Transform val = item; if (((Object)val).name == name) { return val; } Transform val2 = FindDeepChild(val, name); if ((Object)(object)val2 != (Object)null) { return val2; } } return null; } } } namespace RainsCarMod.Logging { public static class Log { public static void LogInfo(string message) { Melon<Core>.Logger.Msg(message); } public static void LogWarning(string message) { Melon<Core>.Logger.Warning(message); } public static void LogError(string message) { Melon<Core>.Logger.Error(message); } public static void LogFatal(string message) { Melon<Core>.Logger.BigError(message); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }