Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of S1FuelMod Mono v1.0.0
S1FuelMod-Mono.dll
Decompiled 2 weeks 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.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using FishNet.Object; using HarmonyLib; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using S1FuelMod; using S1FuelMod.Integrations; using S1FuelMod.Networking; using S1FuelMod.Systems; using S1FuelMod.UI; using S1FuelMod.Utils; using ScheduleOne.DevUtilities; using ScheduleOne.GameTime; using ScheduleOne.Interaction; using ScheduleOne.Levelling; using ScheduleOne.Money; using ScheduleOne.NPCs.CharacterClasses; using ScheduleOne.Networking; using ScheduleOne.Persistence.Datas; using ScheduleOne.Persistence.Loaders; using ScheduleOne.PlayerScripts; using ScheduleOne.UI; using ScheduleOne.Vehicles; using ScheduleOne.Vehicles.Modification; using Steamworks; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(Core), "S1FuelMod", "1.0.0", "Bars & SirTidez", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("S1FuelMod-Mono")] [assembly: AssemblyConfiguration("Release Mono")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+d089bb778743cd91a66252c91ca68967e0016e19")] [assembly: AssemblyProduct("S1FuelMod-Mono")] [assembly: AssemblyTitle("S1FuelMod-Mono")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace S1FuelMod { public class Core : MelonMod { private MelonPreferences_Category? _preferencesCategory; private MelonPreferences_Category? _capacityCategory; private MelonPreferences_Entry<bool>? _enableFuelSystem; private MelonPreferences_Entry<float>? _fuelConsumptionMultiplier; private MelonPreferences_Entry<float>? _defaultFuelCapacity; private MelonPreferences_Entry<float>? _shitboxFuelCapacity; private MelonPreferences_Entry<float>? _veeperFuelCapacity; private MelonPreferences_Entry<float>? _bruiserFuelCapacity; private MelonPreferences_Entry<float>? _dinklerFuelCapacity; private MelonPreferences_Entry<float>? _hounddogFuelCapacity; private MelonPreferences_Entry<float>? _cheetahFuelCapacity; private MelonPreferences_Entry<float>? _hotboxFuelCapacity; private MelonPreferences_Entry<bool>? _showFuelGauge; private MelonPreferences_Entry<bool>? _enableDynamicPricing; private MelonPreferences_Entry<bool>? _enablePricingOnTier; private MelonPreferences_Entry<bool>? _enableDebugLogging; private FuelSystemManager? _fuelSystemManager; private FuelUIManager? _fuelUIManager; private FuelStationManager? _fuelStationManager; public static Core? Instance { get; private set; } public bool EnableFuelSystem => _enableFuelSystem?.Value ?? true; public float FuelConsumptionMultiplier => _fuelConsumptionMultiplier?.Value ?? 1f; public float DefaultFuelCapacity => _defaultFuelCapacity?.Value ?? 40f; public float ShitboxFuelCapacity => _shitboxFuelCapacity?.Value ?? 30f; public float VeeperFuelCapacity => _veeperFuelCapacity?.Value ?? 40f; public float BruiserFuelCapacity => _bruiserFuelCapacity?.Value ?? 40f; public float DinklerFuelCapacity => _dinklerFuelCapacity?.Value ?? 55f; public float HounddogFuelCapacity => _hounddogFuelCapacity?.Value ?? 35f; public float CheetahFuelCapacity => _cheetahFuelCapacity?.Value ?? 35f; public float HotboxFuelCapacity => _hotboxFuelCapacity?.Value ?? 50f; public bool ShowFuelGauge => _showFuelGauge?.Value ?? true; public bool EnableDynamicPricing => _enableDynamicPricing?.Value ?? true; public bool EnablePricingOnTier => _enablePricingOnTier?.Value ?? true; public bool EnableDebugLogging => _enableDebugLogging?.Value ?? false; public override void OnInitializeMelon() { Instance = this; ModLogger.LogInitialization(); try { InitializePreferences(); HarmonyPatches.SetModInstance(this); ModLogger.Info("S1FuelMod initialized successfully"); ModLogger.Info($"Fuel System Enabled: {EnableFuelSystem}"); ModLogger.Info($"Show Fuel Gauge: {ShowFuelGauge}"); ModLogger.Info("Debug logging can be toggled in the mod preferences"); } catch (Exception exception) { ModLogger.Error("Failed to initialize S1FuelMod", exception); } } public override void OnSceneWasInitialized(int buildIndex, string sceneName) { try { ModLogger.Debug($"Scene initialized: {sceneName} (index: {buildIndex})"); if (sceneName.Contains("Main")) { ModLogger.Debug("Main game scene detected, initializing fuel systems..."); InitializeSystems(); } else { ModLogger.Debug("Scene '" + sceneName + "' is not a main game scene, skipping system initialization"); } } catch (Exception exception) { ModLogger.Error("Error during scene initialization", exception); } } public override void OnUpdate() { try { _fuelSystemManager?.Update(); _fuelUIManager?.Update(); _fuelStationManager?.Update(); } catch (Exception exception) { ModLogger.Error("Error during update", exception); } } private void InitializePreferences() { try { _preferencesCategory = MelonPreferences.CreateCategory("S1FuelMod"); _capacityCategory = MelonPreferences.CreateCategory("S1FuelMod_Capacity", "Fuel Tank Capacity"); _enableFuelSystem = _preferencesCategory.CreateEntry<bool>("EnableFuelSystem", true, "Enable Fuel System", "If enabled, vehicles will consume fuel and require refueling", false, false, (ValueValidator)null, (string)null); _fuelConsumptionMultiplier = _preferencesCategory.CreateEntry<float>("FuelConsumptionMultiplier", 1f, "Fuel Consumption Multiplier", "Multiplier for fuel consumption rate (1.0 = normal, 0.5 = half consumption, 2.0 = double consumption)", false, false, (ValueValidator)(object)new ValueRange<float>(0.1f, 5f), (string)null); _defaultFuelCapacity = _preferencesCategory.CreateEntry<float>("DefaultFuelCapacity", 40f, "Default Fuel Capacity (L)", "Default fuel tank capacity for vehicles in liters", false, false, (ValueValidator)(object)new ValueRange<float>(10f, 200f), (string)null); _shitboxFuelCapacity = _capacityCategory.CreateEntry<float>("ShitboxFuelCapacity", 30f, "Shitbox Fuel Capacity (L)", "Fuel capacity for the Shitbox vehicle in liters", false, false, (ValueValidator)(object)new ValueRange<float>(10f, 200f), (string)null); _veeperFuelCapacity = _capacityCategory.CreateEntry<float>("VeeperFuelCapacity", 40f, "Veeper Fuel Capacity (L)", "Fuel capacity for the Veeper vehicle in liters", false, false, (ValueValidator)(object)new ValueRange<float>(10f, 200f), (string)null); _bruiserFuelCapacity = _capacityCategory.CreateEntry<float>("BruiserFuelCapacity", 40f, "Bruiser Fuel Capacity (L)", "Fuel capacity for the Bruiser vehicle in liters", false, false, (ValueValidator)(object)new ValueRange<float>(10f, 200f), (string)null); _dinklerFuelCapacity = _capacityCategory.CreateEntry<float>("DinklerFuelCapacity", 55f, "Dinkler Fuel Capacity (L)", "Fuel capacity for the Dinkler vehicle in liters", false, false, (ValueValidator)(object)new ValueRange<float>(10f, 200f), (string)null); _hounddogFuelCapacity = _capacityCategory.CreateEntry<float>("HounddogFuelCapacity", 35f, "Hounddog Fuel Capacity (L)", "Fuel capacity for the Hounddog vehicle in liters", false, false, (ValueValidator)(object)new ValueRange<float>(10f, 200f), (string)null); _cheetahFuelCapacity = _capacityCategory.CreateEntry<float>("CheetahFuelCapacity", 35f, "Cheetah Fuel Capacity (L)", "Fuel capacity for the Cheetah vehicle in liters", false, false, (ValueValidator)(object)new ValueRange<float>(10f, 200f), (string)null); _hotboxFuelCapacity = _capacityCategory.CreateEntry<float>("HotboxFuelCapacity", 50f, "Hotbox Fuel Capacity (L)", "Fuel capacity for the Hotbox vehicle in liters", false, false, (ValueValidator)(object)new ValueRange<float>(10f, 200f), (string)null); _showFuelGauge = _preferencesCategory.CreateEntry<bool>("ShowFuelGauge", true, "Show Fuel Gauge", "If enabled, shows fuel gauge UI when driving vehicles", false, false, (ValueValidator)null, (string)null); _enableDynamicPricing = _preferencesCategory.CreateEntry<bool>("EnableDynamicPricing", true, "Enable Dynamic Pricing", "If enabled, fuel prices will vary based on which day it is", false, false, (ValueValidator)null, (string)null); _enablePricingOnTier = _preferencesCategory.CreateEntry<bool>("EnablePricingOnTier", true, "Enable Pricing on Tier", "If enabled, fuel prices will be inflated based on the player's current tier", false, false, (ValueValidator)null, (string)null); _enableDebugLogging = _preferencesCategory.CreateEntry<bool>("EnableDebugLogging", true, "Enable Debug Logging", "If enabled, shows detailed debug information in console", false, false, (ValueValidator)null, (string)null); ModLogger.Debug("MelonPreferences initialized successfully"); } catch (Exception exception) { ModLogger.Error("Failed to initialize MelonPreferences", exception); } } private void InitializeSystems() { try { if (!EnableFuelSystem) { ModLogger.Debug("Fuel system disabled via preferences"); return; } _fuelSystemManager = new FuelSystemManager(); ModLogger.Debug("Fuel system manager initialized"); HarmonyPatches.SetModInstance(this); ModLogger.Debug("Harmony patches updated with fuel systems"); _fuelUIManager = new FuelUIManager(); ModLogger.Debug("Fuel UI manager initialized"); _fuelStationManager = new FuelStationManager(); ModLogger.Debug("Fuel station manager initialized"); ModLogger.Debug("All fuel systems initialized successfully"); } catch (Exception exception) { ModLogger.Error("Failed to initialize fuel systems", exception); } } public void ToggleDebugLogging() { try { if (_enableDebugLogging != null) { _enableDebugLogging.Value = !_enableDebugLogging.Value; ModLogger.Info("Debug logging " + (_enableDebugLogging.Value ? "enabled" : "disabled")); if (_enableDebugLogging.Value) { ModLogger.Info("Debug logging is now ON - you should see [FUEL] and [UI] messages"); } else { ModLogger.Info("Debug logging is now OFF"); } } } catch (Exception exception) { ModLogger.Error("Error toggling debug logging", exception); } } public override void OnApplicationQuit() { try { ModLogger.Info("S1FuelMod shutting down..."); _fuelSystemManager?.Dispose(); _fuelUIManager?.Dispose(); _fuelStationManager?.Dispose(); Instance = null; } catch (Exception exception) { ModLogger.Error("Error during mod shutdown", exception); } } public void SavePreferences() { try { MelonPreferences_Category? preferencesCategory = _preferencesCategory; if (preferencesCategory != null) { preferencesCategory.SaveToFile(true); } ModLogger.Debug("Preferences saved successfully"); } catch (Exception exception) { ModLogger.Error("Failed to save preferences", exception); } } public FuelSystemManager? GetFuelSystemManager() { return _fuelSystemManager; } public FuelUIManager? GetFuelUIManager() { return _fuelUIManager; } public FuelStationManager? GetFuelStationManager() { return _fuelStationManager; } } } namespace S1FuelMod.Utils { public static class Constants { public static class Defaults { public const bool ENABLE_FUEL_SYSTEM = true; public const float FUEL_CONSUMPTION_MULTIPLIER = 1f; public const float DEFAULT_FUEL_CAPACITY = 40f; public const float SHITBOX_FUEL_CAPACITY = 30f; public const float VEEPER_FUEL_CAPACITY = 40f; public const float BRUISER_FUEL_CAPACITY = 40f; public const float DINKLER_FUEL_CAPACITY = 55f; public const float HOUNDDOG_FUEL_CAPACITY = 35f; public const float CHEETAH_FUEL_CAPACITY = 35f; public const float HOTBOX_FUEL_CAPACITY = 50f; public const bool SHOW_FUEL_GAUGE = true; public const bool ENABLE_DEBUG_LOGGING = true; } public static class Constraints { public const float MIN_CONSUMPTION_MULTIPLIER = 0.1f; public const float MAX_CONSUMPTION_MULTIPLIER = 5f; public const float MIN_FUEL_CAPACITY = 10f; public const float MAX_FUEL_CAPACITY = 200f; } public static class Fuel { public const float BASE_CONSUMPTION_RATE = 360f; public const float IDLE_CONSUMPTION_RATE = 30f; public const float LOW_FUEL_WARNING_THRESHOLD = 20f; public const float CRITICAL_FUEL_WARNING_THRESHOLD = 5f; public const float REFUEL_RATE = 4f; public const float FUEL_PRICE_PER_LITER = 4f; public const float ENGINE_CUTOFF_FUEL_LEVEL = 0f; public const float ENGINE_SPUTTER_FUEL_LEVEL = 4f; } public static class UI { public static class Colors { public static readonly Color FUEL_NORMAL = new Color(0.2f, 0.8f, 0.2f, 0.8f); public static readonly Color FUEL_LOW = new Color(1f, 0.8f, 0f, 0.8f); public static readonly Color FUEL_CRITICAL = new Color(1f, 0.2f, 0.2f, 0.8f); public static readonly Color GAUGE_BACKGROUND = new Color(0.1f, 0.1f, 0.1f, 0.6f); public static readonly Color GAUGE_BORDER = new Color(0.8f, 0.8f, 0.8f, 0.8f); } public const float GAUGE_UPDATE_INTERVAL = 0.1f; public const float GAUGE_WIDTH = 200f; public const float GAUGE_HEIGHT = 20f; } public static class Game { public const string GAME_STUDIO = "TVGS"; public const string GAME_NAME = "Schedule I"; public const string VEHICLE_LAYER = "Vehicle"; public const string UI_LAYER = "UI"; public const string MAIN_SCENE = "Main"; public const string MENU_SCENE = "Menu"; } public static class Network { public const string FUEL_UPDATE_MESSAGE_TYPE = "fuel_update"; public const string FUEL_SYNC_MESSAGE_TYPE = "fuel_sync"; public const float SYNC_INTERVAL = 1f; } public static class SaveSystem { public const string FUEL_DATA_KEY_PREFIX = "fuel_"; public const string FUEL_LEVEL_KEY = "fuel_level"; public const string MAX_CAPACITY_KEY = "max_capacity"; public const string CONSUMPTION_RATE_KEY = "consumption_rate"; } public const string MOD_NAME = "S1FuelMod"; public const string MOD_VERSION = "1.0.0"; public const string MOD_AUTHORS = "Bars & SirTidez"; public const string MOD_DESCRIPTION = "Adds a comprehensive fuel system to LandVehicles in Schedule I"; public const string PREFERENCES_CATEGORY = "S1FuelMod"; public const string PREFERENCES_FILE_PATH = "UserData/S1FuelMod.cfg"; } public static class ModLogger { public static void Info(string message) { MelonLogger.Msg(message); } public static void Warning(string message) { MelonLogger.Warning(message); } public static void Error(string message) { MelonLogger.Error(message); } public static void Error(string message, Exception exception) { MelonLogger.Error(message + ": " + exception.Message); MelonLogger.Error("Stack trace: " + exception.StackTrace); } public static void Debug(string message) { Core? instance = Core.Instance; if (instance != null && instance.EnableDebugLogging) { MelonLogger.Msg("[DEBUG] " + message); } } public static void FuelDebug(string message) { Core? instance = Core.Instance; if (instance != null && instance.EnableDebugLogging) { MelonLogger.Msg("[FUEL] " + message); } } public static void UIDebug(string message) { Core? instance = Core.Instance; if (instance != null && instance.EnableDebugLogging) { MelonLogger.Msg("[UI] " + message); } } public static void LogInitialization() { Info("Initializing S1FuelMod v1.0.0 by Bars & SirTidez"); Info("Adds a comprehensive fuel system to LandVehicles in Schedule I"); } public static void LogVehicleFuel(string vehicleCode, string vehicleGUID, float currentFuel, float maxCapacity) { Core? instance = Core.Instance; if (instance != null && instance.EnableDebugLogging) { MelonLogger.Msg($"[FUEL] {vehicleCode} ({vehicleGUID.Substring(0, 8)}...): {currentFuel:F1}L / {maxCapacity:F1}L ({currentFuel / maxCapacity * 100f:F1}%)"); } } public static void LogFuelConsumption(string vehicleGUID, float consumed, float remaining) { Core? instance = Core.Instance; if (instance != null && instance.EnableDebugLogging) { MelonLogger.Msg($"[FUEL] Vehicle {vehicleGUID.Substring(0, 8)}... consumed {consumed:F3}L, remaining: {remaining:F1}L"); } } public static void LogFuelWarning(string vehicleGUID, float fuelLevel, string warningType) { MelonLogger.Warning($"[FUEL] Vehicle {vehicleGUID.Substring(0, 8)}... {warningType} fuel warning: {fuelLevel:F1}L"); } } } namespace S1FuelMod.UI { public class FuelGaugeUI : IDisposable { private readonly VehicleFuelSystem _fuelSystem; private GameObject? _gaugeContainer; private RectTransform? _gaugeRect; private Image? _gaugeBackground; private Slider? _gaugeSlider; private TextMeshProUGUI? _fuelText; private Image? _warningIcon; private Image? _gaugeSliderImage; private bool _isVisible = false; private float _lastUpdateTime = 0f; private Canvas? _parentCanvas; private CanvasGroup? _fuelTextParentGroup; public bool IsVisible => _isVisible && (Object)(object)_gaugeContainer != (Object)null && _gaugeContainer.activeInHierarchy; public FuelGaugeUI(VehicleFuelSystem fuelSystem) { _fuelSystem = fuelSystem ?? throw new ArgumentNullException("fuelSystem"); try { CreateGaugeUI(); SetupEventListeners(); UpdateDisplay(); ModLogger.UIDebug("FuelGaugeUI: Created for vehicle " + _fuelSystem.VehicleGUID.Substring(0, 8) + "..."); } catch (Exception exception) { ModLogger.Error("Error creating FuelGaugeUI", exception); } } private void CreateGaugeUI() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_007d: 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_00b3: 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_00df: Unknown result type (might be due to invalid IL or missing references) try { _parentCanvas = FindUICanvas(); if ((Object)(object)_parentCanvas == (Object)null) { ModLogger.Error("FuelGaugeUI: Could not find UI canvas"); return; } _gaugeContainer = new GameObject("FuelGauge"); _gaugeContainer.transform.SetParent(((Component)_parentCanvas).transform, false); _gaugeRect = _gaugeContainer.AddComponent<RectTransform>(); _gaugeRect.anchorMin = new Vector2(0.02f, 0.95f); _gaugeRect.anchorMax = new Vector2(0.02f, 0.95f); _gaugeRect.pivot = new Vector2(0f, 1f); _gaugeRect.sizeDelta = new Vector2(200f, 45f); _gaugeRect.anchoredPosition = Vector2.zero; CreateGaugeBackground(); CreateGaugeFill(); CreateFuelText(); CreateWarningIcon(); _gaugeContainer.SetActive(false); ModLogger.UIDebug("FuelGaugeUI: UI elements created successfully"); } catch (Exception exception) { ModLogger.Error("Error creating gauge UI elements", exception); } } private Canvas? FindUICanvas() { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) try { Scene activeScene = SceneManager.GetActiveScene(); string name = ((Scene)(ref activeScene)).name; ModLogger.UIDebug("FuelGaugeUI: Current scene: " + name); if (name.Contains("Menu")) { ModLogger.UIDebug("FuelGaugeUI: Skipping UI creation in scene: " + name); return null; } if (Singleton<HUD>.InstanceExists) { Canvas canvas = Singleton<HUD>.Instance.canvas; if ((Object)(object)canvas != (Object)null) { ModLogger.UIDebug("FuelGaugeUI: Found HUD Singleton canvas in scene: " + name); return canvas; } } GameObject val = GameObject.Find("HUD"); if ((Object)(object)val != (Object)null) { Canvas component = val.GetComponent<Canvas>(); if ((Object)(object)component != (Object)null) { ModLogger.UIDebug("FuelGaugeUI: Found HUD GameObject canvas in scene: " + name); return component; } } Canvas[] array = Object.FindObjectsOfType<Canvas>(); Canvas[] array2 = array; foreach (Canvas val2 in array2) { if ((int)val2.renderMode == 0 && !((Object)val2).name.Contains("Menu")) { ModLogger.UIDebug("FuelGaugeUI: Found suitable overlay canvas: " + ((Object)val2).name + " in scene: " + name); return val2; } } ModLogger.Warning("FuelGaugeUI: No suitable UI canvas found in scene: " + name); return null; } catch (Exception exception) { ModLogger.Error("Error finding UI canvas", exception); return null; } } private void CreateGaugeBackground() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown //IL_002d: 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_004f: 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) //IL_0078: 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) try { GameObject val = new GameObject("Background"); val.transform.SetParent(_gaugeContainer.transform, false); RectTransform val2 = val.AddComponent<RectTransform>(); val2.anchorMin = Vector2.zero; val2.anchorMax = new Vector2(1f, 0.8f); val2.offsetMin = Vector2.zero; val2.offsetMax = Vector2.zero; _gaugeBackground = val.AddComponent<Image>(); ((Graphic)_gaugeBackground).color = Constants.UI.Colors.GAUGE_BACKGROUND; _gaugeBackground.type = (Type)0; Outline val3 = val.AddComponent<Outline>(); ((Shadow)val3).effectColor = Constants.UI.Colors.GAUGE_BORDER; ((Shadow)val3).effectDistance = new Vector2(1f, 1f); } catch (Exception exception) { ModLogger.Error("Error creating gauge background", exception); } } private void CreateGaugeFill() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown //IL_0037: 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_0059: 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_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Expected O, but got Unknown //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0106: 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) try { GameObject val = new GameObject("Fill"); val.transform.SetParent(_gaugeContainer.transform, false); RectTransform val2 = val.AddComponent<RectTransform>(); val2.anchorMin = new Vector2(0.05f, 0.1f); val2.anchorMax = new Vector2(0.95f, 0.7f); val2.offsetMin = Vector2.zero; val2.offsetMax = Vector2.zero; _gaugeSlider = val.AddComponent<Slider>(); _gaugeSlider.direction = (Direction)1; _gaugeSlider.minValue = 0f; _gaugeSlider.maxValue = 100f; GameObject val3 = new GameObject("SliderFill"); val3.transform.SetParent(val.transform, false); RectTransform val4 = val3.AddComponent<RectTransform>(); _gaugeSliderImage = val3.AddComponent<Image>(); ((Graphic)_gaugeSliderImage).color = Constants.UI.Colors.FUEL_NORMAL; val4.anchorMin = Vector2.zero; val4.anchorMax = Vector2.one; val4.offsetMin = Vector2.zero; val4.offsetMax = Vector2.zero; _gaugeSlider.fillRect = val4; } catch (Exception exception) { ModLogger.Error("Error creating gauge fill", exception); } } private void CreateFuelText() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0059: 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_0085: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_010b: 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) try { GameObject val = new GameObject("FuelText"); val.transform.SetParent(_gaugeContainer.transform, false); _fuelTextParentGroup = val.AddComponent<CanvasGroup>(); RectTransform val2 = val.AddComponent<RectTransform>(); val2.anchorMin = new Vector2(0f, 0.8f); val2.anchorMax = new Vector2(1f, 1f); val2.pivot = new Vector2(0f, 1f); val2.anchoredPosition = new Vector2(0f, -50f); val2.sizeDelta = new Vector2(400f, 20f); _fuelText = val.AddComponent<TextMeshProUGUI>(); ((TMP_Text)_fuelText).alignment = (TextAlignmentOptions)513; ((TMP_Text)_fuelText).fontSize = 12f; ((TMP_Text)_fuelText).fontStyle = (FontStyles)1; ((Graphic)_fuelText).color = Color.white; ((TMP_Text)_fuelText).text = "50.0L (100%)"; Shadow val3 = val.AddComponent<Shadow>(); val3.effectColor = Color.black; val3.effectDistance = new Vector2(1f, -1f); } catch (Exception exception) { ModLogger.Error("Error creating fuel text", exception); } } private void CreateWarningIcon() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown //IL_0037: 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_0059: 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_0082: Unknown result type (might be due to invalid IL or missing references) try { GameObject val = new GameObject("WarningIcon"); val.transform.SetParent(_gaugeContainer.transform, false); RectTransform val2 = val.AddComponent<RectTransform>(); val2.anchorMin = new Vector2(0.85f, 0.15f); val2.anchorMax = new Vector2(0.95f, 0.65f); val2.offsetMin = Vector2.zero; val2.offsetMax = Vector2.zero; _warningIcon = val.AddComponent<Image>(); ((Graphic)_warningIcon).color = Constants.UI.Colors.FUEL_CRITICAL; _warningIcon.type = (Type)0; val.SetActive(false); } catch (Exception exception) { ModLogger.Error("Error creating warning icon", exception); } } private void SetupEventListeners() { try { if ((Object)(object)_fuelSystem != (Object)null) { ModLogger.UIDebug("FuelGaugeUI: Setting up event listeners for vehicle " + _fuelSystem.VehicleGUID.Substring(0, 8) + "..."); _fuelSystem.OnFuelLevelChanged.AddListener((UnityAction<float>)OnFuelLevelChanged); _fuelSystem.OnFuelPercentageChanged.AddListener((UnityAction<float>)OnFuelPercentageChanged); _fuelSystem.OnLowFuelWarning.AddListener((UnityAction<bool>)OnLowFuelWarning); _fuelSystem.OnCriticalFuelWarning.AddListener((UnityAction<bool>)OnCriticalFuelWarning); _fuelSystem.OnFuelEmpty.AddListener((UnityAction<bool>)OnFuelEmpty); ModLogger.UIDebug("FuelGaugeUI: Event listeners set up successfully for vehicle " + _fuelSystem.VehicleGUID.Substring(0, 8) + "..."); } else { ModLogger.Warning("FuelGaugeUI: Cannot setup event listeners - fuel system is null"); } } catch (Exception exception) { ModLogger.Error("Error setting up event listeners", exception); } } public void Update() { try { if (_isVisible && !((Object)(object)_gaugeContainer == (Object)null) && !(Time.time - _lastUpdateTime < 0.1f)) { UpdateDisplay(); _lastUpdateTime = Time.time; } } catch (Exception exception) { ModLogger.Error("Error updating fuel gauge display", exception); } } private void UpdateDisplay() { try { if ((Object)(object)_fuelSystem == (Object)null) { ModLogger.UIDebug("FuelGaugeUI: UpdateDisplay called but fuel system is null"); return; } float currentFuelLevel = _fuelSystem.CurrentFuelLevel; float maxFuelCapacity = _fuelSystem.MaxFuelCapacity; float fuelPercentage = _fuelSystem.FuelPercentage; if ((Object)(object)_gaugeSlider != (Object)null && (Object)(object)_gaugeSliderImage != (Object)null) { _gaugeSlider.value = fuelPercentage; } ModLogger.UIDebug($"FuelGaugeUI: Percentage shown: {fuelPercentage}"); if ((Object)(object)_fuelText != (Object)null) { string text = $"{currentFuelLevel:F1}L ({fuelPercentage:F1}%)"; ((TMP_Text)_fuelText).text = text; } UpdateGaugeColors(); UpdateWarningIcon(); } catch (Exception exception) { ModLogger.Error("Error updating gauge display", exception); } } private void UpdateGaugeColors() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: 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_0032: 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_0038: 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_0063: Unknown result type (might be due to invalid IL or missing references) //IL_004e: 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_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: 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_0082: 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) try { if (!((Object)(object)_fuelText == (Object)null)) { Color color = Color.white; Color val; if (_fuelSystem.IsCriticalFuel) { val = Constants.UI.Colors.FUEL_CRITICAL; color = Constants.UI.Colors.FUEL_CRITICAL; } else if (_fuelSystem.IsLowFuel) { val = Constants.UI.Colors.FUEL_LOW; color = Constants.UI.Colors.FUEL_LOW; } else { val = Constants.UI.Colors.FUEL_NORMAL; } ((Graphic)_gaugeSliderImage).color = Color.Lerp(((Graphic)_gaugeSliderImage).color, val, Time.deltaTime * 5f); ((Graphic)_fuelText).color = color; } } catch (Exception exception) { ModLogger.Error("Error updating gauge colors", exception); } } private void UpdateWarningIcon() { //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)_warningIcon == (Object)null) { return; } bool flag = _fuelSystem.IsLowFuel || _fuelSystem.IsCriticalFuel || _fuelSystem.IsOutOfFuel; ((Component)_warningIcon).gameObject.SetActive(flag); if (flag) { if (_fuelSystem.IsLowFuel) { float a = 0.5f + 0.5f * Mathf.Sin(Time.time * 2f); Color color = ((Graphic)_gaugeSliderImage).color; color.a = a; ((Graphic)_gaugeSliderImage).color = color; } else if (_fuelSystem.IsCriticalFuel || _fuelSystem.IsOutOfFuel) { float a2 = 0.5f + 0.5f * Mathf.Sin(Time.time * 3f); Color color2 = ((Graphic)_warningIcon).color; Color color3 = ((Graphic)_gaugeSliderImage).color; color2.a = a2; color3.a = a2; ((Graphic)_warningIcon).color = color2; ((Graphic)_gaugeSliderImage).color = color3; } else { Color color4 = ((Graphic)_warningIcon).color; color4.a = 1f; ((Graphic)_warningIcon).color = color4; } } } catch (Exception exception) { ModLogger.Error("Error updating warning icon", exception); } } public void Show() { //IL_0037: 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_004f: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)_gaugeContainer != (Object)null) { _gaugeContainer.SetActive(true); if ((Object)(object)_gaugeSliderImage != (Object)null) { Color color = ((Graphic)_gaugeSliderImage).color; color.a = 1f; ((Graphic)_gaugeSliderImage).color = color; } _isVisible = true; UpdateDisplay(); ModLogger.UIDebug("FuelGaugeUI: Shown for vehicle " + _fuelSystem.VehicleGUID.Substring(0, 8) + "..."); } } catch (Exception exception) { ModLogger.Error("Error showing fuel gauge", exception); } } public void Hide() { //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) //IL_0042: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)_gaugeContainer != (Object)null) { if ((Object)(object)_gaugeSliderImage != (Object)null) { Color color = ((Graphic)_gaugeSliderImage).color; color.a = 0f; ((Graphic)_gaugeSliderImage).color = color; } _gaugeContainer.SetActive(false); _isVisible = false; ModLogger.UIDebug("FuelGaugeUI: Hidden for vehicle " + _fuelSystem.VehicleGUID.Substring(0, 8) + "..."); } } catch (Exception exception) { ModLogger.Error("Error hiding fuel gauge", exception); } } private void OnFuelLevelChanged(float fuelLevel) { if (_isVisible) { UpdateDisplay(); } } private void OnFuelPercentageChanged(float percentage) { if (_isVisible) { UpdateDisplay(); } } private void OnLowFuelWarning(bool isActive) { ModLogger.UIDebug("FuelGaugeUI: Low fuel warning " + (isActive ? "activated" : "deactivated")); } private void OnCriticalFuelWarning(bool isActive) { ModLogger.UIDebug("FuelGaugeUI: Critical fuel warning " + (isActive ? "activated" : "deactivated")); } private void OnFuelEmpty(bool isEmpty) { ModLogger.UIDebug("FuelGaugeUI: Fuel empty state " + (isEmpty ? "activated" : "deactivated")); } public void Dispose() { try { if ((Object)(object)_fuelSystem != (Object)null) { _fuelSystem.OnFuelLevelChanged.RemoveListener((UnityAction<float>)OnFuelLevelChanged); _fuelSystem.OnFuelPercentageChanged.RemoveListener((UnityAction<float>)OnFuelPercentageChanged); _fuelSystem.OnLowFuelWarning.RemoveListener((UnityAction<bool>)OnLowFuelWarning); _fuelSystem.OnCriticalFuelWarning.RemoveListener((UnityAction<bool>)OnCriticalFuelWarning); _fuelSystem.OnFuelEmpty.RemoveListener((UnityAction<bool>)OnFuelEmpty); } if ((Object)(object)_gaugeContainer != (Object)null) { Object.Destroy((Object)(object)_gaugeContainer); _gaugeContainer = null; } _gaugeRect = null; _gaugeBackground = null; _gaugeSliderImage = null; _fuelText = null; _warningIcon = null; _isVisible = false; ModLogger.UIDebug("FuelGaugeUI: Disposed for vehicle " + _fuelSystem.VehicleGUID.Substring(0, 8) + "..."); } catch (Exception exception) { ModLogger.Error("Error disposing FuelGaugeUI", exception); } } } public class FuelUIManager : IDisposable { private readonly Dictionary<string, FuelGaugeUI> _activeFuelGauges = new Dictionary<string, FuelGaugeUI>(); private Player? _localPlayer; private LandVehicle? _currentVehicle; private string _currentVehicleGUID = string.Empty; private FuelGaugeUI? _currentGauge; public FuelUIManager() { ModLogger.UIDebug("FuelUIManager: Initializing..."); SceneManager.sceneLoaded += OnSceneLoaded; SceneManager.sceneUnloaded += OnSceneUnloaded; FindLocalPlayer(); ModLogger.UIDebug("FuelUIManager: Initialized"); } public void Update() { try { Core? instance = Core.Instance; if ((instance == null || instance.ShowFuelGauge) && IsInGameScene()) { if ((Object)(object)_localPlayer == (Object)null) { FindLocalPlayer(); return; } CheckVehicleChange(); _currentGauge?.Update(); } } catch (Exception exception) { ModLogger.Error("Error in FuelUIManager.Update", exception); } } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { try { ModLogger.UIDebug("FuelUIManager: Scene loaded: " + ((Scene)(ref scene)).name); _localPlayer = null; _currentVehicle = null; _currentVehicleGUID = string.Empty; if (_currentGauge != null) { _currentGauge.Hide(); _currentGauge = null; } } catch (Exception exception) { ModLogger.Error("Error handling scene loaded event", exception); } } private void OnSceneUnloaded(Scene scene) { try { ModLogger.UIDebug("FuelUIManager: Scene unloaded: " + ((Scene)(ref scene)).name); List<string> list = new List<string>(); foreach (KeyValuePair<string, FuelGaugeUI> activeFuelGauge in _activeFuelGauges) { if (activeFuelGauge.Value != null && !activeFuelGauge.Value.IsVisible) { list.Add(activeFuelGauge.Key); } } foreach (string item in list) { RemoveFuelGaugeForVehicle(item); } } catch (Exception exception) { ModLogger.Error("Error handling scene unloaded event", exception); } } private bool IsInGameScene() { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) try { Scene activeScene = SceneManager.GetActiveScene(); string name = ((Scene)(ref activeScene)).name; if (name.Contains("Menu")) { return false; } return true; } catch (Exception exception) { ModLogger.Error("Error checking game scene", exception); return false; } } private void FindLocalPlayer() { try { if ((Object)(object)Player.Local != (Object)null) { _localPlayer = Player.Local; ModLogger.UIDebug("FuelUIManager: Found local player"); } else { ModLogger.UIDebug("FuelUIManager: Local player not found"); } } catch (Exception exception) { ModLogger.Error("Error finding local player", exception); } } private void CheckVehicleChange() { try { if ((Object)(object)_localPlayer == (Object)null) { return; } LandVehicle val = null; string text = string.Empty; if ((Object)(object)_localPlayer.CurrentVehicle != (Object)null) { NetworkObject currentVehicle = _localPlayer.CurrentVehicle; val = ((Component)currentVehicle).GetComponent<LandVehicle>(); if ((Object)(object)val != (Object)null) { text = val.GUID.ToString(); } } if (text != _currentVehicleGUID) { if (_currentGauge != null) { _currentGauge.Hide(); _currentGauge = null; } _currentVehicle = val; _currentVehicleGUID = text; if ((Object)(object)_currentVehicle != (Object)null) { ShowFuelGaugeForVehicle(_currentVehicle); } LandVehicle? currentVehicle2 = _currentVehicle; ModLogger.UIDebug("FuelUIManager: Vehicle changed to " + (((currentVehicle2 != null) ? currentVehicle2.VehicleName : null) ?? "none")); } } catch (Exception exception) { ModLogger.Error("Error checking vehicle change", exception); } } public void ShowFuelGaugeForVehicle(LandVehicle vehicle) { try { if ((Object)(object)vehicle == (Object)null) { return; } string text = vehicle.GUID.ToString(); if (!_activeFuelGauges.ContainsKey(text)) { VehicleFuelSystem vehicleFuelSystem = Core.Instance?.GetFuelSystemManager()?.GetFuelSystem(vehicle.GUID.ToString()); if ((Object)(object)vehicleFuelSystem == (Object)null) { ModLogger.Warning("FuelUIManager: No fuel system found for vehicle " + text.Substring(0, 8) + "..."); return; } FuelGaugeUI value = new FuelGaugeUI(vehicleFuelSystem); _activeFuelGauges[text] = value; ModLogger.UIDebug("FuelUIManager: Created fuel gauge for vehicle " + text.Substring(0, 8) + "..."); } _currentGauge = _activeFuelGauges[text]; _currentGauge.Show(); ModLogger.UIDebug("FuelUIManager: Showing fuel gauge for " + vehicle.VehicleName); } catch (Exception exception) { ModLogger.Error("Error showing fuel gauge for vehicle", exception); } } public void HideFuelGaugeForVehicle(string vehicleGUID) { try { if (_activeFuelGauges.TryGetValue(vehicleGUID, out var value)) { value.Hide(); ModLogger.UIDebug("FuelUIManager: Hidden fuel gauge for vehicle " + vehicleGUID.Substring(0, 8) + "..."); } } catch (Exception exception) { ModLogger.Error("Error hiding fuel gauge for vehicle", exception); } } public void RemoveFuelGaugeForVehicle(string vehicleGUID) { try { if (_activeFuelGauges.TryGetValue(vehicleGUID, out var value)) { value.Dispose(); _activeFuelGauges.Remove(vehicleGUID); if (_currentGauge == value) { _currentGauge = null; } ModLogger.UIDebug("FuelUIManager: Removed fuel gauge for vehicle " + vehicleGUID.Substring(0, 8) + "..."); } } catch (Exception exception) { ModLogger.Error("Error removing fuel gauge for vehicle", exception); } } public void HideAllGauges() { try { foreach (FuelGaugeUI value in _activeFuelGauges.Values) { value?.Hide(); } _currentGauge = null; ModLogger.UIDebug("FuelUIManager: Hidden all fuel gauges"); } catch (Exception exception) { ModLogger.Error("Error hiding all fuel gauges", exception); } } public void ShowAllGauges() { try { foreach (FuelGaugeUI value in _activeFuelGauges.Values) { value?.Show(); } ModLogger.UIDebug("FuelUIManager: Shown all fuel gauges (debug mode)"); } catch (Exception exception) { ModLogger.Error("Error showing all fuel gauges", exception); } } public FuelUIStats GetStatistics() { FuelUIStats fuelUIStats = new FuelUIStats(); try { fuelUIStats.TotalGauges = _activeFuelGauges.Count; fuelUIStats.HasCurrentGauge = _currentGauge != null; LandVehicle? currentVehicle = _currentVehicle; fuelUIStats.CurrentVehicleName = ((currentVehicle != null) ? currentVehicle.VehicleName : null) ?? "None"; Player? localPlayer = _localPlayer; fuelUIStats.LocalPlayerInVehicle = (Object)(object)((localPlayer != null) ? localPlayer.CurrentVehicle : null) != (Object)null; foreach (FuelGaugeUI value in _activeFuelGauges.Values) { if (value != null) { if (value.IsVisible) { fuelUIStats.VisibleGauges++; } else { fuelUIStats.HiddenGauges++; } } else { fuelUIStats.InvalidGauges++; } } } catch (Exception exception) { ModLogger.Error("Error calculating fuel UI statistics", exception); } return fuelUIStats; } public void Dispose() { try { ModLogger.UIDebug("FuelUIManager: Disposing..."); SceneManager.sceneLoaded -= OnSceneLoaded; SceneManager.sceneUnloaded -= OnSceneUnloaded; foreach (FuelGaugeUI value in _activeFuelGauges.Values) { value?.Dispose(); } _activeFuelGauges.Clear(); _currentGauge = null; _currentVehicle = null; _localPlayer = null; ModLogger.Info("FuelUIManager: Disposed"); } catch (Exception exception) { ModLogger.Error("Error disposing FuelUIManager", exception); } } } public class FuelUIStats { public int TotalGauges { get; set; } public int VisibleGauges { get; set; } public int HiddenGauges { get; set; } public int InvalidGauges { get; set; } public bool HasCurrentGauge { get; set; } public string CurrentVehicleName { get; set; } = string.Empty; public bool LocalPlayerInVehicle { get; set; } } } namespace S1FuelMod.Systems { public class FuelStation : InteractableObject { private enum MessageType { Info, Warning, Error, Success } private float refuelRate = 40f; private float pricePerLiter = 1f; private float maxInteractionDistance = 4f; private float vehicleDetectionRadius = 6f; private AudioSource refuelAudioSource; private AudioClip refuelStartSound; private AudioClip refuelLoopSound; private AudioClip refuelEndSound; private bool _isRefueling = false; private LandVehicle _targetVehicle; private VehicleFuelSystem _targetFuelSystem; private float _refuelStartTime; private float _totalFuelAdded; private float _totalCost; private MoneyManager _moneyManager; private FuelSystemManager _fuelSystemManager; private void Start() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) try { InitializeFuelStation(); ModLogger.Debug($"FuelStation initialized at {((Component)this).transform.position}"); } catch (Exception exception) { ModLogger.Error("Error initializing FuelStation", exception); } } private void InitializeFuelStation() { ((InteractableObject)this).SetMessage("Refuel Vehicle - Hold to refuel"); ((InteractableObject)this).SetInteractionType((EInteractionType)0); base.MaxInteractionRange = maxInteractionDistance; base.RequiresUniqueClick = false; if (NetworkSingleton<MoneyManager>.InstanceExists) { _moneyManager = NetworkSingleton<MoneyManager>.Instance; } if (Core.Instance?.GetFuelSystemManager() != null) { _fuelSystemManager = Core.Instance.GetFuelSystemManager(); } if ((Object)(object)refuelAudioSource == (Object)null) { refuelAudioSource = ((Component)this).GetComponent<AudioSource>(); if ((Object)(object)refuelAudioSource == (Object)null) { refuelAudioSource = ((Component)this).gameObject.AddComponent<AudioSource>(); } } if ((Object)(object)refuelAudioSource != (Object)null) { refuelAudioSource.playOnAwake = false; refuelAudioSource.loop = false; refuelAudioSource.volume = 0.7f; refuelAudioSource.spatialBlend = 1f; refuelAudioSource.maxDistance = 20f; } refuelRate = 4f; pricePerLiter = 4f; } public override void Hovered() { //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Invalid comparison between Unknown and I4 try { LandVehicle nearestOwnedVehicle = GetNearestOwnedVehicle(); if ((Object)(object)nearestOwnedVehicle != (Object)null && (Object)(object)((Component)nearestOwnedVehicle).gameObject != (Object)null) { try { VehicleFuelSystem vehicleFuelSystem = _fuelSystemManager?.GetFuelSystem(nearestOwnedVehicle.GUID.ToString()); if ((Object)(object)vehicleFuelSystem != (Object)null) { SetFuelPrice(); float num = vehicleFuelSystem.MaxFuelCapacity - vehicleFuelSystem.CurrentFuelLevel; float num2 = num * pricePerLiter; if (num > 0.1f) { ((InteractableObject)this).SetMessage($"Refuel {nearestOwnedVehicle.VehicleName} - {MoneyManager.FormatAmount(num2, false, false)} | ${pricePerLiter:F2}/L"); ((InteractableObject)this).SetInteractableState((EInteractableState)0); } else { ((InteractableObject)this).SetMessage(nearestOwnedVehicle.VehicleName + " - Tank Full"); ((InteractableObject)this).SetInteractableState((EInteractableState)1); } } else { ((InteractableObject)this).SetMessage("Vehicle has no fuel system"); ((InteractableObject)this).SetInteractableState((EInteractableState)1); } } catch (Exception ex) { ModLogger.Debug("Error accessing vehicle properties in Hovered: " + ex.Message); ((InteractableObject)this).SetMessage("Vehicle not accessible"); ((InteractableObject)this).SetInteractableState((EInteractableState)1); } } else { ((InteractableObject)this).SetMessage("No owned vehicle nearby"); ((InteractableObject)this).SetInteractableState((EInteractableState)1); } if (base.onHovered != null) { base.onHovered.Invoke(); } if ((int)base.interactionState != 2) { ((InteractableObject)this).ShowMessage(); } } catch (Exception exception) { ModLogger.Error("Error in FuelStation.Hovered", exception); ((InteractableObject)this).SetMessage("Error"); ((InteractableObject)this).SetInteractableState((EInteractableState)1); } } public override void StartInteract() { //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Invalid comparison between Unknown and I4 if (_isRefueling) { return; } try { _targetVehicle = GetNearestOwnedVehicle(); if ((Object)(object)_targetVehicle == (Object)null || (Object)(object)((Component)_targetVehicle).gameObject == (Object)null) { ShowMessage("No owned vehicle nearby!", MessageType.Error); return; } try { Core.Instance?.GetFuelUIManager()?.ShowFuelGaugeForVehicle(_targetVehicle); } catch (Exception ex) { ModLogger.Debug("Error showing fuel gauge UI: " + ex.Message); } try { _targetFuelSystem = _fuelSystemManager?.GetFuelSystem(_targetVehicle.GUID.ToString()); } catch (Exception ex2) { ModLogger.Debug("Error getting fuel system: " + ex2.Message); _targetFuelSystem = null; } if ((Object)(object)_targetFuelSystem == (Object)null) { ShowMessage("Vehicle has no fuel system!", MessageType.Error); return; } float num = _targetFuelSystem.MaxFuelCapacity - _targetFuelSystem.CurrentFuelLevel; if (num <= 0.1f) { ShowMessage("Vehicle tank is already full!", MessageType.Warning); return; } if ((Object)(object)_moneyManager != (Object)null && _moneyManager.onlineBalance < pricePerLiter) { ShowMessage("Insufficient funds! Need " + MoneyManager.FormatAmount(pricePerLiter, false, false) + " minimum", MessageType.Error); return; } if ((int)base.interactionState != 1) { if (base.onInteractStart != null) { base.onInteractStart.Invoke(); } Singleton<InteractionManager>.Instance.LerpDisplayScale(0.9f); } StartRefueling(); } catch (Exception exception) { ModLogger.Error("Error starting fuel station interaction", exception); ShowMessage("Error starting refuel process", MessageType.Error); } } public override void EndInteract() { try { Core? instance = Core.Instance; if (instance != null) { FuelUIManager? fuelUIManager = instance.GetFuelUIManager(); if (fuelUIManager != null) { LandVehicle targetVehicle = _targetVehicle; fuelUIManager.HideFuelGaugeForVehicle((targetVehicle != null) ? targetVehicle.GUID.ToString() : null); } } if (_isRefueling) { StopRefueling(); } if (base.onInteractEnd != null) { base.onInteractEnd.Invoke(); } Singleton<InteractionManager>.Instance.LerpDisplayScale(1f); } catch (Exception exception) { ModLogger.Error("Error in FuelStation.EndInteract", exception); } } private void StartRefueling() { _isRefueling = true; _refuelStartTime = Time.time; _totalFuelAdded = 0f; _totalCost = 0f; PlayRefuelSound(refuelStartSound); ModLogger.Debug("Started refueling " + _targetVehicle.VehicleName + " at fuel station"); ShowMessage("Refueling " + _targetVehicle.VehicleName + "...", MessageType.Info); } private void StopRefueling() { if (_isRefueling) { _isRefueling = false; PlayRefuelSound(refuelEndSound); if (_totalFuelAdded > 0.01f) { ProcessPayment(); ShowMessage($"Refueled {_totalFuelAdded:F1}L for {MoneyManager.FormatAmount(_totalCost, false, false)}", MessageType.Success); ModLogger.Debug($"Completed refueling: {_totalFuelAdded:F1}L for {MoneyManager.FormatAmount(_totalCost, false, false)}"); } else { ShowMessage("No fuel added", MessageType.Warning); } _targetVehicle = null; _targetFuelSystem = null; _totalFuelAdded = 0f; _totalCost = 0f; } } private void Update() { if (_isRefueling && (Object)(object)_targetFuelSystem != (Object)null) { UpdateRefueling(); } } private void UpdateRefueling() { //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) float deltaTime = Time.deltaTime; float num = refuelRate * deltaTime; float num2 = num * pricePerLiter; if ((Object)(object)_targetVehicle == (Object)null || (Object)(object)_targetFuelSystem == (Object)null) { return; } if ((Object)(object)_moneyManager != (Object)null && _moneyManager.onlineBalance < num2) { StopRefueling(); ShowMessage("Insufficient funds to continue refueling!", MessageType.Error); return; } float num3 = _targetFuelSystem.AddFuel(num); if (num3 > 0f) { _totalFuelAdded += num3; _totalCost += num3 * pricePerLiter; if ((Object)(object)refuelLoopSound != (Object)null && !refuelAudioSource.isPlaying) { PlayRefuelSound(refuelLoopSound); } } else { StopRefueling(); ShowMessage("Vehicle tank is now full!", MessageType.Success); } if (!((Object)(object)_targetVehicle == (Object)null) && !((Object)(object)((Component)_targetVehicle).transform == (Object)null) && Vector3.Distance(((Component)this).transform.position, ((Component)_targetVehicle).transform.position) > vehicleDetectionRadius) { StopRefueling(); ShowMessage("Vehicle moved too far away!", MessageType.Warning); } } private void ProcessPayment() { if ((Object)(object)_moneyManager != (Object)null && _totalCost > 0f) { string text = "Fuel Station"; string text2 = $"Refueled {_targetVehicle.VehicleName} with {_totalFuelAdded:F1}L"; _moneyManager.CreateOnlineTransaction(text, 0f - _totalCost, 1f, text2); ModLogger.Debug($"Processed fuel payment: {MoneyManager.FormatAmount(_totalCost, false, false)} for {_totalFuelAdded:F1}L"); } } private LandVehicle GetNearestOwnedVehicle() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) try { Collider[] array = null; try { array = Physics.OverlapSphere(((Component)this).transform.position, vehicleDetectionRadius); } catch (Exception exception) { ModLogger.Error("Error calling Physics.OverlapSphere", exception); return null; } if (array == null) { return null; } List<LandVehicle> list = new List<LandVehicle>(); Collider[] array2 = array; foreach (Collider val in array2) { if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null) { continue; } LandVehicle val2 = null; try { val2 = ((Component)val).GetComponentInParent<LandVehicle>(); } catch (Exception ex) { ModLogger.Debug("Error getting LandVehicle component: " + ex.Message); continue; } if (!((Object)(object)val2 != (Object)null) || !((Object)(object)((Component)val2).gameObject != (Object)null)) { continue; } try { if (val2.IsPlayerOwned && !list.Contains(val2)) { list.Add(val2); } } catch (Exception ex2) { ModLogger.Debug("Skipping vehicle due to property access error: " + ex2.Message); } } if (list.Count > 0) { try { LandVehicle val3 = list.OrderBy((LandVehicle v) => Vector3.Distance(((Component)this).transform.position, ((Component)v).transform.position)).First(); if (Vector3.Distance(((Component)this).transform.position, ((Component)val3).transform.position) <= maxInteractionDistance) { return val3; } } catch (Exception exception2) { ModLogger.Error("Error processing vehicle list", exception2); } } return null; } catch (Exception exception3) { ModLogger.Error("Error finding nearest owned vehicle", exception3); return null; } } private void PlayRefuelSound(AudioClip clip) { if ((Object)(object)refuelAudioSource != (Object)null && (Object)(object)clip != (Object)null) { refuelAudioSource.clip = clip; refuelAudioSource.Play(); } } private void ShowMessage(string message, MessageType type) { try { ModLogger.Debug("FuelStation: " + message); switch (type) { case MessageType.Error: ModLogger.Warning("FuelStation Error: " + message); break; case MessageType.Warning: ModLogger.Warning("FuelStation Warning: " + message); break; case MessageType.Success: ModLogger.Info("FuelStation Success: " + message); break; default: ModLogger.Info("FuelStation: " + message); break; } } catch (Exception exception) { ModLogger.Error("Error showing fuel station message", exception); } } private void SetFuelPrice() { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected I4, but got Unknown float num = 4f; Core? instance = Core.Instance; if (instance == null || !instance.EnableDynamicPricing) { pricePerLiter = num; return; } int hashCode = ("Petrol" + NetworkSingleton<TimeManager>.Instance.DayIndex).GetHashCode(); float num2 = Mathf.Lerp(0f, 0.2f, Mathf.InverseLerp(-2.1474836E+09f, 2.1474836E+09f, (float)hashCode)); ERank rank = NetworkSingleton<LevelManager>.Instance.Rank; if (1 == 0) { } float num3 = (int)rank switch { 0 => 1f, 1 => 1.05f, 2 => 1.1f, 3 => 1.15f, 4 => 1.2f, 5 => 1.25f, 6 => 1.3f, 7 => 1.4f, 8 => 1.5f, 9 => 1.6f, 10 => 1.8f, _ => 1f, }; if (1 == 0) { } float num4 = num3; float num5 = (Core.Instance.EnablePricingOnTier ? (num + num * num2 * num4) : num); pricePerLiter = num5; } private void OnDrawGizmosSelected() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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_0061: 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_0082: Unknown result type (might be due to invalid IL or missing references) Gizmos.color = Color.green; Gizmos.DrawWireSphere(((Component)this).transform.position, vehicleDetectionRadius); Gizmos.color = Color.blue; Gizmos.DrawWireSphere(((Component)this).transform.position, maxInteractionDistance); if (_isRefueling && (Object)(object)_targetVehicle != (Object)null) { Gizmos.color = Color.yellow; Gizmos.DrawLine(((Component)this).transform.position, ((Component)_targetVehicle).transform.position); } } private void OnDestroy() { try { if (_isRefueling) { StopRefueling(); } ModLogger.Debug("FuelStation destroyed"); } catch (Exception exception) { ModLogger.Error("Error destroying FuelStation", exception); } } } public class FuelStationManager : IDisposable { private readonly List<FuelStation> _activeFuelStations = new List<FuelStation>(); private readonly string FUEL_STATION_OBJECT_NAME = "Bowser (EMC Merge)"; private readonly string FUEL_STATION_OBJECT_NAME_ALT = "Bowser (EMC Merge)"; private bool _hasInitialized = false; private float _lastStationCheckTime = 0f; private const float STATION_CHECK_INTERVAL = 15f; private const int EXPECTED_FUEL_STATIONS = 4; private bool _shouldStopChecking = false; public FuelStationManager() { ModLogger.Debug("FuelStationManager: Initializing..."); try { ScanForFuelStations(); _hasInitialized = true; ModLogger.Debug($"FuelStationManager: Initialized with {_activeFuelStations.Count} fuel stations"); } catch (Exception exception) { ModLogger.Error("Error initializing FuelStationManager", exception); } } public void Update() { try { CleanupDestroyedStations(); if (!_shouldStopChecking && Time.time - _lastStationCheckTime > 15f) { CheckForNewFuelStations(); _lastStationCheckTime = Time.time; } } catch (Exception exception) { ModLogger.Error("Error in FuelStationManager.Update", exception); } } private void ScanForFuelStations() { try { int num = 0; int num2 = 0; GameObject[] collection = FindGameObjectsWithName(FUEL_STATION_OBJECT_NAME); GameObject[] collection2 = FindGameObjectsWithName(FUEL_STATION_OBJECT_NAME_ALT); List<GameObject> list = new List<GameObject>(); list.AddRange(collection); list.AddRange(collection2); foreach (GameObject item in list) { if ((Object)(object)item != (Object)null) { num++; if (SetupFuelStation(item)) { num2++; } } } if (num > 0) { ModLogger.Debug($"FuelStationManager: Found {num} Bowser objects, setup {num2} new fuel stations"); } else { ModLogger.Debug("FuelStationManager: No Bowser objects found in scene"); } if (_activeFuelStations.Count >= 4 && !_shouldStopChecking) { _shouldStopChecking = true; ModLogger.Debug($"FuelStationManager: Found expected number of fuel stations ({4}), stopping periodic checks for performance"); } } catch (Exception exception) { ModLogger.Error("Error scanning for fuel stations", exception); } } private void CheckForNewFuelStations() { try { int num = 0; GameObject[] collection = FindGameObjectsWithName(FUEL_STATION_OBJECT_NAME); GameObject[] collection2 = FindGameObjectsWithName(FUEL_STATION_OBJECT_NAME_ALT); List<GameObject> list = new List<GameObject>(); list.AddRange(collection); list.AddRange(collection2); foreach (GameObject item in list) { if (!((Object)(object)item != (Object)null)) { continue; } Transform parent = item.transform.parent; GameObject val = ((parent != null) ? ((Component)parent).gameObject : null); if (!((Object)(object)val != (Object)null)) { continue; } FuelStation component = val.GetComponent<FuelStation>(); if ((Object)(object)component == (Object)null) { if (SetupFuelStation(item)) { num++; } } else if (!_activeFuelStations.Contains(component)) { _activeFuelStations.Add(component); ModLogger.Debug("FuelStationManager: Added existing fuel station to tracking: " + ((Object)val).name); } } if (num > 0) { ModLogger.Debug($"FuelStationManager: Found and setup {num} new fuel stations"); } if (_activeFuelStations.Count >= 4 && !_shouldStopChecking) { _shouldStopChecking = true; ModLogger.Debug($"FuelStationManager: Found expected number of fuel stations ({4}), stopping periodic checks for performance"); } } catch (Exception exception) { ModLogger.Error("Error checking for new fuel stations", exception); } } private bool SetupFuelStation(GameObject bowserObject) { //IL_00fe: Unknown result type (might be due to invalid IL or missing references) try { Transform parent = bowserObject.transform.parent; GameObject val = ((parent != null) ? ((Component)parent).gameObject : null); if ((Object)(object)val == (Object)null) { ModLogger.Warning("FuelStationManager: Bowser object " + ((Object)bowserObject).name + " has no parent - skipping"); return false; } FuelStation component = val.GetComponent<FuelStation>(); if ((Object)(object)component != (Object)null) { if (!_activeFuelStations.Contains(component)) { _activeFuelStations.Add(component); ModLogger.Debug("FuelStationManager: Added existing fuel station to tracking: " + ((Object)val).name + " (parent of " + ((Object)bowserObject).name + ")"); } return true; } FuelStation fuelStation = val.AddComponent<FuelStation>(); if ((Object)(object)fuelStation != (Object)null) { _activeFuelStations.Add(fuelStation); ModLogger.Debug($"FuelStationManager: Setup fuel station on {((Object)val).name} (parent of {((Object)bowserObject).name}) at position {val.transform.position}"); ConfigureFuelStation(fuelStation, val, bowserObject); return true; } ModLogger.Warning("FuelStationManager: Failed to add FuelStation component to " + ((Object)val).name); return false; } catch (Exception exception) { ModLogger.Error("Error setting up fuel station for bowser " + ((Object)bowserObject).name, exception); return false; } } private void ConfigureFuelStation(FuelStation fuelStation, GameObject parentObject, GameObject bowserObject) { try { AudioSource componentInChildren = parentObject.GetComponentInChildren<AudioSource>(); if ((Object)(object)componentInChildren != (Object)null) { ModLogger.Debug("FuelStationManager: Found existing audio source on fuel station " + ((Object)parentObject).name); } ModLogger.Debug("FuelStationManager: Configured fuel station " + ((Object)parentObject).name + " with bowser child " + ((Object)bowserObject).name); } catch (Exception exception) { ModLogger.Error("Error configuring fuel station for " + ((Object)parentObject).name, exception); } } private GameObject[] FindGameObjectsWithName(string name) { List<GameObject> list = new List<GameObject>(); GameObject[] array = Object.FindObjectsOfType<GameObject>(); GameObject[] array2 = array; foreach (GameObject val in array2) { if (((Object)val).name == name) { list.Add(val); } } return list.ToArray(); } private void CleanupDestroyedStations() { try { for (int num = _activeFuelStations.Count - 1; num >= 0; num--) { if ((Object)(object)_activeFuelStations[num] == (Object)null || (Object)(object)((Component)_activeFuelStations[num]).gameObject == (Object)null) { _activeFuelStations.RemoveAt(num); } } } catch (Exception exception) { ModLogger.Error("Error cleaning up destroyed fuel stations", exception); } } public IReadOnlyList<FuelStation> GetActiveFuelStations() { return _activeFuelStations.AsReadOnly(); } public FuelStationStats GetStatistics() { FuelStationStats fuelStationStats = new FuelStationStats { TotalStations = _activeFuelStations.Count, ActiveStations = 0, InactiveStations = 0 }; try { foreach (FuelStation activeFuelStation in _activeFuelStations) { if ((Object)(object)activeFuelStation != (Object)null && (Object)(object)((Component)activeFuelStation).gameObject != (Object)null && ((Behaviour)activeFuelStation).enabled) { fuelStationStats.ActiveStations++; } else { fuelStationStats.InactiveStations++; } } } catch (Exception exception) { ModLogger.Error("Error calculating fuel station statistics", exception); } return fuelStationStats; } public void ForceScan() { ModLogger.Debug("FuelStationManager: Forcing fuel station scan..."); _shouldStopChecking = false; ScanForFuelStations(); } public void Dispose() { try { ModLogger.Debug("FuelStationManager: Disposing..."); _activeFuelStations.Clear(); ModLogger.Debug("FuelStationManager: Disposed"); } catch (Exception exception) { ModLogger.Error("Error disposing FuelStationManager", exception); } } } public class FuelStationStats { public int TotalStations { get; set; } public int ActiveStations { get; set; } public int InactiveStations { get; set; } } public class FuelSystemManager : IDisposable { private readonly Dictionary<string, VehicleFuelSystem> _vehicleFuelSystems = new Dictionary<string, VehicleFuelSystem>(); private bool _debugInfoEnabled = false; private float _lastDebugLogTime = 0f; private const float DEBUG_LOG_INTERVAL = 5f; private readonly FuelNetworkManager _network = new FuelNetworkManager(); public FuelSystemManager() { ModLogger.Debug("FuelSystemManager: Initializing..."); InitializeExistingVehicles(); ModLogger.Debug($"FuelSystemManager: Initialized with {_vehicleFuelSystems.Count} vehicles"); _network.Initialize(); foreach (VehicleFuelSystem value in _vehicleFuelSystems.Values) { _network.RegisterFuelSystem(value); } ModLogger.Debug($"FuelSystemManager: Registered {_vehicleFuelSystems.Count} fuel systems with network manager"); } public void Update() { try { if (_debugInfoEnabled && Time.time - _lastDebugLogTime > 5f) { LogDebugInfo(); _lastDebugLogTime = Time.time; } CheckForNewVehicles(); _network.Update(); } catch (Exception exception) { ModLogger.Error("Error in FuelSystemManager.Update", exception); } } private void InitializeExistingVehicles() { try { LandVehicle[] array = Object.FindObjectsOfType<LandVehicle>(); LandVehicle[] array2 = array; foreach (LandVehicle val in array2) { if ((Object)(object)val != (Object)null) { AddFuelSystemToVehicle(val); } } ModLogger.Debug($"FuelSystemManager: Found and initialized {array.Length} existing vehicles"); } catch (Exception exception) { ModLogger.Error("Error initializing existing vehicles", exception); } } private void CheckForNewVehicles() { try { if (!NetworkSingleton<VehicleManager>.InstanceExists) { return; } VehicleManager instance = NetworkSingleton<VehicleManager>.Instance; foreach (LandVehicle allVehicle in instance.AllVehicles) { if ((Object)(object)allVehicle != (Object)null && !_vehicleFuelSystems.ContainsKey(allVehicle.GUID.ToString())) { VehicleFuelSystem vehicleFuelSystem = AddFuelSystemToVehicle(allVehicle); if ((Object)(object)vehicleFuelSystem != (Object)null) { _network.RegisterFuelSystem(vehicleFuelSystem); } } } } catch (Exception exception) { ModLogger.Error("Error checking for new vehicles", exception); } } public VehicleFuelSystem? AddFuelSystemToVehicle(LandVehicle vehicle) { try { if ((Object)(object)vehicle == (Object)null) { ModLogger.Warning("FuelSystemManager: Attempted to add fuel system to null vehicle"); return null; } string text = vehicle.GUID.ToString(); if (_vehicleFuelSystems.ContainsKey(text)) { ModLogger.Debug("FuelSystemManager: Vehicle " + text.Substring(0, 8) + "... already has fuel system"); return _vehicleFuelSystems[text]; } VehicleFuelSystem component = ((Component)vehicle).GetComponent<VehicleFuelSystem>(); if ((Object)(object)component != (Object)null) { _vehicleFuelSystems[text] = component; ModLogger.Debug("FuelSystemManager: Found existing fuel system for vehicle " + text.Substring(0, 8) + "..."); return component; } VehicleFuelSystem vehicleFuelSystem = ((Component)vehicle).gameObject.AddComponent<VehicleFuelSystem>(); _vehicleFuelSystems[text] = vehicleFuelSystem; _network.RegisterFuelSystem(vehicleFuelSystem); ModLogger.Debug("FuelSystemManager: Added fuel system to " + vehicle.VehicleName + " (" + text.Substring(0, 8) + "...)"); return vehicleFuelSystem; } catch (Exception exception) { ModLogger.Error("Error adding fuel system to vehicle", exception); return null; } } public void RemoveFuelSystem(string vehicleGUID) { try { if (_vehicleFuelSystems.ContainsKey(vehicleGUID)) { VehicleFuelSystem vehicleFuelSystem = _vehicleFuelSystems[vehicleGUID]; if ((Object)(object)vehicleFuelSystem != (Object)null) { _network.UnregisterFuelSystem(vehicleFuelSystem); } _vehicleFuelSystems.Remove(vehicleGUID); ModLogger.Debug("FuelSystemManager: Removed fuel system for vehicle " + vehicleGUID.Substring(0, 8) + "..."); } } catch (Exception exception) { ModLogger.Error("Error removing fuel system", exception); } } public VehicleFuelSystem? GetFuelSystem(string vehicleGUID) { VehicleFuelSystem value; return _vehicleFuelSystems.TryGetValue(vehicleGUID, out value) ? value : null; } public VehicleFuelSystem? GetFuelSystem(LandVehicle vehicle) { if ((Object)(object)vehicle == (Object)null) { return null; } return GetFuelSystem(vehicle.GUID.ToString()); } public IReadOnlyCollection<VehicleFuelSystem> GetAllFuelSystems() { return _vehicleFuelSystems.Values; } public void RefillAllVehicles() { try { int num = 0; foreach (VehicleFuelSystem value in _vehicleFuelSystems.Values) { if ((Object)(object)value != (Object)null && (Object)(object)((Component)value).gameObject != (Object)null) { value.SetFuelLevel(value.MaxFuelCapacity); num++; } } ModLogger.Debug($"FuelSystemManager: Refilled {num} vehicles"); } catch (Exception exception) { ModLogger.Error("Error refilling all vehicles", exception); } } public void DrainAllVehicles(float amount) { try { int num = 0; foreach (VehicleFuelSystem value in _vehicleFuelSystems.Values) { if ((Object)(object)value != (Object)null && (Object)(object)((Component)value).gameObject != (Object)null) { value.ConsumeFuel(amount); num++; } } ModLogger.Debug($"FuelSystemManager: Drained {amount}L from {num} vehicles"); } catch (Exception exception) { ModLogger.Error("Error draining all vehicles", exception); } } public void ToggleDebugInfo() { _debugInfoEnabled = !_debugInfoEnabled; ModLogger.Info("FuelSystemManager: Debug info " + (_debugInfoEnabled ? "enabled" : "disabled")); if (_debugInfoEnabled) { LogDebugInfo(); } } private void LogDebugInfo() { try { ModLogger.Info($"=== Fuel System Debug Info ({_vehicleFuelSystems.Count} vehicles) ==="); foreach (KeyValuePair<string, VehicleFuelSystem> vehicleFuelSystem in _vehicleFuelSystems) { VehicleFuelSystem value = vehicleFuelSystem.Value; if ((Object)(object)value != (Object)null && (Object)(object)((Component)value).gameObject != (Object)null) { LandVehicle component = ((Component)value).GetComponent<LandVehicle>(); string text = ((component != null) ? component.VehicleName : null) ?? "Unknown"; string text2 = ((component != null) ? component.VehicleCode : null) ?? "unknown"; ModLogger.Info($" {text} ({text2}): {value.CurrentFuelLevel:F1}L / {value.MaxFuelCapacity:F1}L " + $"({value.FuelPercentage:F1}%) - Engine: {value.IsEngineRunning} - " + "Warnings: " + (value.IsLowFuel ? "LOW" : "") + " " + (value.IsCriticalFuel ? "CRITICAL" : "") + " " + (value.IsOutOfFuel ? "EMPTY" : "")); } else { ModLogger.Warning(" Invalid fuel system found for vehicle " + vehicleFuelSystem.Key); } } ModLogger.Info("=== End Fuel System Debug Info ==="); } catch (Exception exception) { ModLogger.Error("Error logging debug info", exception); } } public FuelSystemStats GetStatistics() { FuelSystemStats fuelSystemStats = new FuelSystemStats(); try { fuelSystemStats.TotalVehicles = _vehicleFuelSystems.Count; foreach (VehicleFuelSystem value in _vehicleFuelSystems.Values) { if ((Object)(object)value != (Object)null && (Object)(object)((Component)value).gameObject != (Object)null) { fuelSystemStats.ActiveVehicles++; if (value.IsEngineRunning) { fuelSystemStats.RunningVehicles++; } if (value.IsOutOfFuel) { fuelSystemStats.EmptyVehicles++; } else if (value.IsCriticalFuel) { fuelSystemStats.CriticalFuelVehicles++; } else if (value.IsLowFuel) { fuelSystemStats.LowFuelVehicles++; } fuelSystemStats.TotalFuelCapacity += value.MaxFuelCapacity; fuelSystemStats.TotalCurrentFuel += value.CurrentFuelLevel; } else { fuelSystemStats.InactiveVehicles++; } } fuelSystemStats.AverageFuelLevel = ((fuelSystemStats.ActiveVehicles > 0) ? (fuelSystemStats.TotalCurrentFuel / (float)fuelSystemStats.ActiveVehicles) : 0f); fuelSystemStats.OverallFuelPercentage = ((fuelSystemStats.TotalFuelCapacity > 0f) ? (fuelSystemStats.TotalCurrentFuel / fuelSystemStats.TotalFuelCapacity * 100f) : 0f); } catch (Exception exception) { ModLogger.Error("Error calculating fuel system statistics", exception); } return fuelSystemStats; } public void Dispose() { try { ModLogger.Debug("FuelSystemManager: Disposing..."); _vehicleFuelSystems.Clear(); _network.Dispose(); ModLogger.Debug("FuelSystemManager: Disposed"); } catch (Exception exception) { ModLogger.Error("Error disposing FuelSystemManager", exception); } } } public class FuelSystemStats { public int TotalVehicles { get; set; } public int ActiveVehicles { get; set; } public int InactiveVehicles { get; set; } public int RunningVehicles { get; set; } public int EmptyVehicles { get; set; } public int CriticalFuelVehicles { get; set; } public int LowFuelVehicles { get; set; } public float TotalFuelCapacity { get; set; } public float TotalCurrentFuel { get; set; } public float AverageFuelLevel { get; set; } public float OverallFuelPercentage { get; set; } } [Serializable] public class FuelVehicleData : VehicleData { public float CurrentFuelLevel; public float MaxFuelCapacity; public float FuelConsumptionRate; public int FuelDataVersion = 1; public FuelVehicleData(Guid guid, string code, Vector3 pos, Quaternion rot, EVehicleColor col, ItemSet vehicleContents, FuelData fuelData) : base(guid, code, pos, rot, col, vehicleContents) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) if (fuelData != null) { CurrentFuelLevel = fuelData.CurrentFuelLevel; MaxFuelCapacity = fuelData.MaxFuelCapacity; FuelConsumptionRate = fuelData.FuelConsumptionRate; } else { CurrentFuelLevel = 50f; MaxFuelCapacity = 50f; FuelConsumptionRate = 6f; } } public FuelData GetFuelData() { return new FuelData { CurrentFuelLevel = CurrentFuelLevel, MaxFuelCapacity = MaxFuelCapacity, FuelConsumptionRate = FuelConsumptionRate }; } public void GetFuelDataValues(out float currentLevel, out float maxCapacity, out float consumptionRate) { currentLevel = CurrentFuelLevel; maxCapacity = MaxFuelCapacity; consumptionRate = FuelConsumptionRate; } public static bool HasFuelData(VehicleData vehicleData) { return vehicleData is FuelVehicleData; } public static FuelData? TryGetFuelData(VehicleData vehicleData) { if (vehicleData is FuelVehicleData fuelVehicleData) { return fuelVehicleData.GetFuelData(); } return null; } public static bool TryGetFuelDataValues(VehicleData vehicleData, out float currentLevel, out float maxCapacity, out float consumptionRate) { if (vehicleData is FuelVehicleData fuelVehicleData) { fuelVehicleData.GetFuelDataValues(out currentLevel, out maxCapacity, out consumptionRate); return true; } currentLevel = 0f; maxCapacity = 0f; consumptionRate = 0f; return false; } public static FuelVehicleData FromVehicleData(VehicleData vehicleData, FuelData fuelData) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) return new FuelVehicleData(new Guid(vehicleData.GUID), vehicleData.VehicleCode, vehicleData.Position, vehicleData.Rotation, Enum.Parse<EVehicleColor>(vehicleData.Color), vehicleData.VehicleContents, fuelData); } } public class VehicleFuelSystem : MonoBehaviour { private float currentFuelLevel = 50f; private float maxFuelCapacity = 50f; private float globalMaxFuelCapacity = 50f; private float baseFuelConsumptionRate = 6f; private float idleConsumptionRate = 0.5f; private float lowFuelThreshold = 30f; private float criticalFuelThreshold = 5f; private LandVehicle? _landVehicle; private string _vehicleGUID = string.Empty; private bool _isEngineRunning = false; private bool _isInVehicle = false; private bool _lowFuelWarningShown = false; private bool _criticalFuelWarningShown = false; private float _lastConsumptionTime = 0f; private VehicleType _vehicleType = VehicleType.Other; public UnityEvent<float> OnFuelLevelChanged = new UnityEvent<float>(); public UnityEvent<float> OnFuelPercentageChanged = new UnityEvent<float>(); public UnityEvent<bool> OnLowFuelWarning = new UnityEvent<bool>(); public UnityEvent<bool> OnCriticalFuelWarning = new UnityEvent<bool>(); public UnityEvent<bool> OnFuelEmpty = new UnityEvent<bool>(); public float CurrentFuelLevel => currentFuelLevel; public float MaxFuelCapacity => maxFuelCapacity; public float GlobalMaxFuelCapacity => globalMaxFuelCapacity; public float FuelPercentage => (maxFuelCapacity > 0f) ? (currentFuelLevel / maxFuelCapacity * 100f) : 0f; public bool IsOutOfFuel => currentFuelLevel <= 0f; public bool IsLowFuel => FuelPercentage <= lowFuelThreshold; public bool IsCriticalFuel => FuelPercentage <= criticalFuelThreshold; public bool IsEngineRunning => _isEngineRunning; public bool IsInVehicle => _isInVehicle; public string VehicleGUID => _vehicleGUID; public string NetworkID { get { LandVehicle? landVehicle = _landVehicle; object obj; if (landVehicle == null) { obj = null; } else { NetworkObject networkObject = ((NetworkBehaviour)landVehicle).NetworkObject; obj = ((networkObject != null) ? networkObject.ObjectId.ToString() : null); } if (obj == null) { obj = _vehicleGUID; } return (string)obj; } } private void Awake() { try { _landVehicle = ((Component)this).GetComponent<LandVehicle>(); if ((Object)(object)_landVehicle == (Object)null) { ModLogger.Error("VehicleFuelSystem: LandVehicle component not found on " + ((Object)((Component)this).gameObject).name); ((Behaviour)this).enabled = false; return; } _vehicleGUID = _landVehicle.GUID.ToString(); if (Core.Instance != null) { SetVehicleType(); baseFuelConsumptionRate = SetBaseFuelConsumption(); globalMaxFuelCapacity = Core.Instance.DefaultFuelCapacity; maxFuelCapacity = SetMaxFuelCapacity(); currentFuelLevel = maxFuelCapacity; idleConsumptionRate = 30f * Core.Instance.FuelConsumptionMultiplier; } ModLogger.FuelDebug("VehicleFuelSystem initialized for " + _landVehicle.VehicleName + " (" + _vehicleGUID.Substring(0, 8) + "...)"); ModLogger.LogVehicleFuel(_landVehicle.VehicleCode, _vehicleGUID, currentFuelLevel, maxFuelCapacity); } catch (Exception exception) { ModLogger.Error("Error in VehicleFuelSystem.Awake", exception); } } private void Start() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown try { if ((Object)(object)_landVehicle != (Object)null) { if (_landVehicle.onVehicleStart != null) { _landVehicle.onVehicleStart.AddListener(new UnityAction(OnVehicleStarted)); } if (_landVehicle.onVehicleStop != null) { _landVehicle.onVehicleStop.AddListener(new UnityAction(OnVehicleStopped)); } } _lastConsumptionTime = Time.time; TriggerFuelLevelChanged(); } catch (Exception exception) { ModLogger.Error("Error in VehicleFuelSystem.Start", exception); } } private void Update() { try { if (_landVehicle.localPlayerIsDriver) { UpdateEngineState(); if (_isEngineRunning) { UpdateFuelConsumption(); } CheckFuelWarnings(); if (IsOutOfFuel && _isEngineRunning) { HandleOutOfFuel(); } } } catch (Exception exception) { ModLogger.Error("Error in VehicleFuelSystem.Update", exception); } } public float SetMaxFuelCapacity() { VehicleType vehicleType = _vehicleType; if (1 == 0) { } float num = vehicleType switch { VehicleType.Shitbox => Core.Instance.ShitboxFuelCapacity, VehicleType.Veeper => Core.Instance.VeeperFuelCapacity, VehicleType.Bruiser => Core.Instance.BruiserFuelCapacity, VehicleType.Dinkler => Core.Instance.DinklerFuelCapacity, VehicleType.Hounddog => Core.Instance.HounddogFuelCapacity, VehicleType.Cheetah => Core.Instance.CheetahFuelCapacity, VehicleType.Hotbox => Core.Instance.HotboxFuelCapacity, VehicleType.Other => Core.Instance.DefaultFuelCapacity, _ => Core.Instance.DefaultFuelCapacity, }; if (1 == 0) { } return maxFuelCapacity = num; } private float SetBaseFuelConsumption() { VehicleType vehicleType = _vehicleType; if (1 == 0) { } float num = vehicleType switch { VehicleType.Shitbox => 288f, VehicleType.Veeper => 360f, VehicleType.Bruiser => 414f, VehicleType.Dinkler => 432.00003f, VehicleType.Hounddog => 377.99997f, VehicleType.Cheetah => 377.99997f, VehicleType.Hotbox => 360f, VehicleType.Other => 360f, _ => 360f, }; if (1 == 0) { } float num2 = num; return num2 * Core.Instance.FuelConsumptionMultiplier; } private void UpdateEngineState() { if ((Object)(object)_landVehicle == (Object)null) { return; } bool isOccupied = _landVehicle.isOccupied; if (isOccupied != _isEngineRunning) { _isEngineRunning = isOccupied; if (_isEngineRunning) { _lastConsumptionTime = Time.time; ModLogger.FuelDebug("Vehicle " + _vehicleGUID.Substring(0, 8) + "... engine started, consumption timer reset"); } ModLogger.FuelDebug($"Vehicle {_vehicleGUID.Substring(0, 8)}... engine state changed: {_isEngineRunning} " + $"(occupied: {_landVehicle.isOccupied}, throttle: {_landVehicle.currentThrottle:F2}, speed: {_landVehicle.speed_Kmh:F1})"); } } private void UpdateFuelConsumption() { if ((Object)(object)_landVehicle == (Object)null || currentFuelLevel <= 0f || !_isEngineRunning) { return; } float num = Time.time - _lastConsumptionTime; _lastConsumptionTime = Time.time; float num2 = Math.Abs(_landVehicle.currentThrottle); float num3 = 0f; if (num2 > 0.01f) { num3 = Mathf.Lerp(idleConsumptionRate, baseFuelConsumptionRate, num2); if (_landVehicle.speed_Kmh > 50f) { float num4 = 1f + (_landVehicle.speed_Kmh - 50f) / 100f; num3 *= num4; } } else if (_landVehicle.isOccupied) { num3 = idleConsumptionRate; } if (num3 > 0f) { float num5 = num3 / 3600f * num; if (num5 > 0.001f && _landVehicle.isOccupied) { ConsumeFuel(num5); } } } private void CheckFuelWarnings() { float fuelPercentage = FuelPercentage; if (fuelPercentage <= criticalFuelThreshold && !_criticalFuelWarningShown) { _criticalFuelWarningShown = true; _lowFuelWarningShown = true; OnCriticalFuelWarning.Invoke(true); ModLogger.LogFuelWarning(_vehicleGUID, currentFuelLevel, "CRITICAL"); } else if (fuelPercentage > criticalFuelThreshold && _criticalFuelWarningShown) { _criticalFuelWarningShown = false; OnCriticalFuelWarning.Invoke(false); } if (fuelPercentage <= lowFuelThreshold && !_lowFuelWarningShown && !_criticalFuelWarningShown) { _lowFuelWarningShown = true; OnLowFuelWarning.Invoke(true); ModLogger.LogFuelWarning(_vehicleGUID, currentFuelLevel, "LOW"); } else if (fuelPercentage > lowFuelThreshold && _lowFuelWarningShown && !_criticalFuelWarningShown) { _lowFuelWarningShown = false; OnLowFuelWarning.Invoke(false); } } private void HandleOutOfFuel() { if (!((Object)(object)_landVehicle == (Object)null)) { ModLogger.LogFuelWarning(_vehicleGUID, 0f, "OUT OF FUEL"); OnFuelEmpty.Invoke(true); } } public void ConsumeFuel(float amount) { if (!(amount <= 0f)) { float num = currentFuelLevel; currentFuelLevel = Math.Max(0f, currentFuelLevel - amount); if (Math.Abs(num - currentFuelLevel) > 0.001f) { ModLogger.LogFuelConsumption(_vehicleGUID, amount, currentFuelLevel); ModLogger.FuelDebug($"Vehicle {_vehicleGUID.Substring(0, 8)}... fuel consumed: {amount:F3}L, " + $"new level: {currentFuelLevel:F2}L ({FuelPercentage:F1}%)"); TriggerFuelLevelChanged(); } } } public float AddFuel(float amount) { if (amount <= 0f) { return 0f; } float num = currentFuelLevel; currentFuelLevel = Math.Min(maxFuelCapacity, currentFuelLevel + amount); float num2 = currentFuelLevel - num; if (num2 > 0f) { ModLogger.FuelDebug($"Vehicle {_vehicleGUID.Substring(0, 8)}... refueled: +{num2:F1}L"); TriggerFuelLevelChanged(); if (FuelPercentage > lowFuelThreshold) { _lowFuelWarningShown = false; _criticalFuelWarningShown = false; OnLowFuelWarning.Invoke(false); OnCriticalFuelWarning.Invoke(false); OnFuelEmpty.Invoke(false); } } return num2; } public float FullTank() { float num = currentFuelLevel; currentFuelLevel = maxFuelCapacity; if (Math.Abs(num - currentFuelLevel) > 0.001f) { ModLogger.FuelDebug($"Vehicle {_vehicleGUID.Substring(0, 8)}... tank filled to {currentFuelLevel:F1}L"); TriggerFuelLevelChanged(); } return currentFuelLevel; } public void SetFuelLevel(float level) { float num = currentFuelLevel; currentFuelLevel = Math.Clamp(level, 0f, maxFuelCapacity); if (Math.Abs(num - currentFuelLevel) > 0.001f) { ModLogger.FuelDebug($"Vehicle {_vehicleGUID.Substring(0, 8)}... fuel level set to {currentFuelLevel:F1}L"); TriggerFuelLevelChanged(); } } public void SetMaxCapacity(float capacity) { maxFuelCapacity = Math.Max(1f, capacity); currentFuelLevel = Math.Min(currentFuelLevel, maxFuelCapacity); TriggerFuelLevelChanged(); } private void TriggerFuelLevelChanged() { OnFuelLevelChanged.Invoke(currentFuelLevel); OnFuelPercentageChanged.Invoke(FuelPercentage); } private void OnVehicleStarted() { ModLogger.FuelDebug("Vehicle " + _vehicleGUID.Substring(0, 8) + "... started"); } private void OnVehicleStopped() { _isEngineRunning = false; ModLogger.FuelDebug("Vehicle " + _vehicleGUID.Substring(0, 8) + "... stopped"); } public FuelData GetFuelData() { return new FuelData { CurrentFuelLevel = currentFuelLevel, MaxFuelCapacity = maxFuelCapacity, FuelConsumptionRate = baseFuelConsumptionRate }; } public void LoadFuelData(FuelData data) { maxFuelCapacity = data.MaxFuelCapacity; currentFuelLevel = data.CurrentFuelLevel; baseFuelConsumptionRate = data.FuelConsumptionRate; TriggerFuelLevelChanged(); ModLogger.FuelDebug("Vehicle " + _vehicleGUID.Substring(0, 8) + "... fuel data loaded"); } public void GetFuelDataValues(out float currentLevel) { currentLevel = currentFuelLevel; } public void LoadFuelDataValues(float currentLevel) { currentFuelLevel = currentLevel; SetBaseFuelConsumption(); maxFuelCapacity = SetMaxFuelCapacity(); TriggerFuelLevelChanged(); ModLogger.FuelDebug("Vehicle " + _vehicleGUID.Substring(0, 8) + "... fuel data loaded"); } private void SetVehicleType() { switch (_landVehicle.vehicleName) { case "Shitbox": _vehicleType = VehicleType.Shitbox; break; case "Veeper": _vehicleType = VehicleType.Veeper; break; case "Bruiser": _vehicleType = VehicleType.Bruiser; break; case "Dinkler": _vehicleType = VehicleType.Dinkler; break; case "Hounddog": _vehicleType = VehicleType.Hounddog; break; case "Cheetah": _vehicleType = VehicleType.Cheetah; break; case "Hotbox": _vehicleType = VehicleType.Hotbox; break; default: _vehicleType = VehicleType.Other; break; } } private void OnDestroy() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown try { if ((Object)(object)_landVehicle != (Object)null) { if (_landVehicle.onVehicleStart != null) { _landVehicle.onVehicleStart.RemoveListener(new UnityAction(OnVehicleStarted)); } if (_landVehicle.onVehicleStop != null) { _landVehicle.onVehicleStop.RemoveListener(new UnityAction(OnVehicleStopped)); } } ModLogger.FuelDebug("VehicleFuelSystem destroyed for vehicle " + _vehicleGUID.Substring(0, 8) + "..."); } catch (Exception exception) { ModLogger.Error("Error in VehicleFuelSystem.OnDestroy", exception); } } } [Serializable] public class FuelData { public float CurrentFuelLevel; public float MaxFuelCapacity; public float FuelConsumptionRate; } public enum VehicleType { Shitbox, Veeper, Bruiser, Dinkler, Hounddog, Cheetah, Hotbox, Other } } namespace S1FuelMod.Networking { internal class FuelNetworkManager : IDisposable { private const int P2P_CHANNEL = 98; private bool _initialized; private bool _disposed; private Callback<P2PSessionRequest_t>? _sessionRequestCb; private Callback<P2PSessionConnectFail_t>? _sessionFailCb; private readonly Dictionary<string, VehicleFuelSystem> _trackedFuelSystems = new Dictionary<string, VehicleFuelSystem>(); private float _lastHeartbeatTime = 0f; private const float HEARTBEAT_INTERVAL = 3f; private readonly Dictionary<string, float> _lastSentLevel = new Dictionary<string, float>(); private readonly Dictionary<string, float> _lastSentTime = new Dictionary<string, float>(); private readonly Dictionary<string, float> _lastNetLevel = new Dictionary<string, float>(); private readonly Dictionary<string, float> _lastNetTime = new Dictionary<string, float>(); private bool _snapshotRequested; private readonly Dictionary<string, PendingFuelData> _pendingSnapshotData = new Dictionary<string, PendingFuelData>(); internal void Initialize() { if (_initialized) { return; } try { if (!SteamAPI.IsSteamRunning()) { ModLogger.Warning("FuelNetwork: Steam not running, deferring init"); return; } if (!SteamManager.Initialized) { ModLogger.Warning("FuelNetwork: SteamManager not initialized, deferring init"); return; } _sessionRequestCb = Callback<P2PSessionRequest_t>.Create((DispatchDelegate<P2PSessionRequest_t>)OnSessionRequest); _sessionFailCb = Callback<P2PSessionConnectFail_t>.Create((DispatchDelegate<P2PSessionConnectFail_t>)OnSessionConnectFail); _initialized = true; ModLogger.Debug("FuelNetwork: Initialized P2P callbacks"); } catch (Exception exception) { ModLogger.Error("FuelNetwork: Initialize failed", exception); } } public void Dispose() { if (!_disposed) { try { _sessionRequestCb?.Dispose(); _sessionFailCb?.Dispose(); _trackedFuelSystems.Clear(); _pendingSnapshotData.Clear(); } catch (Exception exception) { ModLogger.Error("FuelNetwork: Dispose