Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of Rollin v1.0.4
Rollin.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using Chassis.Api; using HarmonyLib; using Il2CppFishNet; using Il2CppFishNet.Connection; using Il2CppFishNet.Managing; using Il2CppFishNet.Managing.Object; using Il2CppFishNet.Object; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppScheduleOne; using Il2CppScheduleOne.AvatarFramework; using Il2CppScheduleOne.Core.Weather; using Il2CppScheduleOne.DevUtilities; using Il2CppScheduleOne.Interaction; using Il2CppScheduleOne.ItemFramework; using Il2CppScheduleOne.Lighting; using Il2CppScheduleOne.Persistence; using Il2CppScheduleOne.Persistence.Datas; using Il2CppScheduleOne.PlayerScripts; using Il2CppScheduleOne.Quests; using Il2CppScheduleOne.Storage; using Il2CppScheduleOne.Vehicles; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using Il2CppSystem.Reflection; using Il2CppTMPro; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using Rollin; using Rollin.Chair; using Rollin.Compat; using Rollin.Net; using Rollin.Tuning; using UnityEngine; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(Core), "Rollin", "1.0.4", "DooDesch", "https://github.com/DooDesch-Mods/ScheduleOne-Rollin")] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: MelonAdditionalDependencies(new string[] { "Chassis" })] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("DooDesch")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © DooDesch")] [assembly: AssemblyFileVersion("1.0.4.0")] [assembly: AssemblyInformationalVersion("1.0.4+4e8710ba50014fbc91c558555aae115256d96cd3")] [assembly: AssemblyProduct("Rollin")] [assembly: AssemblyTitle("Rollin")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: AssemblyMetadata("AI_Assisted_Creation", "This assembly was partially created with the assistance of Generative AI.")] [assembly: AssemblyMetadata("AI_Model_Vendor", "Anthropic/OpenAI")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.4.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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 DooDesch { internal static class ModVersion { internal const string Current = "1.0.4"; } } namespace Rollin { public sealed class Core : MelonMod { private bool _inWorld; private static readonly Dictionary<string, float> _lastError = new Dictionary<string, float>(); private static readonly Dictionary<string, int> _muted = new Dictionary<string, int>(); public static Core Instance { get; private set; } public static Instance Log { get; private set; } public override void OnInitializeMelon() { Instance = this; Log = ((MelonBase)this).LoggerInstance; int num = 0; foreach (MethodBase patchedMethod in ((MelonBase)this).HarmonyInstance.GetPatchedMethods()) { _ = patchedMethod; num++; } Log.Msg("[Core] Harmony patches applied by MelonLoader on " + num + " method(s)."); RollinNet.Apply(((MelonBase)this).HarmonyInstance); Start("sync", Sync.Init); Start("wheelchair profile", WheelchairProfile.Register); Start("garage", Garage.Init); Start("tuning effects", Effects.Init); Start("tuning menu", Menu.Init); Start("stock trim", StockTrim.Init); Log.Msg("Rollin loaded."); } public override void OnSceneWasLoaded(int buildIndex, string sceneName) { _inWorld = sceneName == "Main"; if (!_inWorld) { ResetWorld(); } } public override void OnSceneWasUnloaded(int buildIndex, string sceneName) { _inWorld = false; ResetWorld(); } private static void ResetWorld() { Sync.Reset(); Ids.Reset(); Push.Reset(); PropSwap.Reset(); WheelchairModel.Reset(); Garage.Reset(); Effects.Reset(); GameMeshes.Reset(); Menu.Reset(); Cargo.Reset(); StockTrim.Reset(); } public override void OnLateUpdate() { if (_inWorld) { Guard("push placement", Push.LateTick); Guard("tuning effects", Effects.LateTick); } } public override void OnUpdate() { if (_inWorld) { Guard("sync", Sync.Tick); Guard("prop swap", PropSwap.Tick); Guard("push", Push.Tick); Guard("garage", Garage.Tick); Guard("cargo", Cargo.Tick); Guard("tuning menu", Menu.Tick); } } private static void Start(string what, Action a) { try { a(); } catch (Exception ex) { Log.Error("[Core] " + what + " did not start and stays off: " + ex); } } private static void Guard(string what, Action a) { try { a(); } catch (Exception ex) { if (_lastError.TryGetValue(what, out var value) && Time.time - value < 5f) { _muted.TryGetValue(what, out var value2); _muted[what] = value2 + 1; return; } _lastError[what] = Time.time; _muted.TryGetValue(what, out var value3); _muted[what] = 0; Log.Error("[Core] " + what + " failed this frame" + ((value3 > 0) ? (" (and " + value3 + " more time(s) in the last 5 s)") : "") + ": " + ex); } } } } namespace Rollin.Tuning { internal static class Cargo { [HarmonyPatch(typeof(LandVehicle), "Hovered")] private static class HullHover { [HarmonyPriority(0)] private static void Postfix(LandVehicle __instance) { InteractableObject intObj = __instance.intObj; if (!WheelchairType.Is(__instance) || (Object)(object)intObj == (Object)null) { return; } BoxCollider val = (Push.LocalPushing ? null : AimedBox(__instance)); if ((Object)(object)val == (Object)null) { if (_labelHome.TryGetValue(((Il2CppObjectBase)intObj).Pointer, out var value)) { intObj.displayLocationCollider = value; _labelHome.Remove(((Il2CppObjectBase)intObj).Pointer); } return; } if (!_labelHome.ContainsKey(((Il2CppObjectBase)intObj).Pointer)) { _labelHome[((Il2CppObjectBase)intObj).Pointer] = intObj.displayLocationCollider; } intObj.displayLocationCollider = (Collider)(object)val; Hovered(intObj); } } [HarmonyPatch(typeof(LandVehicle), "Interacted")] private static class HullInteract { private static bool Prefix(LandVehicle __instance) { if (!WheelchairType.Is(__instance) || (Object)(object)__instance.intObj == (Object)null || Push.LocalPushing || !Aimed(__instance)) { return true; } Core.Log.Msg("[Cargo] E on net " + Ids.Of((Component)(object)__instance) + " aims at the Moving Box, opening it instead of getting in."); Open(__instance.intObj); return false; } } internal const int Slots = 4; internal const string BoxName = "Moving Box"; internal const string TriggerName = "rollin_box_open"; private const float StandKmh = 1f; private static readonly Dictionary<int, KeyValuePair<string, float>> _pending = new Dictionary<int, KeyValuePair<string, float>>(); private const float LoadDelay = 1f; private static readonly Dictionary<IntPtr, Collider> _labelHome = new Dictionary<IntPtr, Collider>(); internal static void Reset() { _pending.Clear(); } internal static void Setup(LandVehicle lv) { StorageEntity val = (((Object)(object)lv != (Object)null) ? lv.Storage : null); if ((Object)(object)val == (Object)null) { Core.Log.Warning("[Cargo] net " + Ids.Of((Component)(object)lv) + " has no trunk - the Moving Box stores nothing."); return; } List<ItemSlot> itemSlots = val.ItemSlots; int num = itemSlots?.Count ?? 0; if (itemSlots != null) { while (itemSlots.Count > 4) { itemSlots.RemoveAt(itemSlots.Count - 1); } } val.SlotCount = 4; val.StorageEntityName = "Moving Box"; val.AccessSettings = (EAccessSettings)2; val.MaxAccessDistance = 3f; Core.Log.Msg("[Cargo] net " + Ids.Of((Component)(object)lv) + ": trunk is the Moving Box, " + num + " -> " + (itemSlots?.Count ?? 0) + " slot(s), open to everyone."); } internal static bool HasItems(LandVehicle lv) { if ((Object)(object)lv != (Object)null && (Object)(object)lv.Storage != (Object)null) { return lv.Storage.ItemCount > 0; } return false; } internal static string Serialize(LandVehicle lv) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (!HasItems(lv)) { return null; } return new ItemSet(lv.Storage.ItemSlots).GetJSON(); } internal static void LoadLater(LandVehicle lv, string json) { if (!((Object)(object)lv == (Object)null) && !string.IsNullOrEmpty(json)) { _pending[Ids.Of((Component)(object)lv)] = new KeyValuePair<string, float>(json, Time.time + 1f); } } internal static void Tick() { if (_pending.Count == 0 || !RollinNet.IsHost) { return; } foreach (int item in new List<int>(_pending.Keys)) { KeyValuePair<string, float> keyValuePair = _pending[item]; if (!(Time.time < keyValuePair.Value)) { LandVehicle val = Ids.Find<LandVehicle>(item); if ((Object)(object)val == (Object)null) { _pending.Remove(item); Core.Log.Warning("[Cargo] net " + item + " is gone before its box contents came back - they stay in the store."); } else if (((NetworkBehaviour)val).IsSpawned) { _pending.Remove(item); Load(val, keyValuePair.Key); } } } } private static void Load(LandVehicle lv, string json) { if ((Object)(object)lv.Storage == (Object)null) { Core.Log.Error("[Cargo] net " + Ids.Of((Component)(object)lv) + " has no trunk - its saved box contents are not loaded."); return; } DeserializedItemSet val = default(DeserializedItemSet); if (!ItemSet.TryDeserialize(json, ref val) || val == null) { Core.Log.Error("[Cargo] the saved box contents of net " + Ids.Of((Component)(object)lv) + " do not read as an item set - not loaded."); return; } val.LoadTo(lv.Storage.ItemSlots); Core.Log.Msg("[Cargo] net " + Ids.Of((Component)(object)lv) + ": " + lv.Storage.ItemCount + " item(s) back in the Moving Box."); } internal static void AddTrigger(Transform root, Bounds box) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("rollin_box_open"); val.transform.SetParent(root, false); val.layer = WheelchairType.InteractionLayer; Vector3 size = ((Bounds)(ref box)).size + new Vector3(0.04f, 0.02f, 0.04f); float num = Mathf.Min(((Bounds)(ref box)).max.y + 0.01f, 0.465f); float num2 = ((Bounds)(ref box)).min.y - 0.01f; size.y = Mathf.Max(0.05f, num - num2); val.transform.localPosition = new Vector3(((Bounds)(ref box)).center.x, (num + num2) * 0.5f, ((Bounds)(ref box)).center.z); BoxCollider obj = val.AddComponent<BoxCollider>(); ((Collider)obj).isTrigger = true; obj.size = size; InteractableObject io = val.AddComponent<InteractableObject>(); io.MaxInteractionRange = 2.5f; io.SetMessage("Open Moving Box"); io.SetInteractableState((EInteractableState)0); io.onHovered.AddListener(UnityAction.op_Implicit((Action)delegate { Hovered(io); })); io.onInteractStart.AddListener(UnityAction.op_Implicit((Action)delegate { Open(io); })); } private static bool Aimed(LandVehicle lv) { return (Object)(object)AimedBox(lv) != (Object)null; } private static BoxCollider AimedBox(LandVehicle lv) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) PlayerCamera instance = PlayerSingleton<PlayerCamera>.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)lv == (Object)null) { return null; } RaycastHit val = default(RaycastHit); foreach (BoxCollider componentsInChild in ((Component)lv).GetComponentsInChildren<BoxCollider>(false)) { if (!(((Object)((Component)componentsInChild).gameObject).name != "rollin_box_open")) { Transform transform = ((Component)instance).transform; return ((Collider)componentsInChild).Raycast(new Ray(transform.position, transform.forward), ref val, 2.5f) ? componentsInChild : null; } } return null; } private static void Hovered(InteractableObject io) { StorageEntity st; string text = Blocked(io, out st); io.SetMessage(text ?? "Open Moving Box"); io.SetInteractableState((EInteractableState)(text != null)); } private static string Blocked(InteractableObject io, out StorageEntity st) { st = null; LandVehicle val = (((Object)(object)io != (Object)null) ? ((Component)io).GetComponentInParent<LandVehicle>() : null); if ((Object)(object)val == (Object)null || (Object)(object)val.Storage == (Object)null) { return "No storage"; } st = val.Storage; if (Mathf.Abs(val.Speed_Kmh) > 1f) { return "Stop to open"; } if (!st.CanBeOpened()) { return "In use"; } return null; } private static void Open(InteractableObject io) { StorageEntity st; string text = Blocked(io, out st); if (text != null) { Core.Log.Msg("[Cargo] box not opened: " + text + "."); return; } Player local = Player.Local; if ((Object)(object)local == (Object)null || (Object)(object)local.CurrentVehicle != (Object)null) { Core.Log.Msg("[Cargo] box not opened: the local player is in a vehicle or not there."); return; } st.Open(); Core.Log.Msg("[Cargo] opened the Moving Box of net " + Ids.Of((Component)(object)((Component)io).GetComponentInParent<LandVehicle>()) + " (" + st.ItemCount + " item(s))."); } } internal static class Effects { private sealed class State { internal LandVehicle Lv; internal float NextScan; internal Transform PivotL; internal Transform PivotR; internal Transform SpinL; internal Transform SpinR; internal Transform Hat; internal Transform HatHome; internal readonly List<Renderer> HatRenderers = new List<Renderer>(); internal readonly List<ParticleSystem> Smokes = new List<ParticleSystem>(); internal readonly List<Wheel> Tyres = new List<Wheel>(); internal bool Squealing; internal readonly List<Transform> Pulses = new List<Transform>(); internal Transform Red; internal Transform Blue; internal Vector3 LastPos; internal bool HasPos; internal float Speed; internal float Accel; internal Player HeadOf; internal Transform Head; } private static readonly Dictionary<IntPtr, State> _chairs = new Dictionary<IntPtr, State>(); private static readonly List<IntPtr> _gone = new List<IntPtr>(); private const float HatLift = 0.14f; private const float MaxLift = 0.24f; internal static int Count => _chairs.Count; internal static void Init() { WheelchairSpawn.Started += delegate(LandVehicle lv) { if ((Object)(object)lv != (Object)null) { _chairs[((Il2CppObjectBase)lv).Pointer] = new State { Lv = lv }; } }; ChassisApi.TuningChanged += delegate(LandVehicle lv, string key) { if ((Object)(object)lv != (Object)null && _chairs.TryGetValue(((Il2CppObjectBase)lv).Pointer, out var value)) { value.NextScan = 0f; } }; } internal static void Reset() { _chairs.Clear(); } internal static void LateTick() { if (_chairs.Count == 0) { return; } _gone.Clear(); foreach (KeyValuePair<IntPtr, State> chair in _chairs) { State value = chair.Value; if ((Object)(object)value.Lv == (Object)null) { _gone.Add(chair.Key); continue; } try { Tick(value); } catch (Exception ex) { Core.Log.Error("[Effects] chair net " + Ids.Of((Component)(object)value.Lv) + " failed and stops moving its parts: " + ex); _gone.Add(chair.Key); } } foreach (IntPtr item in _gone) { _chairs.Remove(item); } } private static void Tick(State s) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) LandVehicle lv = s.Lv; if (Time.time >= s.NextScan) { Scan(s); } float num = Mathf.Max(Time.deltaTime, 0.0001f); Vector3 position = ((Component)lv).transform.position; if (s.HasPos) { float num2 = Vector3.Distance(position, s.LastPos) / num * 3.6f; if (num2 > 300f) { num2 = s.Speed; } float num3 = Mathf.Lerp(s.Speed, num2, 1f - Mathf.Exp((0f - num) * 8f)); s.Accel = Mathf.Lerp(s.Accel, (num3 - s.Speed) / num, 1f - Mathf.Exp((0f - num) * 6f)); s.Speed = num3; } s.LastPos = position; s.HasPos = true; Rims(s); Hat(s); Smoke(s); Squeal(s); Lightbar(s); Pulse(s); } private static void Scan(State s) { s.NextScan = Time.time + 0.5f; Transform transform = ((Component)s.Lv).transform; Transform val = null; Transform val2 = null; if ((Object)(object)s.Hat != (Object)null && (Object)(object)s.Head != (Object)null && (Object)(object)s.Hat.parent == (Object)(object)s.Head) { val = s.Hat; val2 = s.HatHome; } s.PivotL = (((Object)(object)s.PivotL != (Object)null) ? s.PivotL : WheelchairType.Find(transform, "RimPivot_L")); s.PivotR = (((Object)(object)s.PivotR != (Object)null) ? s.PivotR : WheelchairType.Find(transform, "RimPivot_R")); s.SpinL = (s.SpinR = (s.Hat = (s.HatHome = (s.Red = (s.Blue = null))))); s.HatRenderers.Clear(); s.Smokes.Clear(); s.Pulses.Clear(); if (s.Tyres.Count == 0) { foreach (Wheel componentsInChild in ((Component)transform).GetComponentsInChildren<Wheel>(true)) { if ((Object)(object)componentsInChild != (Object)null && componentsInChild.DriftAudioEnabled) { s.Tyres.Add(componentsInChild); } } } foreach (Transform componentsInChild2 in ((Component)transform).GetComponentsInChildren<Transform>(true)) { if ((Object)(object)componentsInChild2 == (Object)null) { continue; } string name = ((Object)componentsInChild2).name; if (name == "Chassis_Tune_neon" && (Object)(object)componentsInChild2.parent == (Object)(object)transform && (Object)(object)componentsInChild2.Find("rollin_neon") == (Object)null) { Models.FitNeon(s.Lv, componentsInChild2); } else { if (!name.StartsWith("rollin_", StringComparison.Ordinal)) { continue; } switch (name) { case "rollin_spin_L": s.SpinL = componentsInChild2; break; case "rollin_spin_R": s.SpinR = componentsInChild2; break; case "rollin_hat": if ((Object)(object)val != (Object)null && Interop.Same((Object)(object)componentsInChild2, (Object)(object)val)) { break; } s.Hat = componentsInChild2; s.HatHome = componentsInChild2.parent; foreach (Renderer componentsInChild3 in ((Component)componentsInChild2).GetComponentsInChildren<Renderer>(true)) { s.HatRenderers.Add(componentsInChild3); } break; case "rollin_smoke": { ParticleSystem val3 = SmokeAt(s.Lv, componentsInChild2); if ((Object)(object)val3 != (Object)null) { s.Smokes.Add(val3); } break; } case "rollin_blink_red": s.Red = componentsInChild2; break; case "rollin_blink_blue": s.Blue = componentsInChild2; break; case "rollin_pulse": s.Pulses.Add(componentsInChild2); break; } } } if ((Object)(object)val == (Object)null) { return; } if ((Object)(object)s.Hat == (Object)null && (Object)(object)val2 != (Object)null && val2.IsChildOf(transform)) { s.Hat = val; s.HatHome = val2; { foreach (Renderer componentsInChild4 in ((Component)val).GetComponentsInChildren<Renderer>(true)) { s.HatRenderers.Add(componentsInChild4); } return; } } if ((Object)(object)val2 != (Object)null) { val.SetParent(val2, true); Core.Log.Msg("[Effects] chair net " + Ids.Of((Component)(object)s.Lv) + ": hat part replaced or removed, the old hat is taken off."); } else { Object.Destroy((Object)(object)((Component)val).gameObject); Core.Log.Msg("[Effects] chair net " + Ids.Of((Component)(object)s.Lv) + ": hat part gone, the hat is taken off the rider's head."); } } private static void Rims(State s) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)s.SpinL != (Object)null && (Object)(object)s.PivotL != (Object)null) { s.SpinL.position = s.PivotL.position; s.SpinL.rotation = s.PivotL.rotation; } if ((Object)(object)s.SpinR != (Object)null && (Object)(object)s.PivotR != (Object)null) { s.SpinR.position = s.PivotR.position; s.SpinR.rotation = s.PivotR.rotation; } } private static void Hat(State s) { //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)s.Hat == (Object)null) { return; } LandVehicle lv = s.Lv; Player val = null; Il2CppReferenceArray<VehicleSeat> seats = lv.Seats; if (seats != null && ((Il2CppArrayBase<VehicleSeat>)(object)seats).Length > 0 && (Object)(object)((Il2CppArrayBase<VehicleSeat>)(object)seats)[0] != (Object)null) { val = ((Il2CppArrayBase<VehicleSeat>)(object)seats)[0].Occupant; } if ((Object)(object)val == (Object)null) { if ((Object)(object)s.Head != (Object)null && (Object)(object)s.Hat.parent == (Object)(object)s.Head) { Core.Log.Msg("[Effects] chair net " + Ids.Of((Component)(object)lv) + ": the rider got up, the hat is back on the seat."); } HatHome(s); ShowHat(s, on: true); s.HeadOf = null; s.Head = null; return; } if ((Object)(object)s.HeadOf == (Object)null || !Interop.Same((Object)(object)s.HeadOf, (Object)(object)val)) { HatHome(s); s.HeadOf = val; s.Head = HeadOf(val); if ((Object)(object)s.Head == (Object)null) { Core.Log.Warning("[Effects] chair net " + Ids.Of((Component)(object)lv) + ": " + ((Object)val).name + " has no head bone - the hat stays on the seat."); } } if (!((Object)(object)s.Head == (Object)null)) { if ((Object)(object)s.Hat.parent != (Object)(object)s.Head) { PutOn(s, val); } Camera main = Camera.main; ShowHat(s, (Object)(object)main == (Object)null || Vector3.Distance(((Component)main).transform.position, s.Head.position) > 0.45f); } } private static void PutOn(State s, Player rider) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) LandVehicle lv = s.Lv; string by; float num = LiftOver(rider, s.Head, out by); Vector3 up = ((Component)lv).transform.up; s.Hat.SetParent(s.Head, true); s.Hat.position = s.Head.position + up * num; s.Hat.rotation = Quaternion.LookRotation(((Component)lv).transform.forward, up); Core.Log.Msg("[Effects] chair net " + Ids.Of((Component)(object)lv) + ": hat on " + ((Object)rider).name + "'s head, " + num.ToString("F2", CultureInfo.InvariantCulture) + " m above the head bone (" + by + ")."); } private static void HatHome(State s) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)s.Hat == (Object)null) && !((Object)(object)s.HatHome == (Object)null) && !((Object)(object)s.Hat.parent == (Object)(object)s.HatHome)) { s.Hat.SetParent(s.HatHome, true); s.Hat.localPosition = Models.HatSeat; s.Hat.localRotation = Quaternion.identity; } } private static void ShowHat(State s, bool on) { foreach (Renderer hatRenderer in s.HatRenderers) { if ((Object)(object)hatRenderer != (Object)null && hatRenderer.enabled != on) { hatRenderer.enabled = on; } } } private static float LiftOver(Player p, Transform head, out string by) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) float num = head.position.y + 0.14f; by = "skull"; foreach (Renderer componentsInChild in ((Component)p.Avatar).GetComponentsInChildren<Renderer>(true)) { if (!((Object)(object)componentsInChild == (Object)null) && componentsInChild.enabled && ((Component)componentsInChild).gameObject.activeInHierarchy) { Bounds bounds = componentsInChild.bounds; if (!(((Bounds)(ref bounds)).size.y > 0.45f) && !(Vector3.Distance(((Bounds)(ref bounds)).center, head.position) > 0.25f) && !(((Bounds)(ref bounds)).max.y <= num)) { num = ((Bounds)(ref bounds)).max.y; by = ((Object)componentsInChild).name; } } } float num2 = num - head.position.y; if (num2 > 0.24f) { by = by + ", capped from " + num2.ToString("F2", CultureInfo.InvariantCulture); num2 = 0.24f; } return num2; } private static Transform HeadOf(Player p) { Avatar val = (((Object)(object)p != (Object)null) ? p.Avatar : null); if ((Object)(object)val == (Object)null) { return null; } Animator val2 = (((Object)(object)val.Animation != (Object)null) ? val.Animation._animator : null); if ((Object)(object)val2 == (Object)null) { val2 = ((Component)val).GetComponentInChildren<Animator>(true); } if ((Object)(object)val2 == (Object)null || !val2.isHuman) { return null; } return val2.GetBoneTransform((HumanBodyBones)10); } private static ParticleSystem SmokeAt(LandVehicle lv, Transform point) { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) Transform val = point.Find("rollin_smoke_fx"); if ((Object)(object)val != (Object)null) { return ((Component)val).GetComponent<ParticleSystem>(); } VehicleFX componentInChildren = ((Component)lv).GetComponentInChildren<VehicleFX>(true); ParticleSystem val2 = (((Object)(object)componentInChildren != (Object)null && componentInChildren.exhaustFX != null && ((Il2CppArrayBase<ParticleSystem>)(object)componentInChildren.exhaustFX).Length > 0) ? ((Il2CppArrayBase<ParticleSystem>)(object)componentInChildren.exhaustFX)[0] : null); if ((Object)(object)val2 == (Object)null) { Core.Log.Warning("[Effects] chair net " + Ids.Of((Component)(object)lv) + " has no exhaust smoke to copy - the tailpipes stay clean."); ((Object)((Component)point).gameObject).name = "rollin_smoke_none"; return null; } GameObject val3 = Object.Instantiate<GameObject>(((Component)val2).gameObject, point, false); ((Object)val3).name = "rollin_smoke_fx"; val3.transform.localPosition = Vector3.zero; val3.transform.localRotation = Quaternion.identity; foreach (Renderer componentsInChild in val3.GetComponentsInChildren<Renderer>(true)) { componentsInChild.enabled = true; } ParticleSystem component = val3.GetComponent<ParticleSystem>(); component.Stop(true, (ParticleSystemStopBehavior)0); Core.Log.Msg("[Effects] chair net " + Ids.Of((Component)(object)lv) + ": exhaust smoke '" + ((Object)val2).name + "' on a tailpipe."); return component; } private static void Smoke(State s) { if (s.Smokes.Count == 0) { return; } bool isOccupied = s.Lv.IsOccupied; foreach (ParticleSystem smoke in s.Smokes) { if (!((Object)(object)smoke == (Object)null)) { if (isOccupied && !smoke.isPlaying) { smoke.Play(true); } else if (!isOccupied && smoke.isEmitting) { smoke.Stop(true, (ParticleSystemStopBehavior)1); } } } } private static void Squeal(State s) { bool flag = false; foreach (Wheel tyre in s.Tyres) { if ((Object)(object)tyre != (Object)null && (Object)(object)tyre.DriftAudioSource != (Object)null && tyre.DriftAudioSource.IsPlaying) { flag = true; break; } } if (flag != s.Squealing) { s.Squealing = flag; Core.Log.Msg("[Effects] chair net " + Ids.Of((Component)(object)s.Lv) + ": tyres " + (flag ? "squeal" : "quiet") + " at " + s.Speed.ToString("F1") + " km/h."); } } private static void Lightbar(State s) { if (!((Object)(object)s.Red == (Object)null) || !((Object)(object)s.Blue == (Object)null)) { bool isOccupied = s.Lv.IsOccupied; float num = Time.time * 3.2f; bool flag = num - Mathf.Floor(num) < 0.5f; bool flag2 = Time.time * 14f % 1f < 0.6f; Blink(s.Red, isOccupied && flag && flag2); Blink(s.Blue, isOccupied && !flag && flag2); } } private static void Blink(Transform t, bool on) { if (!((Object)(object)t == (Object)null)) { Light componentInChildren = ((Component)t).GetComponentInChildren<Light>(true); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.intensity = (on ? 1.2f : 0f); } Transform val = t.Find("rollin_on"); Renderer val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<Renderer>() : null); if ((Object)(object)val2 != (Object)null && val2.enabled != on) { val2.enabled = on; } } } private static void Pulse(State s) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) if (s.Pulses.Count == 0) { return; } float num = (s.Lv.IsOccupied ? Mathf.Pow(Mathf.Max(0f, Mathf.Sin(Time.time * (float)Math.PI * 2f * 2.1f)), 6f) : 0f); Vector3 localScale = Vector3.one * (1f + 0.08f * num); foreach (Transform pulse in s.Pulses) { if ((Object)(object)pulse != (Object)null) { pulse.localScale = localScale; } } } private static string SmokeInfo(ParticleSystem ps) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ps == (Object)null) { return "(gone)"; } ParticleSystemRenderer component = ((Component)ps).GetComponent<ParticleSystemRenderer>(); string[] obj = new string[7] { "(", ps.isPlaying ? "playing" : "stopped", ", ", ps.particleCount.ToString(), " particles, renderer ", null, null }; object obj3; if (!((Object)(object)component == (Object)null)) { string obj2 = (((Renderer)component).enabled ? "on" : "off"); Bounds bounds = ((Renderer)component).bounds; Vector3 size = ((Bounds)(ref bounds)).size; obj3 = obj2 + ", bounds " + ((Vector3)(ref size)).ToString("F2"); } else { obj3 = "none"; } obj[5] = (string)obj3; obj[6] = ")"; return string.Concat(obj); } internal static string Describe() { List<string> list = new List<string>(); foreach (State value in _chairs.Values) { if (!((Object)(object)value.Lv == (Object)null)) { list.Add("net " + Ids.Of((Component)(object)value.Lv) + " " + value.Speed.ToString("F1") + " km/h" + (((Object)(object)value.SpinL != (Object)null) ? ", rims" : "") + (((Object)(object)value.Hat != (Object)null) ? (", hat" + (((Object)(object)value.Head != (Object)null && (Object)(object)value.Hat.parent == (Object)(object)value.Head) ? " on head" : " on seat")) : "") + ((value.Smokes.Count > 0) ? (", " + value.Smokes.Count + " smoking pipe(s) " + SmokeInfo(value.Smokes[0])) : "") + (((Object)(object)value.Red != (Object)null) ? ", lightbar" : "") + ((value.Pulses.Count > 0) ? ", speaker" : "")); } } return "effects: " + ((list.Count == 0) ? "no chairs" : string.Join("; ", list)); } } internal static class GameMeshes { internal const string RimSport = "rim_sport"; internal const string RimMuscle = "rim_muscle"; internal const string Tailpipe = "tailpipe"; internal const string Lightbar = "lightbar"; internal const string JerryCan = "jerrycan"; internal const string Box = "box"; internal const string Umbrella = "umbrella"; internal const string Radio = "radio"; internal const string Gnome = "gnome"; internal static readonly string[] All = new string[9] { "rim_sport", "rim_muscle", "tailpipe", "lightbar", "jerrycan", "box", "umbrella", "radio", "gnome" }; private static readonly Dictionary<string, Transform> _found = new Dictionary<string, Transform>(StringComparer.Ordinal); private static readonly HashSet<string> _missing = new HashSet<string>(StringComparer.Ordinal); private static readonly Regex Skip = new Regex("LOD\\s*_?[1-9]|Impostor|Convex|Collider", RegexOptions.IgnoreCase); internal static Transform Source(string key) { if (_found.TryGetValue(key, out var value) && (Object)(object)value != (Object)null) { return value; } if (_missing.Contains(key)) { return null; } try { value = Find(key); } catch (Exception ex) { Core.Log.Error("[GameMeshes] looking up '" + key + "' failed: " + ex); value = null; } if ((Object)(object)value == (Object)null) { _missing.Add(key); Core.Log.Error("[GameMeshes] no game mesh for '" + key + "' - the part shows nothing."); return null; } _found[key] = value; Core.Log.Msg("[GameMeshes] '" + key + "' from " + PathOf(value) + "."); return value; } internal static void Reset() { _found.Clear(); _missing.Clear(); } private static Transform Find(string key) { switch (key) { case "rim_sport": return Vehicle("cheetah", "SportsCarWheel_FL/ModelContainer/Model/Sports car wheel/sports car wheel"); case "rim_muscle": return Vehicle("hounddog", "MuscleCarWheel_FR/ModelContainer/Model/Muscle Car Wheel/muscle car wheel"); case "tailpipe": return Vehicle("bruiser", "SUV/suv/TailPipe"); case "lightbar": return Vehicle("bruiser_police", "SUV/Lightbar/lightbar"); case "jerrycan": return Item("gasoline", "jerry can"); case "box": return Named("smallbox", null, "Box"); case "umbrella": return Resource("equippables/umbrella/Umbrella_TP", "Umbrella (Static)"); case "radio": return Named("SM_Item_Radio_01", "SM_Item_Radio_01", null); case "gnome": return Named("gnome", null, "Beard"); default: Core.Log.Error("[GameMeshes] unknown source '" + key + "'."); return null; } } internal static bool LightbarMaterials(out Material redOn, out Material redOff, out Material blueOn, out Material blueOff) { redOn = (redOff = (blueOn = (blueOff = null))); Transform val = Source("lightbar"); Transform val2 = (((Object)(object)val != (Object)null) ? val.parent : null); PoliceLight val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponent<PoliceLight>() : null); if ((Object)(object)val3 == (Object)null) { Core.Log.Warning("[GameMeshes] no PoliceLight beside the lightbar - the lenses keep their off colour."); return false; } redOn = val3.RedOnMat; redOff = val3.RedOffMat; blueOn = val3.BlueOnMat; blueOff = val3.BlueOffMat; int num; if ((Object)(object)redOn != (Object)null) { num = (((Object)(object)blueOn != (Object)null) ? 1 : 0); if (num != 0) { goto IL_00a4; } } else { num = 0; } Core.Log.Warning("[GameMeshes] the PoliceLight has no on materials - the lenses keep their off colour."); goto IL_00a4; IL_00a4: return (byte)num != 0; } private static Transform Vehicle(string code, string path) { VehicleManager instance = NetworkSingleton<VehicleManager>.Instance; if ((Object)(object)instance == (Object)null) { Core.Log.Warning("[GameMeshes] no VehicleManager yet for '" + code + "'."); return null; } LandVehicle vehiclePrefab = instance.GetVehiclePrefab(code); if ((Object)(object)vehiclePrefab == (Object)null) { Core.Log.Warning("[GameMeshes] the game has no vehicle '" + code + "'."); return null; } Transform val = ((Component)vehiclePrefab).transform.Find(path); if ((Object)(object)val != (Object)null) { return val; } string name = path.Substring(path.LastIndexOf('/') + 1); val = Descendant(((Component)vehiclePrefab).transform, name); Core.Log.Warning("[GameMeshes] '" + code + "' has no '" + path + "'" + (((Object)(object)val != (Object)null) ? (", took " + PathOf(val) + " instead.") : ".")); return val; } private static Transform Item(string id, string child) { ItemDefinition item = Registry.GetItem(id); if ((Object)(object)item == (Object)null) { Core.Log.Warning("[GameMeshes] the game has no item '" + id + "'."); return null; } StorableItemDefinition val = ((Il2CppObjectBase)item).TryCast<StorableItemDefinition>(); StoredItem val2 = (((Object)(object)val != (Object)null) ? val.StoredItem : null); if ((Object)(object)val2 == (Object)null) { Core.Log.Warning("[GameMeshes] item '" + id + "' has no stored model."); return null; } Transform val3 = Descendant(((Component)val2).transform, child); if ((Object)(object)val3 == (Object)null) { Core.Log.Warning("[GameMeshes] item '" + id + "' has no '" + child + "' under " + ((Object)val2).name + "."); } return val3; } private static Transform Resource(string path, string child) { GameObject val = Resources.Load<GameObject>(path); if ((Object)(object)val == (Object)null) { Core.Log.Warning("[GameMeshes] no Resources prefab '" + path + "'."); return null; } Transform val2 = Descendant(val.transform, child); if ((Object)(object)val2 == (Object)null) { Core.Log.Warning("[GameMeshes] '" + path + "' has no '" + child + "'."); } return val2; } private static Transform Named(string name, string mesh, string child) { int num = 0; foreach (Transform item in Resources.FindObjectsOfTypeAll<Transform>()) { if ((Object)(object)item == (Object)null || ((Object)item).name != name) { continue; } num++; if (child != null && (Object)(object)item.Find(child) == (Object)null) { continue; } if (mesh != null) { MeshFilter component = ((Component)item).GetComponent<MeshFilter>(); if ((Object)(object)component == (Object)null || (Object)(object)component.sharedMesh == (Object)null || ((Object)component.sharedMesh).name != mesh) { continue; } } if (!Batched(item)) { return item; } } Core.Log.Warning("[GameMeshes] " + num + " object(s) named '" + name + "', none with " + (mesh ?? child) + " and its own mesh."); return null; } private static bool Batched(Transform t) { foreach (MeshFilter componentsInChild in ((Component)t).GetComponentsInChildren<MeshFilter>(true)) { if ((Object)(object)componentsInChild.sharedMesh != (Object)null && ((Object)componentsInChild.sharedMesh).name.StartsWith("Combined Mesh", StringComparison.Ordinal)) { return true; } } return false; } private static Transform Descendant(Transform root, string name) { foreach (Transform componentsInChild in ((Component)root).GetComponentsInChildren<Transform>(true)) { if (((Object)componentsInChild).name == name) { return componentsInChild; } } return null; } private static string PathOf(Transform t) { string text = ((Object)t).name; Transform parent = t.parent; while ((Object)(object)parent != (Object)null) { text = ((Object)parent).name + "/" + text; parent = parent.parent; } return text; } internal static Transform Copy(string key, Transform parent, Material fallback = null) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) Transform val = Source(key); if ((Object)(object)val == (Object)null) { return null; } Transform obj = CopyNode(val, parent, fallback); obj.localPosition = Vector3.zero; obj.localRotation = val.rotation; obj.localScale = val.lossyScale; return obj; } private static Transform CopyNode(Transform src, Transform parent, Material fallback) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(((Object)src).name); Transform transform = val.transform; transform.SetParent(parent, false); transform.localPosition = src.localPosition; transform.localRotation = src.localRotation; transform.localScale = src.localScale; MeshFilter component = ((Component)src).GetComponent<MeshFilter>(); MeshRenderer component2 = ((Component)src).GetComponent<MeshRenderer>(); if ((Object)(object)component != (Object)null && (Object)(object)component.sharedMesh != (Object)null && (Object)(object)component2 != (Object)null) { val.AddComponent<MeshFilter>().sharedMesh = component.sharedMesh; MeshRenderer val2 = val.AddComponent<MeshRenderer>(); Il2CppReferenceArray<Material> sharedMaterials = ((Renderer)component2).sharedMaterials; bool flag = false; for (int i = 0; i < ((Il2CppArrayBase<Material>)(object)sharedMaterials).Length; i++) { if ((Object)(object)((Il2CppArrayBase<Material>)(object)sharedMaterials)[i] != (Object)null) { flag = true; } else { ((Il2CppArrayBase<Material>)(object)sharedMaterials)[i] = fallback; } } if (!flag && (Object)(object)fallback == (Object)null) { Core.Log.Warning("[GameMeshes] " + ((Object)src).name + " has no material and no fallback."); } ((Renderer)val2).sharedMaterials = sharedMaterials; } for (int j = 0; j < src.childCount; j++) { Transform child = src.GetChild(j); if (!Skip.IsMatch(((Object)child).name) && (!((Object)(object)((Component)child).GetComponent<Light>() != (Object)null) || !((Object)(object)((Component)child).GetComponent<MeshFilter>() == (Object)null) || child.childCount != 0)) { CopyNode(child, transform, fallback); } } return transform; } internal static Bounds Measure(Transform space, Transform root) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) Bounds result = default(Bounds); bool flag = true; Vector3 val = default(Vector3); foreach (MeshFilter componentsInChild in ((Component)root).GetComponentsInChildren<MeshFilter>(true)) { if ((Object)(object)componentsInChild.sharedMesh == (Object)null) { continue; } Bounds bounds = componentsInChild.sharedMesh.bounds; for (int i = 0; i < 8; i++) { ((Vector3)(ref val))..ctor(((i & 1) == 0) ? ((Bounds)(ref bounds)).min.x : ((Bounds)(ref bounds)).max.x, ((i & 2) == 0) ? ((Bounds)(ref bounds)).min.y : ((Bounds)(ref bounds)).max.y, ((i & 4) == 0) ? ((Bounds)(ref bounds)).min.z : ((Bounds)(ref bounds)).max.z); Vector3 val2 = space.InverseTransformPoint(((Component)componentsInChild).transform.TransformPoint(val)); if (flag) { result = new Bounds(val2, Vector3.zero); flag = false; } else { ((Bounds)(ref result)).Encapsulate(val2); } } } return result; } internal static string Describe(string key) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) Transform val = Source(key); if ((Object)(object)val == (Object)null) { return key + ": missing"; } GameObject val2 = new GameObject("rollin_probe"); try { Transform val3 = Copy(key, val2.transform); Bounds val4 = Measure(val2.transform, val3); int length = ((Component)val3).GetComponentsInChildren<MeshRenderer>(true).Length; HashSet<string> hashSet = new HashSet<string>(); foreach (MeshRenderer componentsInChild in ((Component)val3).GetComponentsInChildren<MeshRenderer>(true)) { foreach (Material item in (Il2CppArrayBase<Material>)(object)((Renderer)componentsInChild).sharedMaterials) { hashSet.Add(((Object)(object)item == (Object)null) ? "null" : (((Object)item).name + " (" + (((Object)(object)item.shader != (Object)null) ? ((Object)item.shader).name : "no shader") + ")")); } } string[] obj = new string[9] { key, ": ", PathOf(val), ", ", length.ToString(), " renderer(s), size ", null, null, null }; Vector3 size = ((Bounds)(ref val4)).size; obj[6] = ((Vector3)(ref size)).ToString("F2"); obj[7] = ", "; obj[8] = string.Join(", ", hashSet); return string.Concat(obj); } finally { Object.Destroy((Object)(object)val2); } } } internal static class Garage { [HarmonyPatch(typeof(SaveManager), "Save", new Type[] { typeof(string) })] private static class SaveHook { private static void Prefix() { if (!RollinNet.IsHost) { return; } try { EnsureLoaded(); } catch (Exception ex) { Core.Log.Error("[Garage] reading Rollin.tuning before the save failed: " + ex); } } private static void Postfix(SaveManager __instance) { if (!RollinNet.IsHost) { return; } try { List<string> approvedBaseLevelPaths = __instance.ApprovedBaseLevelPaths; if (approvedBaseLevelPaths == null) { Core.Log.Warning("[Garage] the game has no list of kept files - Rollin.tuning may be deleted at the end of the save."); } else if (!approvedBaseLevelPaths.Contains("Rollin.tuning")) { approvedBaseLevelPaths.Add("Rollin.tuning"); } } catch (Exception ex) { Core.Log.Error("[Garage] could not mark Rollin.tuning as kept: " + ex); } try { Save(); } catch (Exception ex2) { Core.Log.Error("[Garage] saving the wheelchair tuning failed: " + ex2); } } } internal const string FileName = "Rollin.tuning"; private static readonly Dictionary<string, Dictionary<string, string>> _byProp = new Dictionary<string, Dictionary<string, string>>(StringComparer.Ordinal); private static readonly Dictionary<string, Vector4> _parked = new Dictionary<string, Vector4>(StringComparer.Ordinal); private static readonly Dictionary<string, string> _cargo = new Dictionary<string, string>(StringComparer.Ordinal); private static int _applying = -1; private static string _loadedFrom; private static string _restoredFor; private static float _restoreAt = -1f; private const float RestoreDelay = 3f; internal static void Init() { ChassisApi.TuningChanged += OnTuningChanged; PropSwap.Swapped += OnSwapped; PropSwap.KeepsVehicle = KeepsVehicle; Parts.RegisterAll(); } internal static void Reset() { _byProp.Clear(); _parked.Clear(); _cargo.Clear(); _applying = -1; _loadedFrom = null; _restoredFor = null; _restoreAt = -1f; } internal static void Tick() { if (RollinNet.IsHost) { EnsureLoaded(); RestoreParked(); } } internal static bool IsTuned(string prop) { if (prop != null && _byProp.TryGetValue(prop, out var value)) { return value.Count > 0; } return false; } private static bool KeepsVehicle(string prop) { if (!IsTuned(prop)) { return Cargo.HasItems(PropSwap.VehicleOf(prop)); } return true; } private static void RestoreParked() { //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) if (_loadedFrom == null || _restoredFor == _loadedFrom || (Object)(object)Player.Local == (Object)null) { return; } if (_restoreAt < 0f) { _restoreAt = Time.time + 3f; } else { if (Time.time < _restoreAt) { return; } _restoredFor = _loadedFrom; _restoreAt = -1f; int num = 0; int num2 = 0; HashSet<string> hashSet = new HashSet<string>(_byProp.Keys, StringComparer.Ordinal); hashSet.UnionWith(_cargo.Keys); foreach (string item in hashSet) { num2++; Vector4 value; bool flag = _parked.TryGetValue(item, out value); if (PropSwap.HostPark(item, flag ? new Vector3?(new Vector3(value.x, value.y, value.z)) : ((Vector3?)null), flag ? value.w : 0f)) { num++; } } Core.Log.Msg("[Garage] " + num + "/" + num2 + " tuned wheelchair(s) parked again as vehicles."); } } internal static bool Request(LandVehicle lv, string key, string value, string why) { if ((Object)(object)lv == (Object)null || !WheelchairType.Is(lv)) { Core.Log.Warning("[Garage] " + why + ": no wheelchair given - " + key + " ignored."); return false; } value = value ?? string.Empty; if (RollinNet.IsHost) { return ChassisApi.SetTuning(lv, key, value); } RollinNet.ToHost("req.tune", Ids.Of((Component)(object)lv).ToString(CultureInfo.InvariantCulture), key, value); Core.Log.Msg("[Garage] asked the host to set " + key + " = '" + value + "' on net " + Ids.Of((Component)(object)lv) + " (" + why + ")."); return true; } internal static void HostRequest(int vehicle, string key, string value) { LandVehicle val = Ids.Find<LandVehicle>(vehicle); if ((Object)(object)val == (Object)null || !WheelchairType.Is(val)) { Core.Log.Warning("[Garage] tuning request for net " + vehicle + ", which is no wheelchair here - dropped."); } else if (!ChassisApi.SetTuning(val, key, value)) { Core.Log.Warning("[Garage] Chassis refused " + key + " = '" + value + "' on net " + vehicle + " (reason above)."); } } private static void OnTuningChanged(LandVehicle lv, string key) { if ((Object)(object)lv == (Object)null || !WheelchairType.Is(lv) || !RollinNet.IsHost) { return; } int num = Ids.Of((Component)(object)lv); if (num == _applying) { return; } string text = PropSwap.KeyOfVehicle(num); if (text == null) { Core.Log.Msg("[Garage] net " + num + " is no swapped prop (console spawn) - its tuning is not kept."); return; } Dictionary<string, string> dictionary = ChassisApi.Tuning(lv); if (dictionary.Count == 0) { _byProp.Remove(text); _parked.Remove(text); } else { _byProp[text] = dictionary; } Core.Log.Msg("[Garage] prop " + text + " keeps " + dictionary.Count + " tuning key(s)."); } private static void OnSwapped(string prop, LandVehicle lv) { EnsureLoaded(); if (_cargo.TryGetValue(prop, out var value) && !Cargo.HasItems(lv)) { Cargo.LoadLater(lv, value); Core.Log.Msg("[Garage] prop " + prop + ": its box contents go back into net " + Ids.Of((Component)(object)lv) + "."); } if (!_byProp.TryGetValue(prop, out var value2) || value2.Count == 0) { return; } int applying = Ids.Of((Component)(object)lv); int num = 0; _applying = applying; try { foreach (KeyValuePair<string, string> item in new List<KeyValuePair<string, string>>(value2)) { if (ChassisApi.SetTuning(lv, item.Key, item.Value)) { num++; continue; } Core.Log.Warning("[Garage] prop " + prop + ": " + item.Key + " = '" + item.Value + "' was refused (part no longer registered?)."); } } finally { _applying = -1; } Core.Log.Msg("[Garage] prop " + prop + " is net " + applying + " again with " + num + "/" + value2.Count + " tuning key(s)."); } internal static string Describe(string prop) { if (prop == null || !_byProp.TryGetValue(prop, out var value)) { return "stock"; } return Encode(value); } private static string SavePath() { if (!Singleton<LoadManager>.InstanceExists) { return null; } string loadedGameFolderPath = Singleton<LoadManager>.Instance.LoadedGameFolderPath; if (!string.IsNullOrEmpty(loadedGameFolderPath) && Directory.Exists(loadedGameFolderPath)) { return Path.Combine(loadedGameFolderPath, "Rollin.tuning"); } return null; } private static void EnsureLoaded() { //IL_00ed: Unknown result type (might be due to invalid IL or missing references) string text = SavePath(); if (text == null || text == _loadedFrom) { return; } _loadedFrom = text; _byProp.Clear(); _parked.Clear(); _cargo.Clear(); if (!File.Exists(text)) { Core.Log.Msg("[Garage] no Rollin.tuning in this save yet."); return; } try { string[] array = File.ReadAllLines(text); foreach (string text2 in array) { int num = text2.IndexOf('|'); if (num <= 0) { continue; } if (text2[0] == '@') { string[] array2 = text2.Substring(num + 1).Split(';'); if (array2.Length == 4 && TryF(array2[0], out var v) && TryF(array2[1], out var v2) && TryF(array2[2], out var v3) && TryF(array2[3], out var v4)) { _parked[text2.Substring(1, num - 1)] = new Vector4(v, v2, v3, v4); } else { Core.Log.Warning("[Garage] unreadable parking line '" + text2 + "' - that chair comes back at its prop."); } continue; } if (text2[0] == '$') { try { _cargo[text2.Substring(1, num - 1)] = Encoding.UTF8.GetString(Convert.FromBase64String(text2.Substring(num + 1))); } catch (FormatException) { Core.Log.Error("[Garage] unreadable box line for " + text2.Substring(1, num - 1) + " - those items are lost."); } continue; } Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); string[] array3 = text2.Substring(num + 1).Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text3 in array3) { int num2 = text3.IndexOf('='); if (num2 <= 0) { Core.Log.Warning("[Garage] unreadable entry '" + text3 + "' skipped."); } else { dictionary[text3.Substring(0, num2)] = text3.Substring(num2 + 1); } } if (dictionary.Count > 0) { _byProp[text2.Substring(0, num)] = dictionary; } } Core.Log.Msg("[Garage] loaded the tuning of " + _byProp.Count + " wheelchair(s), " + _parked.Count + " parking spot(s), " + _cargo.Count + " filled box(es), from " + text + "."); } catch (Exception ex2) { Core.Log.Error("[Garage] could not read " + text + ", the wheelchairs stay stock: " + ex2.Message); } } private static void Save() { //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) string text = SavePath(); if (text == null) { Core.Log.Warning("[Garage] no save folder - the wheelchair tuning stays in memory."); return; } EnsureLoaded(); StringBuilder stringBuilder = new StringBuilder(); foreach (KeyValuePair<string, Dictionary<string, string>> item in _byProp) { stringBuilder.Append(item.Key).Append('|').Append(Encode(item.Value)) .Append('\n'); } foreach (string item2 in PropSwap.VehicleKeys()) { string text2 = Cargo.Serialize(PropSwap.VehicleOf(item2)); if (text2 != null) { _cargo[item2] = text2; } else { _cargo.Remove(item2); } } foreach (KeyValuePair<string, string> item3 in _cargo) { stringBuilder.Append('$').Append(item3.Key).Append('|') .Append(Convert.ToBase64String(Encoding.UTF8.GetBytes(item3.Value))) .Append('\n'); } HashSet<string> hashSet = new HashSet<string>(_byProp.Keys, StringComparer.Ordinal); hashSet.UnionWith(_cargo.Keys); foreach (string item4 in hashSet) { LandVehicle val = PropSwap.VehicleOf(item4); if ((Object)(object)val != (Object)null) { Transform transform = ((Component)val).transform; _parked[item4] = new Vector4(transform.position.x, transform.position.y, transform.position.z, transform.eulerAngles.y); } if (_parked.TryGetValue(item4, out var value)) { stringBuilder.Append('@').Append(item4).Append('|') .Append(F(value.x)) .Append(';') .Append(F(value.y)) .Append(';') .Append(F(value.z)) .Append(';') .Append(F(value.w)) .Append('\n'); } } File.WriteAllText(text, stringBuilder.ToString()); Core.Log.Msg("[Garage] saved the tuning of " + _byProp.Count + " wheelchair(s), " + _parked.Count + " parking spot(s), " + _cargo.Count + " filled box(es), to " + text + "."); } private static string F(float v) { return v.ToString("R", CultureInfo.InvariantCulture); } private static bool TryF(string s, out float v) { return float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out v); } private static string Encode(Dictionary<string, string> s) { StringBuilder stringBuilder = new StringBuilder(); foreach (KeyValuePair<string, string> item in s) { if (stringBuilder.Length > 0) { stringBuilder.Append(';'); } stringBuilder.Append(item.Key).Append('=').Append(item.Value); } return stringBuilder.ToString(); } } internal static class Horns { internal sealed class Horn { internal string Name; internal string Label; internal Func<float[]> Make; } private const int Rate = 44100; internal static readonly List<Horn> All = new List<Horn> { new Horn { Name = "rollin_clown", Label = "Clown Horn", Make = Clown }, new Horn { Name = "rollin_duck", Label = "Rubber Duck", Make = Duck }, new Horn { Name = "rollin_train", Label = "Freight Train", Make = Train }, new Horn { Name = "rollin_charge", Label = "Charge!", Make = Charge }, new Horn { Name = "rollin_cucaracha", Label = "La Cucaracha", Make = Cucaracha } }; private const float G4 = 392f; private const float C5 = 523.25f; private const float D5 = 587.33f; private const float E5 = 659.25f; private const float F5 = 698.46f; private const float G5 = 783.99f; private const float A5 = 880f; internal static void RegisterAll() { foreach (Horn item in All) { try { float[] array = item.Make(); AudioClip val = AudioClip.Create(item.Name, array.Length, 1, 44100, false); val.SetData(Il2CppStructArray<float>.op_Implicit(array), 0); ((Object)val).hideFlags = (HideFlags)32; ChassisApi.RegisterSound(item.Name, val); Core.Log.Msg("[Horns] '" + item.Name + "' made, " + ((float)array.Length / 44100f).ToString("F2") + " s."); } catch (Exception ex) { Core.Log.Error("[Horns] making '" + item.Name + "' failed - that horn is missing: " + ex); } } } private static float[] Buffer(float seconds) { return new float[(int)(seconds * 44100f)]; } private static void Tone(float[] buf, float at, float length, float fromHz, float toHz, Func<float, float> wave, float gain) { int num = (int)(at * 44100f); int num2 = (int)(length * 44100f); double num3 = 0.0; for (int i = 0; i < num2 && num + i < buf.Length; i++) { float num4 = (float)i / (float)num2; float num5 = Mathf.Lerp(fromHz, toHz, num4); num3 += (double)(num5 / 44100f); float num6 = Mathf.Min(1f, (float)i / 441f) * Mathf.Min(1f, (float)(num2 - i) / 1323f); buf[num + i] += wave((float)(num3 - Math.Floor(num3))) * num6 * gain; } } private static float Saw(float p) { return 2f * p - 1f; } private static float Square(float p) { if (!(p < 0.5f)) { return -0.8f; } return 0.8f; } private static float Sine(float p) { return Mathf.Sin(p * 2f * (float)Math.PI); } private static float[] Clip(float[] buf) { for (int i = 0; i < buf.Length; i++) { buf[i] = Mathf.Clamp(buf[i], -1f, 1f); } return buf; } private static float[] Clown() { float[] buf = Buffer(0.75f); Tone(buf, 0f, 0.28f, 420f, 360f, Saw, 0.45f); Tone(buf, 0f, 0.28f, 840f, 720f, Square, 0.12f); Tone(buf, 0.38f, 0.32f, 400f, 330f, Saw, 0.45f); Tone(buf, 0.38f, 0.32f, 800f, 660f, Square, 0.12f); return Clip(buf); } private static float[] Duck() { float[] buf = Buffer(0.5f); Tone(buf, 0f, 0.18f, 900f, 1500f, Square, 0.35f); Tone(buf, 0.22f, 0.22f, 1400f, 800f, Square, 0.35f); return Clip(buf); } private static float[] Train() { float[] buf = Buffer(1.4f); float[] array = new float[4] { 277f, 349f, 415f, 523f }; foreach (float num in array) { Tone(buf, 0f, 1.4f, num, num * 0.995f, Saw, 0.16f); Tone(buf, 0f, 1.4f, num * 1.004f, num, Saw, 0.12f); } return Clip(buf); } private static float[] Melody(float beat, (float hz, float beats)[] notes, Func<float, float> wave, float gain) { float num = 0f; (float, float)[] array = notes; for (int i = 0; i < array.Length; i++) { (float, float) tuple = array[i]; num += tuple.Item2 * beat; } float[] buf = Buffer(num + 0.05f); float num2 = 0f; array = notes; for (int i = 0; i < array.Length; i++) { (float, float) tuple2 = array[i]; if (tuple2.Item1 > 0f) { Tone(buf, num2, tuple2.Item2 * beat * 0.9f, tuple2.Item1, tuple2.Item1, wave, gain); } num2 += tuple2.Item2 * beat; } return Clip(buf); } private static float[] Charge() { return Melody(0.13f, new(float, float)[6] { (392f, 1f), (523.25f, 1f), (659.25f, 1f), (783.99f, 2f), (659.25f, 1f), (783.99f, 4f) }, Square, 0.3f); } private static float[] Cucaracha() { return Melody(0.11f, new(float, float)[19] { (523.25f, 1f), (523.25f, 1f), (523.25f, 1f), (698.46f, 3f), (880f, 2f), (0f, 1f), (523.25f, 1f), (523.25f, 1f), (523.25f, 1f), (698.46f, 3f), (880f, 2f), (0f, 1f), (698.46f, 2f), (698.46f, 1f), (659.25f, 1f), (659.25f, 1f), (587.33f, 1f), (587.33f, 1f), (523.25f, 4f) }, Square, 0.28f); } } internal static class Menu { private sealed class Row { internal string Label; internal string Key; internal readonly List<KeyValuePair<string, string>> Options = new List<KeyValuePair<string, string>>(); } private static MelonPreferences_Entry<KeyCode> _key; private static readonly string[] PartSlots = new string[10] { "spoiler", "booster", "exhaust", "rims", "hat", "mascot", "roof", "lights", "audio", "cargo" }; private static readonly string[] StageSlots = new string[6] { "engine", "brakes", "suspension", "tyres", "steering", "weight" }; private static readonly (string Label, string Value)[] Paints = new(string, string)[10] { ("Stock", ""), ("Hot Pink", "FF3EA5,metallic"), ("Toxic Lime", "7CFF2E,classic"), ("Gold", "FFC423,chrome"), ("Chrome", "D9DDE3,chrome"), ("Matte Black", "151515,matte"), ("Candy Red", "C8102E,metallic"), ("Baby Blue", "8FD3FF,classic"), ("Royal Purple", "7A2BD9,metallic"), ("Hospital Green", "8FBFA5,matte") }; private static readonly (string Label, string Value)[] Neons = new(string, string)[7] { ("Off", ""), ("Pink", "FF2EC4,fblr"), ("Cyan", "2EF2FF,fblr"), ("Green", "39FF14,fblr"), ("Red", "FF1A1A,fblr"), ("Purple", "9B30FF,fblr"), ("White", "FFFFFF,fblr") }; private static List<Row> _rows; private static LandVehicle _lv; private static int _row; private static GameObject _canvas; private static TextMeshProUGUI _body; private static readonly Dictionary<string, (string Value, float Until)> _pending = new Dictionary<string, (string, float)>(StringComparer.OrdinalIgnoreCase); private static bool _orbit; private static bool _orbitWarned; internal static KeyCode Key { get { //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (_key == null) { return (KeyCode)114; } return _key.Value; } } internal static bool IsOpen => (Object)(object)_lv != (Object)null; internal static void Init() { //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) _key = MelonPreferences.CreateCategory("Rollin", "Rollin").CreateEntry<KeyCode>("GarageKey", (KeyCode)114, "Garage key", "Opens and closes the tuning menu while you drive a wheelchair.", false, false, (ValueValidator)null, (string)null); Core.Log.Msg("[Menu] garage key: " + ((object)Key/*cast due to .constrained prefix*/).ToString() + "."); ChassisApi.AddKeyHint("rollin.garage", "Tuning", (Func<KeyHintContext, bool>)((KeyHintContext c) => c.Driver && WheelchairType.Is(c.Vehicle)), (Func<KeyCode>)(() => Key)); } internal static void Reset() { if ((Object)(object)_lv != (Object)null) { Lock(_lv, on: false, "reset"); } _lv = null; _orbit = false; if ((Object)(object)_canvas != (Object)null) { _canvas.SetActive(false); } } internal static void Tick() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_lv == (Object)null) { if (Input.GetKeyDown(Key) && !GameInput.IsTyping) { LandVehicle val = LocalChair(); if (!((Object)(object)val == (Object)null)) { Open(val, ((object)Key/*cast due to .constrained prefix*/).ToString() + " pressed"); } } } else if (!Object.op_Implicit((Object)(object)_lv) || !_lv.LocalPlayerIsDriver) { Close("left the wheelchair"); } else { if (GameInput.IsTyping) { return; } if (Input.GetKeyDown(Key)) { Close(((object)Key/*cast due to .constrained prefix*/).ToString() + " pressed"); return; } if (Input.GetKeyDown((KeyCode)119) || Input.GetKeyDown((KeyCode)273)) { Move(-1); } if (Input.GetKeyDown((KeyCode)115) || Input.GetKeyDown((KeyCode)274)) { Move(1); } if (Input.GetKeyDown((KeyCode)97)) { Cycle(-1); } if (Input.GetKeyDown((KeyCode)100)) { Cycle(1); } Draw(); HoldOrbit(); } } private static void HoldOrbit() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) if (!Singleton<GameInput>.InstanceExists) { if (!_orbitWarned) { _orbitWarned = true; Core.Log.Warning("[Menu] no GameInput - the camera orbits only with the right button held."); } return; } GameInput instance = Singleton<GameInput>.Instance; ButtonCode val = (ButtonCode)1; if (!instance.buttonsDown.Contains(val)) { instance.buttonsDown.Add(val); if (!instance.buttonsDownThisFrame.Contains(val)) { instance.buttonsDownThisFrame.Add(val); } if (!_orbit) { Core.Log.Msg("[Menu] the camera orbits with the mouse while the menu is open."); } _orbit = true; } } private static void ReleaseOrbit(string why) { if (_orbit) { _orbit = false; if (!Singleton<GameInput>.InstanceExists) { Core.Log.Warning("[Menu] GameInput is gone - nothing to release (" + why + ")."); return; } if (Input.GetMouseButton(1)) { Core.Log.Msg("[Menu] right button is really held - the camera keeps orbiting (" + why + ")."); return; } GameInput instance = Singleton<GameInput>.Instance; instance.buttonsDown.Remove((ButtonCode)1); instance.buttonsUpThisFrame.Add((ButtonCode)1); Core.Log.Msg("[Menu] camera back to right-click orbit (" + why + ")."); } } internal static LandVehicle LocalChair() { Player local = Player.Local; NetworkObject val = (((Object)(object)local != (Object)null) ? local.CurrentVehicle : null); LandVehicle val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<LandVehicle>() : null); if (!((Object)(object)val2 != (Object)null) || !WheelchairType.Is(val2) || !val2.LocalPlayerIsDriver) { return null; } return val2; } internal static bool Open(LandVehicle lv, string why) { if ((Object)(object)lv == (Object)null) { Core.Log.Warning("[Menu] open (" + why + "): you are not driving a wheelchair."); return false; } BuildRows(); if (!EnsureCanvas()) { return false; } _lv = lv; Lock(lv, on: true, why); _row = Mathf.Clamp(_row, 0, _rows.Count - 1); _canvas.SetActive(true); Draw(); Core.Log.Msg("[Menu] opened for net " + Ids.Of((Component)(object)lv) + " (" + why + "), " + _rows.Count + " rows."); return true; } internal static void Close(string why) { LandVehicle lv = _lv; _lv = null; if ((Object)(object)lv != (Object)null) { Lock(lv, on: false, why); } ReleaseOrbit(why); if ((Object)(object)_canvas != (Object)null) { _canvas.SetActive(false); } Core.Log.Msg("[Menu] closed (" + why + ")."); } internal static void Move(int by) { if (_rows != null && _rows.Count != 0) { _row = (_row + by + _rows.Count) % _rows.Count; } } internal static void Cycle(int by) { if (!((Object)(object)_lv == (Object)null) && _rows != null) { Row row = _rows[_row]; int num = IndexOf(row, Current(row.Key)); int index = (((num >= 0) ? num : 0) + by + row.Options.Count) % row.Options.Count; KeyValuePair<string, string> keyValuePair = row.Options[index]; _pending[row.Key] = (keyValuePair.Value, Time.time + 2f); if (!Garage.Request(_lv, row.Key, keyValuePair.Value, "menu")) { Core.Log.Warning("[Menu] " + row.Label + " -> " + keyValuePair.Key + " was refused (reason above)."); } else { Core.Log.Msg("[Menu] " + row.Label + " -> " + keyValuePair.Key + " (" + row.Key + " = '" + keyValuePair.Value + "')."); } } } private static string Current(string key) { if (_pending.TryGetValue(key, out (string, float) value) && Time.time < value.Item2) { return value.Item1; } return ChassisApi.GetTuning(_lv, key) ?? ""; } private static int IndexOf(Row row, string value) { for (int i = 0; i < row.Options.Count; i++) { if (string.Equals(row.Options[i].Value, value ?? "", StringComparison.OrdinalIgnoreCase)) { return i; } } return -1; } private static void BuildRows() { if (_rows != null) { return; } _rows = new List<Row>(); Row row = new Row { Label = "Paint", Key = "paint" }; Row row2 = new Row { Label = "Trim Paint", Key = "paint2" }; (string, string)[] paints = Paints; for (int i = 0; i < paints.Length; i++) { (string, string) tuple = paints[i]; row.Options.Add(new KeyValuePair<string, string>(tuple.Item1, tuple.Item2)); row2.Options.Add(new KeyValuePair<string, string>(tuple.Item1, tuple.Item2)); } _rows.Add(row); _rows.Add(row2); Row row3 = new Row { Label = "Neon", Key = "neon" }; paints = Neons; for (int i = 0; i < paints.Length; i++) { (string, string) tuple2 = paints[i]; row3.Options.Add(new KeyValuePair<string, string>(tuple2.Item1, tuple2.Item2)); } _rows.Add(row3); Row row4 = new Row { Label = "Horn", Key = "horn" }; row4.Options.Add(new KeyValuePair<string, string>("Stock", "")); foreach (Horns.Horn item in Horns.All) { row4.Options.Add(new KeyValuePair<string, string>(item.Label, item.Name)); } row4.Options.Add(new KeyValuePair<string, string>("Bicycle Horn", "rollin_bicycle")); _rows.Add(row4); string[] partSlots = PartSlots; for (int i = 0; i < partSlots.Length; i++) { AddSlot(partSlots[i]); } partSlots = StageSlots; for (int i = 0; i < partSlots.Length; i++) { AddSlot(partSlots[i]); } } private static void AddSlot(string slot) { Row row = new Row { Label = Title(slot), Key = "part." + slot }; row.Options.Add(new KeyValuePair<string, string>("Stock", "")); foreach (TuningPart item in Parts.All) { if (string.Equals(item.Slot, slot, StringComparison.OrdinalIgnoreCase)) { row.Options.Add(new KeyValuePair<string, string>(item.Label, item.Id)); } } if (row.Options.Count > 1) { _rows.Add(row); } else { Core.Log.Warning("[Menu] slot '" + slot + "' has no parts - no row for it."); } } private static string Title(string slot) { if (slot.Length != 0) { return char.ToUpperInvariant(slot[0]) + slot.Substring(1); } return slot; } private static void Draw() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_body == (Object)null || (Object)(object)_lv == (Object)null) { return; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("<size=130%><b>ROLLIN GARAGE</b></size>\n<color=#9AA3AD><size=80%>W/S row A/D change " + ((object)Key/*cast due to .constrained prefix*/).ToString() + " close Free of charge</size></color>\n\n"); for (int i = 0; i < _rows.Count; i++) { Row row = _rows[i]; string text = Current(row.Key); int num = IndexOf(row, text); string value = ((num >= 0) ? row.Options[num].Key : text); bool flag = i == _row; if (i == 4 || i == 4 + PartSlotsShown()) { stringBuilder.Append("<size=40%> </size>\n"); } stringBuilder.Append(flag ? "<color=#FFD24A>> " : "<color=#D8DEE6> ").Append(row.Label).Append("</color>"); stringBuilder.Append("<pos=46%>").Append(flag ? "<color=#FFD24A>< " : "<color=#8D96A0>").Append(value) .Append(flag ? " ></color>" : "</color>") .Append('\n'); } TuningStats val = ChassisApi.TuningStatsOf(_lv); if (val != null) { stringBuilder.Append("\n<color=#9AA3AD><size=75%>").Append(((object)val).ToString()).Append("</size></color>"); } ((TMP_Text)_body).text = stringBuilder.ToString(); } private static int PartSlotsShown() { int num = 0; foreach (Row row in _rows) { string[] partSlots = PartSlots; foreach (string text in partSlots) { if (row.Key == "part." + text) { num++; } } } return num; } private static bool EnsureCanvas() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: 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) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_canvas != (Object)null) { return true; } try { _canvas = new GameObject("RollinTuningMenu"); Object.DontDestroyOnLoad((Object)(object)_canvas); Canvas obj = _canvas.AddComponent<Canvas>(); obj.renderMode = (RenderMode)0; obj.sortingOrder = 400; CanvasScaler obj2 = _canvas.AddComponent<CanvasScaler>(); obj2.uiScaleMode = (ScaleMode)1; obj2.referenceResolution = new Vector2(1920f, 1080f); obj2.matchWidthOrHeight = 1f; GameObject val = new GameObject("Panel"); val.transform.SetParent(_canvas.transform, false); RectTransform obj3 = val.AddComponent<RectTransform>(); Vector2 anchorMin = (obj3.anchorMax = new Vector2(1f, 0.5f)); obj3.anchorMin = anchorMin; obj3.pivot = new Vector2(1f, 0.5f); obj3.anchoredPosition = new Vector2(-48f, 50f); obj3.sizeDelta = new Vector2(560f, 820f); Image obj4 = val.AddComponent<Image>(); ((Graphic)obj4).color = new Color(0.05f, 0.06f, 0.08f, 0.9f); ((Graphic)obj4).raycastTarget = false; GameObject val3 = new GameObject("Accent"); val3.transform.SetParent(val.transform, false); RectTransform obj5 = val3.AddComponent<RectTransform>(); obj5.anchorMin = new Vector2(0f, 0f); obj5.anchorMax = new Vector2(0f, 1f); obj5.pivot = new Vector2(0f, 0.5f); obj5.sizeDelta = new Vector2(6f, 0f); Image obj6 = val3.AddComponent<Image>(); ((Graphic)obj6).color = new Color(1f, 0.82f, 0.29f, 1f); ((Graphic)obj6).raycastTarget = false; GameObject val4 = new GameObject("Body"); val4.transform.SetParent(val.transform, false); RectTransform obj7 = val4.AddComponent<RectTransform>(); obj7.anchorMin = Vector2.zero; obj7.anchorMax = Vector2.one; obj7.offsetMin = new Vector2(30f, 22f); obj7.offsetMax = new Vector2(-22f, -22f); _body = val4.AddComponent<TextMeshProUGUI>(); TMP_FontAsset val5 = Font(); if ((Object)(object)val5 != (Object)null) { ((TMP_Text)_body).font = val5; } else { Core.Log.Warning("[Menu] no game font found - the menu uses TextMeshPro's default."); } ((TMP_Text)_body).fontSize = 21f; ((TMP_Text)_body).richText = true; ((TMP_Text)_body).enableWordWrapping = false; ((TMP_Text)_body).alignment = (TextAlignmentOptions)257; ((Graphic)_body).color = Color.white; ((Graphic)_body).raycastTarget = false; _canvas.SetActive(false); Core.Log.Msg("[Menu] built the menu canvas, font " + (((Object)(object)val5 != (Object)null) ? ((Object)val5).name : "default") + "."); return true; } catch (Exception ex) { Core.Log.Error("[Menu] building the menu failed - tuning stays on the console: " + ex); if ((Object)(object)_canvas != (Object)null) { Object.Destroy((Object)(object)_canvas); } _canvas = null; _body = null; return false; } } private static TMP_FontAsset Font() { Il2CppArrayBase<TMP_FontAsset> val = Resources.FindObjectsOfTypeAll<TMP_FontAsset>(); string[] array = new string[3] { "OpenSans-SemiBold SDF", "OpenSans-Regular SDF", "LiberationSans SDF" }; foreach (string text in array) { foreach (TMP_FontAsset item in val) { if ((Object)(object)item != (Object)null && ((Object)item).name == text) { return item; } } } if (val.Length <= 0) { return null; } return val[0]; } private static void Lock(LandVehicle lv, bool on, string why) { lv.overrideControls = on; lv.throttleOverride = 0f; lv.steerOverride = 0f; Core.Log.Msg("[Menu] net " + Ids.Of((Component)(object)lv) + (on ? " stands still while the menu is open" : " drives again") + " (" + why + ")."); } } internal static class Models { internal enum Anchor { Bottom, Top, Centre, Back, Front, BottomFront } internal enum Axis { Longest, Widest, Height } internal const string SpinLeft = "rollin_spin_L"; internal const string SpinRight = "rollin_spin_R"; internal const string Hat = "rollin_hat"; internal const string SmokePoint = "rollin_smoke"; internal const string SmokeFx = "rollin_smoke_fx"; internal const string BlinkRed = "rollin_blink_red"; internal const string BlinkBlue = "rollin_blink_blue"; internal const string BlinkOn = "rollin_on"; internal const string Pulse = "rollin_pulse"; private static readonly string[] StockRims = new string[2] { "Wheel", "Wheel (1)" }; private static readonly Color DarkSlate = Hex(2899535); private static readonly Color Steel = Hex(9807270); private static readonly Color PipeMetal = new Color(0.32f, 0.33f, 0.34f); private const float HandleY = 1.105f; private const float HandleX = 0.2f; private const float HandleFront = -0.27f; private const float HandleBore = 0.024f; private static readonly Vector3 PoleFoot = new Vector3(0f, 1.105f, -0.3f); private const float SeatUnderside = 0.479f; private const float BackPostX = 0.25f; private const float BackZ = -0.236f; private const float BackTilt = 5.5f; private const float BackPostFoot = 0.46f; private const float PipeX = 0.17f; private const float PipeTop = 0.454f; private const float PipeFront = -0.2f; private const float PipeLength = 0.3f; private const float PipeLead = -0.02f; private const float PipeBore = 0.04f; private static readonly float[] PipeHangers = new float[2] { -0.06f, -0.16f }; private const float LightbarTop = 1.46f; private const float UmbrellaFoot = 1.54f; internal static readonly Vector3 HatSeat = new Vector3(0f, 0.5f, -0.08f); internal static Vector3 PipeTurn = new Vector3(0f, 180f, 0f); private const float TailpipeBoreRatio = 0.22222221f; internal const string ChassisNeon = "Chassis_Tune_neon"; internal const string ChassisNeonLight = "Chassis_Tune_neon_light_"; internal const string SeatNeon = "rollin_neon"; private static readonly Dictionary<string, Material> _mats = new Dictionary<string, Material>(StringComparer.Ordinal); private static string _trim; internal static IEnumerable<TuningPart> Parts() { yield return Rims("rollin_rims_sport", "Sports Rims", 1200, "rim_sport", null); yield return Rims("rollin_rims_muscle", "Muscle Rims", 1600, "rim_muscle", new TuningStats { Grip = 1.1f }); yield return Part("rollin_exhaust_twin", "exhaust", "Twin Tailpipes", 900, TwinExhaust, new TuningStats { EnginePitch = 0.85f }); yield return Part("rollin_box", "cargo", "Moving Box", 30, delegate(Transform root) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) Transform val = Game(root, "box", new Vector3(0f, 0.479f, 0.02f), new Vector3(0f, 12f, 0f), 0.26f, Axis.Longest, Anchor.Top); if ((Object)(object)val == (Object)null) { Core.Log.Warning("[Models] no moving box mesh - the box cannot be opened."); } else { Cargo.AddTrigger(root, GameMeshes.Measure(root, val)); } }, new TuningStats { Mass = 1.05f }); yield return Part("rollin_jerrycan", "booster", "Jerry Can Rocket", 15000, JerryCanRocket, new TuningStats { Torque = 1.8f, Gearing = 1.8f, EnginePitch = 1.2f }); yield return Part("rollin_wing", "spoiler", "Handle Wing", 2500, Wing, new TuningStats { Grip = 1.1f }); yield return Part("rollin_lightbar", "lights", "Police Lightbar", 8000, Lightbar, null); yield return Part("rollin_umbrella", "roof", "Sun Umbrella", 60, delegate(Transform root) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) Pole(root, 1.76f); Game(root, "umbrella", new Vector3(PoleFoot.x, 1.54f, PoleFoot.z), Vector3.zero, 0.6f, Axis.Widest, Anchor.Bottom); }, new TuningStats { Mass = 0.9f }); yield return Part("rollin_radio", "audio", "Armrest Radio", 700, delegate(Transform root) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) Pulsing(Game(root, "radio", new Vector3(-0.29f, 0.72f, 0.15f), new Vector3(0f, -90f, 0f), 0.18f, Axis.Longest, Anchor.Bottom, null, lengthAlongZ: false, null, null, flatSideBack: false, null, ownAxes: true)); }, null); yield return Part("rollin_gnome", "mascot", "Garden Gnome", 3, delegate(Transform root) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) Game(root, "gnome", new Vector3(0f, 0.52f, 0.16f), Vector3.zero, 0.24f, Axis.Height, Anchor.Bottom, null, lengthAlongZ: false, null, "Hat", flatSideBack: false, "Beard"); }, null); yield return Part("rollin_hat_gnome", "hat", "Gnome Hat", 420, delegate(Transform root) { HatPiece(root, "gnome", "Hat", 0.2f, Axis.Widest, 0.02f); }, null); } private static TuningPart Part(string id, string slot, string label, int price, Action<Transform> build, TuningStats stats) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown //IL_006b: Expected O, but got Unknown return new TuningPart { Id = id, Slot = slot, Label = label, Price = price, Stats = stats, Build = delegate(LandVehicle lv) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown _trim = ChassisApi.GetTuning(lv, "paint2"); try { GameObject val = new GameObject("rollin_part_" + id); build(val.transform); return val; } finally { _trim = null; } }, Fits = { ["rollin_wheelchair"] = new PartFit() } }; } private static TuningPart Rims(string id, string label, int price, string source, TuningStats stats) { TuningPart obj = Part(id, "rims", label, price, delegate(Transform root) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) Rim(root, "rollin_spin_R", source, WheelchairType.BigWheel, 0f); Rim(root, "rollin_spin_L", source, new Vector3(0f - WheelchairType.BigWheel.x, WheelchairType.BigWheel.y, WheelchairType.BigWheel.z), 180f); }, stats); obj.Fits["rollin_wheelchair"].Hide.AddRange(StockRims); return obj; } private static void Rim(Transform root, string name, string source, Vector3 at, float yaw) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) Transform transform = new GameObject(name).transform; transform.SetParent(root, false); transform.localPosition = at; transform.localRotation = Quaternion.Euler(0f, yaw, 0f); Transform transform2 = new GameObject("fit").transform; transform2.SetParent(transform, false); Transform val = GameMeshes.Copy(source, transform2); if (!((Object)(object)val == (Object)null)) { val.localRotation = Quaternion.identity; Bounds val2 = GameMeshes.Measure(transform2, val); Vector3 size = ((Bounds)(ref val2)).size; if (size.y < size.x && size.y < size.z) { val.localRotation = Quaternion.Euler(0f, 0f, 90f) * val.localRotation; } else if (size.z < size.x && size.z < size.y) { val.localRotation = Quaternion.Euler(0f, 90f, 0f) * val.localRotation; } val2 = GameMeshes.Measure(transform2, val); float num = 0.66f; transform2.localScale = new Vector3(0.06f / Mathf.Max(0.001f, ((Bounds)(ref val2)).size.x), num / Mathf.Max(0.001f, ((Bounds)(ref val2)).size.y), num / Mathf.Max(0.001f, ((Bounds)(ref val2)).size.z)); val.localPosition -= ((Bounds)(ref val2)).center; } } private static void HatPiece(Transform root, string source, string child, float size, Axis axis, float sink) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) Transform transform = new GameObject("rollin_hat").transform; transform.SetParent(root, false); transform.localPosition = HatSeat; if ((Object)(object)Game(transform, source, new Vector3(0f, 0f - sink, 0f), Vector3.zero, size, axis, Anchor.Bottom, null, lengthAlongZ: false, child) == (Object)null) { Core.Log.Warning("[Models] hat from '" + source + "' did not build."); } } private unsafe static void TwinExhaust(Transform root) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing