Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of FPSCounter v1.0.7
FPSCounter.dll
Decompiled 10 months agousing System; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using UnityEngine; 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(FPSCounter), "FPS Counter", "1.0.7", "DiumStream", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: AssemblyMetadata("NexusModID", "737")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyVersion("0.0.0.0")] 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; } } } public class FPSCounter : MelonMod { private GameObject? _uiRoot; private Text? _fpsText; private RectTransform? _bgRect; private float _smoothedFps; private float _currentFps; private readonly char[] _fpsBuffer = new char[8]; private const string FpsPrefix = "FPS: "; public override void OnInitializeMelon() { try { Application.targetFrameRate = -1; Config.Load(); Config.OnSettingsUpdated += OnSettingsUpdateReceived; InitializeUI(); OnSettingsUpdateReceived(); MelonLogger.Msg("FPS Counter initialisé !"); } catch (Exception value) { MelonLogger.Error($"Erreur initialisation: {value}"); } } public override void OnDeinitializeMelon() { Config.OnSettingsUpdated -= OnSettingsUpdateReceived; } private void OnSettingsUpdateReceived() { UpdateUI(); UpdatePosition(); if ((Object)(object)_uiRoot != (Object)null) { _uiRoot.SetActive(Config.Enabled.Value); } } public override void OnPreferencesSaved() { Config.OnPreferencesSaved(); } private void InitializeUI() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Expected O, but got Unknown //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) try { for (int i = 0; i < "FPS: ".Length; i++) { _fpsBuffer[i] = "FPS: "[i]; } _uiRoot = new GameObject("FPS_Canvas"); Canvas val = _uiRoot.AddComponent<Canvas>(); val.renderMode = (RenderMode)0; val.sortingOrder = 9999; CanvasScaler val2 = _uiRoot.AddComponent<CanvasScaler>(); val2.uiScaleMode = (ScaleMode)1; val2.referenceResolution = new Vector2(1920f, 1080f); GameObject val3 = new GameObject("Background"); val3.transform.SetParent(_uiRoot.transform); _bgRect = val3.AddComponent<RectTransform>(); RectTransform? bgRect = _bgRect; Vector2 anchorMin = (_bgRect.anchorMax = new Vector2(0f, 1f)); bgRect.anchorMin = anchorMin; _bgRect.pivot = new Vector2(0.5f, 0.5f); _bgRect.sizeDelta = new Vector2(120f, 40f); Image val5 = val3.AddComponent<Image>(); val5.sprite = MakeRoundedSprite(16); val5.type = (Type)1; ((Graphic)val5).color = new Color(0f, 0f, 0f, 0.7f); GameObject val6 = new GameObject("FPS_Text"); val6.transform.SetParent(val3.transform); RectTransform val7 = val6.AddComponent<RectTransform>(); val7.anchoredPosition = Vector2.zero; anchorMin = (val7.anchorMax = new Vector2(0.5f, 0.5f)); val7.anchorMin = anchorMin; val7.pivot = new Vector2(0.5f, 0.5f); val7.sizeDelta = new Vector2(200f, 50f); _fpsText = val6.AddComponent<Text>(); _fpsText.font = Resources.GetBuiltinResource<Font>("Arial.ttf"); _fpsText.alignment = (TextAnchor)4; ((Graphic)_fpsText).raycastTarget = false; Object.DontDestroyOnLoad((Object)(object)_uiRoot); } catch (Exception ex) { MelonLogger.Error($"Erreur création UI: {ex}\n{ex.StackTrace}"); } } private Sprite MakeRoundedSprite(int radius) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) int num = radius * 2 + 2; Texture2D val = new Texture2D(num, num, (TextureFormat)5, false); Color32 val2 = default(Color32); ((Color32)(ref val2))..ctor((byte)0, (byte)0, (byte)0, (byte)0); Color32 val3 = default(Color32); ((Color32)(ref val3))..ctor(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); for (int i = 0; i < num; i++) { for (int j = 0; j < num; j++) { float num2 = ((j < radius) ? (radius - j) : (j - (num - radius - 1))); float num3 = ((i < radius) ? (radius - i) : (i - (num - radius - 1))); if (num2 < 0f) { num2 = 0f; } if (num3 < 0f) { num3 = 0f; } float num4 = Mathf.Sqrt(num2 * num2 + num3 * num3); val.SetPixel(j, i, Color32.op_Implicit((num4 > (float)radius) ? val2 : val3)); } } val.Apply(); return Sprite.Create(val, new Rect(0f, 0f, (float)num, (float)num), new Vector2(0.5f, 0.5f), 100f, 1u, (SpriteMeshType)0, new Vector4((float)radius, (float)radius, (float)radius, (float)radius)); } private void UpdateUI() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_fpsText == (Object)null) && !((Object)(object)_bgRect == (Object)null)) { _fpsText.fontSize = Config.FontSize.Value; ((Graphic)_fpsText).color = Config.ColorValue.Value; _bgRect.sizeDelta = new Vector2(Mathf.Clamp(_fpsText.preferredWidth + 20f, 100f, 300f), 40f); } } private void UpdatePosition() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_bgRect == (Object)null)) { _bgRect.anchoredPosition = new Vector2(Mathf.Round(Config.FpsPosX.Value) + 100f, Mathf.Round(Config.FpsPosY.Value)); } } public override void OnUpdate() { Application.targetFrameRate = -1; if ((Object)(object)_uiRoot != (Object)null && Config.Enabled.Value && (Object)(object)_fpsText != (Object)null) { _currentFps = 1f / Time.unscaledDeltaTime; _smoothedFps = Mathf.Lerp(_smoothedFps, _currentFps, Config.SmoothingFactor.Value); int num = Mathf.RoundToInt(Mathf.Min(_smoothedFps, 999f)); int length = "FPS: ".Length; if (num >= 100) { _fpsBuffer[length++] = (char)(48 + num / 100); _fpsBuffer[length++] = (char)(48 + num % 100 / 10); _fpsBuffer[length++] = (char)(48 + num % 10); } else if (num >= 10) { _fpsBuffer[length++] = (char)(48 + num / 10); _fpsBuffer[length++] = (char)(48 + num % 10); } else { _fpsBuffer[length++] = (char)(48 + num); } _fpsText.text = new string(_fpsBuffer, 0, length); } } public override void OnSceneWasInitialized(int buildIndex, string sceneName) { if ((Object)(object)_uiRoot == (Object)null) { InitializeUI(); OnSettingsUpdateReceived(); } } } public static class Config { public static MelonPreferences_Category Category { get; private set; } public static MelonPreferences_Entry<Color> ColorValue { get; private set; } public static MelonPreferences_Entry<int> FontSize { get; private set; } public static MelonPreferences_Entry<bool> Enabled { get; private set; } public static MelonPreferences_Entry<float> SmoothingFactor { get; private set; } public static MelonPreferences_Entry<float> FpsPosX { get; private set; } public static MelonPreferences_Entry<float> FpsPosY { get; private set; } public static event Action? OnSettingsUpdated; public static void Load() { try { InitializeCategory(); ConvertLegacyConfig(); ValidateSettings(); MelonLogger.Msg("Configuration chargée avec succès !"); } catch (Exception value) { MelonLogger.Error($"Erreur lors du chargement de la config: {value}"); } } private static void InitializeCategory() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) Category = MelonPreferences.CreateCategory("FPSCounter_Visuals", "Paramètres visuels"); ColorValue = Category.CreateEntry<Color>("ColorValue", Color.white, "Couleur du texte", "Contrôle la couleur RGBA du compteur", false, false, (ValueValidator)null, (string)null); FontSize = Category.CreateEntry<int>("FontSize", 24, "Taille de police", "Taille en pixels du texte", false, false, (ValueValidator)null, (string)null); Enabled = Category.CreateEntry<bool>("Enabled", true, "Activé", "Activer/désactiver le compteur", false, false, (ValueValidator)null, (string)null); SmoothingFactor = Category.CreateEntry<float>("SmoothingFactor", 0.1f, "Lissage", "Fluidité de l'affichage (0.1-1.0)", false, false, (ValueValidator)null, (string)null); FpsPosX = Category.CreateEntry<float>("FpsPosX", -40f, "Position X", "Décalage horizontal", false, false, (ValueValidator)null, (string)null); FpsPosY = Category.CreateEntry<float>("FpsPosY", -20f, "Position Y", "Décalage vertical", false, false, (ValueValidator)null, (string)null); } private static void ConvertLegacyConfig() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) try { MelonPreferences_Entry<string> entry = MelonPreferences.GetEntry<string>("FPSCounter", "TextColorHex"); Color value = default(Color); if (entry != null && ColorUtility.TryParseHtmlString(entry.Value, ref value)) { ColorValue.Value = value; ((MelonPreferences_Entry)entry).IsHidden = true; } MelonPreferences_Entry<string> entry2 = MelonPreferences.GetEntry<string>("FPSCounter", "ColorValue"); if (entry2 != null) { float result; float[] array = (from s in entry2.Value.Trim('[', ']').Split(',') select float.TryParse(s.Trim(), out result) ? result : 255f).ToArray(); if (array.Length >= 4) { ColorValue.Value = new Color(Mathf.Clamp01(array[0] / 255f), Mathf.Clamp01(array[1] / 255f), Mathf.Clamp01(array[2] / 255f), Mathf.Clamp01(array[3] / 255f)); } ((MelonPreferences_Entry)entry2).IsHidden = true; } } catch (Exception ex) { MelonLogger.Warning("Échec de la conversion des anciens paramètres: " + ex.Message); } } public static void OnPreferencesSaved() { ValidateSettings(); Config.OnSettingsUpdated?.Invoke(); } private static void ValidateSettings() { if (SmoothingFactor.Value < 0.1f || SmoothingFactor.Value > 1f) { SmoothingFactor.Value = Mathf.Clamp(SmoothingFactor.Value, 0.1f, 1f); Category.SaveToFile(true); } FpsPosX.Value = Mathf.Clamp(FpsPosX.Value, -1920f, 1920f); FpsPosY.Value = Mathf.Clamp(FpsPosY.Value, -1080f, 1080f); } } public static class PluginInfo { public const string PLUGIN_AUTHOR = "DiumStream"; public const string PLUGIN_NAME = "FPS Counter"; public const string PLUGIN_VERSION = "1.0.7"; }