code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using CheatMenu.Utils;
using CheatMenu.Managers;
using Logger = BepInEx.Logger;
using BepInEx.Logging;
using System.IO;

namespace CheatMenu.Menus
{
    public class MenuDebug : MenuBase
    {
        GUIStyle defaultFontControlHeightButtonStyle;
        GUIStyle labelStyle;
        GUIStyle labelHeaderStyle;
        GUIStyle buttonStyle;

        MenuPrompt promptDumpAll;

        public MenuDebug() : base("Debug", null)
        {
            Alignment = Alignment.TopRight;

            promptDumpAll = new MenuPrompt("Dump All")
            {
                PromptText = "Are you sure you want to dump all scenes?\nThis can take several minutes",
                PromptButtons = { DialogResult.Yes, DialogResult.Cancel },
            };
            promptDumpAll.ButtonClicked += (s, b) =>
            {
                if (b == DialogResult.Yes)
                {
                    MenuManager.HideAll();
                    StateManager.DumpAllScenes();
                }
            };
        }

        protected override Vector2 InitializeSize()
        => new Vector2(GUIManager.ControlWidth + (GUIManager.PaddingSize * 2), (GUIManager.ControlHeight * 2) + (GUIManager.PaddingSize * 2));

        protected override void OnHidden() => promptDumpAll.Shown = false;

        protected override void InitializeGUI()
        {
            defaultFontControlHeightButtonStyle = new GUIStyle(GUI.skin.button)
            {
                fontSize = GUIManager.ControlFontSize,
                fixedHeight = GUIManager.ControlHeight
            };

            labelStyle = new GUIStyle(GUI.skin.label)
            {
                fixedHeight = GUIManager.ControlHeight,
                margin = new RectOffset(0, 0, 0, 0),
                padding = new RectOffset(0, 0, 0, 0),
                fontSize = GUIManager.ControlFontSize,
                normal = new GUIStyleState
                {
                    textColor = GUIManager.LabelColor
                }
            };

            labelHeaderStyle = new GUIStyle(GUI.skin.label)
            {
                fixedHeight = GUIManager.ControlHeight,
                margin = new RectOffset(0, 0, 0, 0),
                padding = new RectOffset(0, 0, 0, 0),
                fontStyle = FontStyle.Bold,
                fontSize = GUIManager.ControlFontSize,
                normal = new GUIStyleState
                {
                    textColor = GUIManager.LabelHeaderColor
                }
            };

            buttonStyle = new GUIStyle(GUI.skin.button)
            {
                fontSize = GUIManager.ControlFontSize,
                margin = new RectOffset(0, 0, 0, 0),
                padding = new RectOffset(0, 0, 0, 0),
                fixedHeight = GUIManager.ControlHeight
            };
        }

        protected override void MenuWindow(int id)
        {
            GUILayout.BeginVertical();
            {
                GUILayout.BeginHorizontal();
                {
                    //GUILayout.Space(GuiManager.DefaultControlWidth);
                    GUILayout.FlexibleSpace();
                    GUILayout.BeginHorizontal(GUI.skin.box);
                    {
                        if (GUILayout.Button("Close", defaultFontControlHeightButtonStyle))
                        {
                            Shown = false;
                        }
                    }
                    GUILayout.EndHorizontal();
                }
                GUILayout.EndHorizontal();

                GUILayout.BeginVertical(GUI.skin.box);
                {
                    GUILayout.BeginVertical(GUI.skin.box);
                    {
                        GUILayout.Label("Scene", labelHeaderStyle);
                        GUILayout.Label(StateManager.LastSceneName, labelStyle);
                    }
                    GUILayout.EndVertical();

                    GUILayout.BeginVertical(GUI.skin.box);
                    {
                        GUILayout.Label("SceneDump", labelHeaderStyle);
                        if (GUILayout.Button("Dump Current", buttonStyle))
                        {
                            SceneUtil.DumpScene();
                            MenuManager.GetMenu<MenuNotifications>().PushNotification($"SceneDump: {StateManager.LastSceneName}", $"{Path.Combine(Application.dataPath, StateManager.LastSceneName + ".dmp")}");
                        }
                        if (GUILayout.Button("Dump All", buttonStyle)) { promptDumpAll.ToggleShown(); }
                    }
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal(GUI.skin.box);
                    {
                        GUILayout.Label("FlowCharts", labelHeaderStyle);
                        GUILayout.FlexibleSpace();
                        GUILayout.Label($"{StateManager.FlowchartCount}", labelStyle);
                    }
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal(GUI.skin.box);
                    {
                        GUILayout.Label("InitCounter", labelHeaderStyle);
                        GUILayout.FlexibleSpace();
                        GUILayout.Label($"{StateManager.InitCounter}", labelStyle);
                    }
                    GUILayout.EndHorizontal();
                }
                GUILayout.EndVertical();
            }
            GUILayout.EndVertical();
        }
    }
}


code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using CheatMenu.Utils;
using CheatMenu.Managers;
using UnityEngine.SceneManagement;

namespace CheatMenu.Menus
{
    public class MenuLoadScene : MenuButtonList
    {
        private readonly string[] blacklistScenes = { "intro01", "house1", "Start", "start_day" };

        public MenuLoadScene() : base("LoadScene", null)
        {
            Alignment = Alignment.Centre;
            HeaderText = "EXPERIMENTAL";

            CommandGroup groupScenes = new CommandGroup("Scenes");
            string[] sceneNames = SceneUtil.GetSceneNames();
            sceneNames = sceneNames.Where((s) => !blacklistScenes.Contains(s)).OrderBy((s) => s).ToArray();
            for (int i = 0; i < sceneNames.Length; i++)
            {
                string sceneName = sceneNames[i];
                groupScenes.AddCommand(sceneName, (c) =>
                {
                    SceneManager.LoadScene(sceneName);
                    Shown = false;
                });
            }
            CommandGroups.Add(groupScenes);
        }

        protected override Vector2 InitializeSize()
        => new Vector2((GUIManager.ControlHeight * 10f) + (GUIManager.PaddingSize * 2) + GUIManager.ScrollBarWidth, (GUIManager.ControlHeight * 15) + (GUIManager.PaddingSize * 2));
    }
}

repo_name: dsconstructor/CheatMenuPlugin

license: mit


code:
using CheatMenu.Managers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using CheatMenu.Utils;
using Logger = BepInEx.Logger;
using BepInEx.Logging;

namespace CheatMenu.Menus
{
    public class MenuNotifications : MenuBase
    {
        private GUIStyle defaultFontLabelStyle;
        private GUIStyle defaultFontLabelHeaderStyle;

        private float beginTime;
        private string headerText;
        private string bodyText;

        public static float ShownTimeout { get; set; } = 10f;

        public MenuNotifications() : base("Notifications")
        {
            ForceGUIEnabled = true;
        }

        protected override Vector2 InitializeSize()
        => new Vector2((GUIManager.ControlWidth) + (GUIManager.PaddingSize * 2), (GUIManager.ControlHeight) + (GUIManager.PaddingSize * 2));

        protected override void InitializeGUI()
        {
            defaultFontLabelStyle = new GUIStyle(GUI.skin.label)
            {
                fontSize = GUIManager.ControlFontSize,
                wordWrap = false,
                normal = new GUIStyleState
                {
                    textColor = GUIManager.LabelColor
                }
            };

            defaultFontLabelHeaderStyle = new GUIStyle(GUI.skin.label)
            {
                fontSize = GUIManager.ControlFontSize,
                wordWrap = false,
                fontStyle = FontStyle.Bold,
                normal = new GUIStyleState
                {
                    textColor = GUIManager.LabelHeaderColor
                }
            };
        }

        protected override void MenuWindow(int id)
        {
            GUILayout.BeginHorizontal();
            {
                GUILayout.BeginVertical(GUI.skin.box);
                {
                    GUILayout.Label(headerText, defaultFontLabelHeaderStyle);
                    GUILayout.Label(bodyText, defaultFontLabelStyle);
                }
                GUILayout.EndVertical();
            }
            GUILayout.EndHorizontal();

            if ((Time.realtimeSinceStartup - beginTime) > ShownTimeout)
                Shown = false;
        }

        public void PushNotification(string header, string body)
        {
            if (StateManager.LastSceneName == "Start")
                WindowOffset = new Vector2(0f, -GUIManager.TopPadding);
            else
                WindowOffset = new Vector2(0f, 0f);

            headerText = header;
            bodyText = body;
            beginTime = Time.realtimeSinceStartup;
            Shown = true;
        }
    }
}


code:
using CheatMenu.Managers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using CheatMenu.Utils;

namespace CheatMenu.Menus
{
    public class MenuPrompt : MenuBase
    {
        public delegate void PromptButtonClickedDelegate(MenuPrompt sender, DialogResult pressedButton);

        public event PromptButtonClickedDelegate ButtonClicked;
        protected void OnButtonClicked(DialogResult pressedButton)
        {
            if (CloseOnButtonClicked)
                Shown = false;

            ButtonClicked?.Invoke(this, pressedButton);
        }

        private GUIStyle defaultFontLabelStyle;
        private GUIStyle defaultFontLabelHeaderStyle;
        private GUIStyle defaultFontControlWidthHeightButtonStyle;

        public string PromptHeader { get; set; }
        public string PromptText { get; set; }
        public readonly List<DialogResult> PromptButtons = new List<DialogResult>();
        public bool CloseOnButtonClicked { get; set; } = true;

        public MenuPrompt(string name, string text = null) : base(name, text)
        {
            Alignment = Alignment.Centre;
        }

        protected override Vector2 InitializeSize()
        => new Vector2((GUIManager.ControlWidth * 3) + (GUIManager.PaddingSize * 2), (GUIManager.ControlHeight * 2) + (GUIManager.PaddingSize * 2));

        protected override void InitializeGUI()
        {
            defaultFontLabelStyle = new GUIStyle(GUI.skin.label)
            {
                fontSize = GUIManager.ControlFontSize,
                normal = new GUIStyleState
                {
                    textColor = GUIManager.LabelColor
                }
            };

            defaultFontLabelHeaderStyle = new GUIStyle(GUI.skin.label)
            {
                fontSize = GUIManager.ControlFontSize,
                fontStyle = FontStyle.Bold,
                normal = new GUIStyleState
                {
                    textColor = GUIManager.LabelHeaderColor
                }
            };

            defaultFontControlWidthHeightButtonStyle = new GUIStyle(GUI.skin.button)
            {
                fontSize = GUIManager.ControlFontSize,
                fixedWidth = GUIManager.ControlWidth,
                fixedHeight = GUIManager.ControlHeight
            };
        }

        protected override void MenuWindow(int id)
        {
            GUILayout.BeginVertical();
            {
                GUILayout.BeginVertical(GUI.skin.box);
                {
                    if (!string.IsNullOrEmpty(PromptHeader)) GUILayout.Label(PromptHeader, defaultFontLabelHeaderStyle);
                    if (!string.IsNullOrEmpty(PromptText)) GUILayout.Label(PromptText, defaultFontLabelStyle);
                }
                GUILayout.EndVertical();

                GUILayout.BeginHorizontal();
                {
                    GUILayout.BeginHorizontal(GUI.skin.box);
                    {
                        for (int i = 0; i < PromptButtons.Count; i++)
                        {
                            if(i > 0)
                                GUILayout.FlexibleSpace();

                            if (GUILayout.Button(Enum.GetName(typeof(DialogResult), PromptButtons[i]), defaultFontControlWidthHeightButtonStyle))
                                OnButtonClicked(PromptButtons[i]);
                        }
                    }
                    GUILayout.EndHorizontal();
                }
                GUILayout.EndHorizontal();
            }
            GUILayout.EndVertical();
        }
    }
}


code:
using CheatMenu.Managers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using CheatMenu.Utils;
using BepInEx.Logging;
using Logger = BepInEx.Logger;

namespace CheatMenu.Menus
{
    public class MenuPromtKeyBind : MenuBase
    {
        public delegate void KeyBoundDelegate(MenuPromtKeyBind sender, KeyCode keyPressed);

        public event KeyBoundDelegate KeyBoundEvent;
        protected void OnKeyBound(KeyCode pressedButton)
        {
            Shown = false;
            KeyBoundEvent?.Invoke(this, pressedButton);
        }

        private GUIStyle defaultFontLabelStyle;
        private GUIStyle defaultFontLabelHeaderStyle;
        private GUIStyle defaultFontControlWidthHeightButtonStyle;

        public string BindName { get; set; }

        public MenuPromtKeyBind(string name, string text = null) : base(name, text)
        {
            Alignment = Alignment.Centre;
        }

        protected override Vector2 InitializeSize()
        => new Vector2((GUIManager.ControlWidth * 3) + (GUIManager.PaddingSize * 2), (GUIManager.ControlHeight * 2) + (GUIManager.PaddingSize * 2));

        protected override void InitializeGUI()
        {
            defaultFontLabelStyle = new GUIStyle(GUI.skin.label)
            {
                fontSize = GUIManager.ControlFontSize,
                normal = new GUIStyleState
                {
                    textColor = GUIManager.LabelColor
                }
            };

            defaultFontLabelHeaderStyle = new GUIStyle(GUI.skin.label)
            {
                fontSize = GUIManager.ControlFontSize,
                fontStyle = FontStyle.Bold,
                normal = new GUIStyleState
                {
                    textColor = GUIManager.LabelHeaderColor
                }
            };

            defaultFontControlWidthHeightButtonStyle = new GUIStyle(GUI.skin.button)
            {
                fontSize = GUIManager.ControlFontSize,
                fixedWidth = GUIManager.ControlWidth,
                fixedHeight = GUIManager.ControlHeight
            };
        }

        protected override void MenuWindow(int id)
        {
            GUILayout.BeginVertical();
            {
                GUILayout.BeginVertical(GUI.skin.box);
                {
                    GUILayout.Label("Hit any key for new keybind:", defaultFontLabelHeaderStyle);
                    if (!string.IsNullOrEmpty(BindName)) GUILayout.Label(BindName, defaultFontLabelStyle);
                }
                GUILayout.EndVertical();
            }
            GUILayout.EndVertical();

            Event e = Event.current;
            if (e.rawType == EventType.KeyDown && e.keyCode != KeyCode.None)
            {
                OnKeyBound(e.keyCode);
            }
        }

        public void PopulateAndShow(string bindName)
        {
            BindName = bindName;
            Focus();
            BringWindowToFront();
            Shown = true;
        }
    }
}


code:
using CheatMenu.Managers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using CheatMenu.Utils;
using BepInEx.Logging;
using Logger = BepInEx.Logger;

namespace CheatMenu.Menus
{
    public class MenuRandomIntegerPicker : MenuButtonList
    {
        public MenuRandomIntegerPicker() : base("RandomInteger Picker")
        {
            Alignment = Alignment.Centre;
            CanClose = false;
        }

        protected override Vector2 InitializeSize()
        => new Vector2((GUIManager.ControlHeight * 8f) + (GUIManager.PaddingSize * 2) + GUIManager.ScrollBarWidth, (GUIManager.ControlHeight * 12) + (GUIManager.PaddingSize * 2));
    }
}


code:
using CheatMenu.Managers;
using CheatMenu.Utils;
using System.Collections.Generic;
using UnityEngine;

namespace CheatMenu.Menus
{
    public class MenuScreenshot : MenuBase
    {
        private GUIStyle defaultFontControlHeightButtonStyle;
        private GUIStyle defaultFontNoWrapLabelHeaderStyle;
        private GUIStyle normalButtonStyle;
        private GUIStyle labelHeaderStyle;

        private int selectedResolutionIndex = 0;
        private float[] resolutionScales = new float[] { 1f, 2f, 4f };
        private bool canTakeScreenshot = true;
        private int selectedImageDataType = 0;
        private ImageDataType[] imageDataTypes = new ImageDataType[] { ImageDataType.JPG, ImageDataType.PNG };

        public MenuScreenshot() : base("Screenshot", null)
        {
            Alignment = Alignment.Centre;
            ScreenshotUtil.ScreenshotSaved += (r) =>
            {
                canTakeScreenshot = true;
                MenuManager.GetMenu<MenuNotifications>().PushNotification("Saved Screenshot:", r.SavePath);
            };
        }

        protected override Vector2 InitializeSize()
        => new Vector2(GUIManager.ControlWidth + (GUIManager.PaddingSize * 2), GUIManager.ControlHeight + (GUIManager.PaddingSize * 2));

        protected override void InitializeGUI()
        {
            defaultFontControlHeightButtonStyle = new GUIStyle(GUI.skin.button)
            {
                fontSize = GUIManager.ControlFontSize,
                fixedHeight = GUIManager.ControlHeight
            };

            defaultFontNoWrapLabelHeaderStyle = new GUIStyle(GUI.skin.label)
            {
                fontSize = GUIManager.ControlFontSize,
                fontStyle = FontStyle.Bold,
                wordWrap = false,
                normal = new GUIStyleState
                {
                    textColor = GUIManager.LabelHeaderColor
                }
            };

            normalButtonStyle = new GUIStyle(GUI.skin.button)
            {
                margin = new RectOffset(0, 0, 0, 0),
                padding = new RectOffset(0, 0, 0, 0),
                fontSize = GUIManager.ControlFontSize,
                fixedHeight = GUIManager.ControlHeight
            };

            labelHeaderStyle = new GUIStyle(GUI.skin.label)
            {
                fixedHeight = GUIManager.ControlHeight,
                margin = new RectOffset(0, 0, 0, 0),
                padding = new RectOffset(0, 0, 0, 0),
                fontStyle = FontStyle.Bold,
                fontSize = GUIManager.ControlFontSize,
                normal = new GUIStyleState
                {
                    textColor = GUIManager.LabelHeaderColor
                }
            };
        }

        protected override void MenuWindow(int id)
        {
            GUILayout.BeginVertical();
            {
                GUILayout.BeginHorizontal();
                {
                    GUILayout.BeginVertical(GUI.skin.box);
                    {
                        GUILayout.Label("EXPERIMENTAL", defaultFontNoWrapLabelHeaderStyle);
                    }
                    GUILayout.EndVertical();
                    GUILayout.FlexibleSpace();
                    GUILayout.BeginHorizontal(GUI.skin.box);
                    {
                        if (GUILayout.Button("Close", defaultFontControlHeightButtonStyle))
                        {
                            Shown = false;
                        }
                    }
                    GUILayout.EndHorizontal();
                }
                GUILayout.EndHorizontal();

                GUILayout.BeginVertical(GUI.skin.box);
                {
                    GUILayout.Label("Resolution", labelHeaderStyle);
                    GUILayout.BeginVertical(GUI.skin.box);
                    {
                        Color oldBackground = GUI.backgroundColor;
                        for (int i = 0; i < resolutionScales.Length; i++)
                        {
                            if (i == selectedResolutionIndex)
                                GUI.backgroundColor = GUIManager.SelectedButtonColor;
                            else
                                GUI.backgroundColor = oldBackground;

                            float rScale = resolutionScales[i];
                            if (GUILayout.Button(string.Format("{0:0}x ({1:0}x{2:0})", rScale, Screen.width * rScale, Screen.height * rScale), normalButtonStyle))
                                selectedResolutionIndex = i;
                        }
                        GUI.backgroundColor = oldBackground;
                    }
                    GUILayout.EndVertical();
                }
                GUILayout.EndVertical();

                GUILayout.BeginVertical(GUI.skin.box);
                {
                    GUILayout.Label("Compression", labelHeaderStyle);
                    GUILayout.BeginHorizontal(GUI.skin.box);
                    {
                        Color oldBackground = GUI.backgroundColor;
                        for (int i = 0; i < imageDataTypes.Length; i++)
                        {
                            ImageDataType type = imageDataTypes[i];
                            if (i == selectedImageDataType)
                                GUI.backgroundColor = GUIManager.SelectedButtonColor;
                            else
                                GUI.backgroundColor = oldBackground;

                            if (GUILayout.Button(imageDataTypes[i].ToString(), normalButtonStyle))
                                selectedImageDataType = i;
                        }
                        GUI.backgroundColor = oldBackground;
                    }
                    GUILayout.EndHorizontal();
                }
                GUILayout.EndVertical();

                bool guiEnabled = GUI.enabled;
                GUI.enabled = canTakeScreenshot && guiEnabled;
                if (GUILayout.Button("Take Screenshot", normalButtonStyle))
                {
                    canTakeScreenshot = false;
                    bool success = ScreenshotUtil.TakeScreenShot(null, resolutionScales[selectedResolutionIndex], imageDataTypes[selectedImageDataType]);
                    if (!success)
                        MenuManager.GetMenu<MenuNotifications>().PushNotification("Failed to take screenshot!", "Yeah, about that...");
                }
                GUI.enabled = guiEnabled;
            }
            GUILayout.EndVertical();
        }
    }
}


code:
using BepInEx.Logging;
using CheatMenu.Managers;
using CheatMenu.Utils;
using Fungus;
using System;
using System.Collections.Generic;
using UnityEngine;
using Logger = BepInEx.Logger;

namespace CheatMenu.Menus
{
    public sealed class MenuStateViewer : MenuBase
    {
        private GUILayoutOption[] stateViewerTypeWidth;
        private GUILayoutOption[] stateViewerEditWidth;
        private GUILayoutOption[] stateViewerNameWidth;
        private GUILayoutOption[] stateViewerValueWidth;

        private GUIStyle defaultFontControlHeightButtonStyle;
        private GUIStyle defaultFontBoxStyle;
        private GUIStyle defaultFontLabelStyle;
        private GUIStyle noPaddingFontBoxStyle;
        private GUIStyle stretchHeightBoxStyle;
        private GUIStyle stretchWidthHeightBoxStyle;
        private GUIStyle labelHeaderStyle;
        private GUIStyle labelTypeStyle;
        private GUIStyle labelEditStyle;
        private GUIStyle labelNameStyle;
        private GUIStyle labelValueStyle;
        private GUIStyle smallButtonStyle;
        private GUIStyle doubleButtonStyle;
        private GUIStyle filterTextFieldStyle;

        private string filterText = "";
        private Vector2 scrollStateViewVector;
        private MenuTextEditor menuTextEditor;

        public MenuStateViewer() : base("StateViewer", null)
        {
            Alignment = Alignment.TopLeft;

            menuTextEditor = new MenuTextEditor("Text Editor");
            menuTextEditor.ButtonClicked += (s, b) =>
            {
                if (b == DialogResult.Apply)
                {
                    if(menuTextEditor.Apply())
                    {
                        MenuManager.GetMenu<MenuNotifications>().PushNotification("Applied value", $"{menuTextEditor.Variable.Key}={menuTextEditor.Result}");
                    }
                    else
                    {
                        MenuManager.GetMenu<MenuNotifications>().PushNotification("Failed to apply value", $"{menuTextEditor.Variable.Key}={menuTextEditor.Result}");
                    }
                }
            };
        }

        public void ResetScrollVector() => scrollStateViewVector = new Vector2();

        protected override Vector2 InitializeSize()
        => new Vector2(GUIManager.ControlWidth + (GUIManager.PaddingSize * 2), -1);

        protected override void OnHidden() => menuTextEditor.Shown = false;

        protected override void InitializeGUI()
        {
            stateViewerTypeWidth = new GUILayoutOption[] { GUILayout.Width((GUIManager.ControlHeight * 2) + GUIManager.PaddingSize), GUILayout.MaxWidth((GUIManager.ControlHeight * 2) + GUIManager.PaddingSize) };
            stateViewerEditWidth = new GUILayoutOption[] { GUILayout.Width(GUIManager.ControlHeight * 2), GUILayout.MaxWidth(GUIManager.ControlHeight * 2) };
            stateViewerNameWidth = new GUILayoutOption[] { GUILayout.Width(GUIManager.ControlWidth), GUILayout.MaxWidth(GUIManager.ControlWidth) };
            stateViewerValueWidth = new GUILayoutOption[] { GUILayout.Width(GUIManager.ControlWidth), GUILayout.MaxWidth(GUIManager.ControlWidth) };

            defaultFontControlHeightButtonStyle = new GUIStyle(GUI.skin.button)
            {
                fontSize = GUIManager.ControlFontSize,
                fixedHeight = GUIManager.ControlHeight
            };

            defaultFontBoxStyle = new GUIStyle(GUI.skin.box)
            {
                fontSize = GUIManager.ControlFontSize
            };

            defaultFontLabelStyle = new GUIStyle(GUI.skin.label)
            {
                fixedHeight = GUIManager.ControlHeight,
                fontSize = GUIManager.ControlFontSize,
                normal = new GUIStyleState
                {
                    textColor = GUIManager.LabelColor
                }
            };

            noPaddingFontBoxStyle = new GUIStyle(GUI.skin.box)
            {
                fontSize = GUIManager.ControlFontSize,
                margin = new RectOffset(0, 0, 0, 0),
                padding = new RectOffset(0, 0, 0, 0),
            };

            stretchHeightBoxStyle = new GUIStyle(GUI.skin.box)
            {
                stretchHeight = true,
            };

            stretchWidthHeightBoxStyle = new GUIStyle(GUI.skin.box)
            {
                stretchWidth = true,
                stretchHeight = true,
            };

            labelTypeStyle = new GUIStyle(GUI.skin.label)
            {
                fixedHeight = GUIManager.ControlHeight,
                fixedWidth = GUIManager.ControlHeight * 2,
                margin = new RectOffset(0, 0, 0, 0),
                padding = new RectOffset(0, 0, 0, 0),
                fontSize = GUIManager.ControlFontSize,
                normal = new GUIStyleState
                {
                    textColor = GUIManager.LabelColor
                }
            };

            labelEditStyle = new GUIStyle(GUI.skin.label)
            {
                fixedHeight = GUIManager.ControlHeight,
                fixedWidth = GUIManager.ControlHeight * 2,
                margin = new RectOffset(0, 0, 0, 0),
                padding = new RectOffset(0, 0, 0, 0),
                fontSize = GUIManager.ControlFontSize,
                normal = new GUIStyleState
                {
                    textColor = GUIManager.LabelColor
                }
            };

            labelNameStyle = new GUIStyle(GUI.skin.label)
            {
                fixedHeight = GUIManager.ControlHeight,
                fixedWidth = GUIManager.ControlWidth,
                margin = new RectOffset(0, 0, 0, 0),
                padding = new RectOffset(0, 0, 0, 0),
                fontSize = GUIManager.ControlFontSize,
                normal = new GUIStyleState
                {
                    textColor = GUIManager.LabelColor
                }
            };

            labelValueStyle = new GUIStyle(GUI.skin.label)
            {
                fixedHeight = GUIManager.ControlHeight,
                margin = new RectOffset(0, 0, 0, 0),
                padding = new RectOffset(0, 0, 0, 0),
                fontSize = GUIManager.ControlFontSize,
                normal = new GUIStyleState
                {
                    textColor = GUIManager.LabelColor
                }
            };

            labelHeaderStyle = new GUIStyle(GUI.skin.label)
            {
                fixedHeight = GUIManager.ControlHeight,
                margin = new RectOffset(0, 0, 0, 0),
                padding = new RectOffset(0, 0, 0, 0),
                fontStyle = FontStyle.Bold,
                fontSize = GUIManager.ControlFontSize,
                normal = new GUIStyleState
                {
                    textColor = GUIManager.LabelHeaderColor
                }
            };

            smallButtonStyle = new GUIStyle(GUI.skin.button)
            {
                fixedHeight = GUIManager.ControlHeight,
                fixedWidth = GUIManager.ControlHeight,
                margin = new RectOffset(0, 0, 0, 0),
                padding = new RectOffset(0, 0, 0, 0),
                fontSize = GUIManager.ControlFontSize
            };

            doubleButtonStyle = new GUIStyle(GUI.skin.button)
            {
                fixedHeight = GUIManager.ControlHeight,
                fixedWidth = GUIManager.ControlHeight * 2,
                margin = new RectOffset(0, 0, 0, 0),
                padding = new RectOffset(0, 0, 0, 0),
                fontSize = GUIManager.ControlFontSize
            };

            filterTextFieldStyle = new GUIStyle(GUI.skin.textField)
            {
                fixedHeight = GUIManager.ControlHeight,
                fixedWidth = GUIManager.ControlWidth,
                fontSize = GUIManager.ControlFontSize
            };
        }

        protected override void MenuWindow(int id)
        {
            GUILayout.BeginVertical();
            {
                GUILayout.BeginHorizontal();
                {
                    GUILayout.BeginHorizontal(GUI.skin.box);
                    {
                        GUILayout.Label("Filter:", defaultFontLabelStyle);
                        filterText = GUILayout.TextField(filterText, filterTextFieldStyle);
                        if (GUILayout.Button("Clear", defaultFontControlHeightButtonStyle)) { filterText = ""; }
                    }
                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal(GUI.skin.box);
                    {
                        if (GUILayout.Button("Close", defaultFontControlHeightButtonStyle)) { Shown = false; }
                    }
                    GUILayout.EndHorizontal();
                }
                GUILayout.EndHorizontal();

                GUILayout.BeginVertical(GUI.skin.box);
                {
                    GUILayout.BeginHorizontal();
                    {
                        GUILayout.Space(1);
                        GUILayout.Label("Type", noPaddingFontBoxStyle, stateViewerTypeWidth);
                        GUILayout.Space(1);
                        GUILayout.Label("Edit", noPaddingFontBoxStyle, stateViewerEditWidth);
                        GUILayout.Space(1);
                        GUILayout.Label("Name", noPaddingFontBoxStyle, stateViewerNameWidth);
                        GUILayout.Space(1);
                        GUILayout.Label("Value", noPaddingFontBoxStyle, stateViewerValueWidth);
                    }
                    GUILayout.EndHorizontal();

                    GUILayout.BeginVertical(stretchHeightBoxStyle);
                    {
                        List<FilteredFlowchart> filtered = StateManager.GetFilteredFlowcharts(filterText);

                        scrollStateViewVector = GUILayout.BeginScrollView(scrollStateViewVector, false, false, GUI.skin.horizontalScrollbar, GUI.skin.verticalScrollbar, stretchWidthHeightBoxStyle);
                        for (int i = 0; i < filtered.Count; i++)
                            DrawStateChart(filtered[i]);

                        GUILayout.EndScrollView();

                        //Hacky workaround for the ScrollView not taking mouse scrollwheel focus
                        if (GUIUtil.MouseScrollingAndContained(WindowRect))
                            Input.ResetInputAxes();
                    }
                    GUILayout.EndVertical();
                }
                GUILayout.EndVertical();
            }
            GUILayout.EndVertical();
        }

        private void DrawStateChart(FilteredFlowchart filtered)
        {
            GUILayout.Label(string.Format("FC:{0}", filtered.Flowchart.name), labelHeaderStyle);
            for (int i = 0; i < filtered.Variables.Count; i++)
                DrawStateEntry(filtered.Flowchart, filtered.Variables[i]);
        }

        private void DrawStateEntry(Flowchart chart, Variable variable)
        {
            Type type = variable.GetType();
            if (type == typeof(BooleanVariable))
            {
                BooleanVariable booleanVariable = (BooleanVariable)variable;
                GUILayout.BeginHorizontal();
                {
                    GUILayout.Label("Bool", labelTypeStyle);
                    if (GUILayout.Button(booleanVariable.Value ? "true" : "false", doubleButtonStyle))
                    {
                        booleanVariable.Value = !booleanVariable.Value;
                        //chart.SetBooleanVariable(variable.Key, booleanVariable.Value);
                        PlayerPrefs.SetInt(SetSaveProfile.SaveProfile + "_" + chart.SubstituteVariables(variable.Key), booleanVariable.Value ? 1 : 0);
                    }
                    GUILayout.Space(1);
                    GUILayout.Label(variable.Key, labelNameStyle);
                    GUILayout.Space(1);
                    GUILayout.Label(booleanVariable.Value.ToString(), labelValueStyle, GUILayout.ExpandWidth(true));
                }
                GUILayout.EndHorizontal();
                return;
            }
            if (type == typeof(IntegerVariable))
            {
                IntegerVariable integerVariable = (IntegerVariable)variable;
                GUILayout.BeginHorizontal();
                {
                    GUILayout.Label("Int", labelTypeStyle);
                    bool hitPlus = GUILayout.Button("+", smallButtonStyle);
                    bool hitMinus = GUILayout.Button("-", smallButtonStyle);
                    if (hitPlus || hitMinus)
                    {
                        int addValue = GetIntFromModifierKeys(hitPlus);
                        Logger.Log(LogLevel.Info, $"Add/Subtract To Int: {addValue}");
                        integerVariable.Value += addValue;
                        //chart.SetIntegerVariable(variable.Key, integerVariable.Value);
                        PlayerPrefs.SetInt(SetSaveProfile.SaveProfile + "_" + chart.SubstituteVariables(variable.Key), integerVariable.Value);
                    }
                    GUILayout.Space(1);
                    GUILayout.Label(variable.Key, labelNameStyle);
                    GUILayout.Space(1);
                    GUILayout.Label(integerVariable.Value.ToString(), labelValueStyle, GUILayout.ExpandWidth(true));
                }
                GUILayout.EndHorizontal();
                return;
            }
            if (type == typeof(StringVariable))
            {
                StringVariable stringVariable = (StringVariable)variable;
                GUILayout.BeginHorizontal();
                {
                    GUILayout.Label("Str", labelTypeStyle);
                    if (GUILayout.Button("Edit", doubleButtonStyle))
                    {
                        menuTextEditor.Populate(chart, stringVariable);
                        menuTextEditor.Shown = true;
                    }
                    GUILayout.Space(1);
                    GUILayout.Label(variable.Key, labelNameStyle);
                    GUILayout.Space(1);
                    GUILayout.Label(stringVariable.Value, labelValueStyle, GUILayout.ExpandWidth(true));
                }
                GUILayout.EndHorizontal();
                return;
            }
            if (type == typeof(FloatVariable))
            {
                FloatVariable floatVariable = (FloatVariable)variable;
                GUILayout.BeginHorizontal();
                {
                    GUILayout.Label("Float", labelTypeStyle);
                    bool hitPlus = GUILayout.Button("+", smallButtonStyle);
                    bool hitMinus = GUILayout.Button("-", smallButtonStyle);
                    if (hitPlus || hitMinus)
                    {
                        floatVariable.Value += GetFloatFromModifierKeys(hitPlus);
                        //chart.SetFloatVariable(variable.Key, floatVariable.Value);
                        PlayerPrefs.SetFloat(SetSaveProfile.SaveProfile + "_" + chart.SubstituteVariables(variable.Key), floatVariable.Value);
                    }
                    GUILayout.Space(1);
                    GUILayout.Label(variable.Key, labelNameStyle);
                    GUILayout.Space(1);
                    GUILayout.Label($"{floatVariable.Value:0.00}", labelValueStyle, GUILayout.ExpandWidth(true));
                }
                GUILayout.EndHorizontal();
                return;
            }
            GUILayout.BeginHorizontal();
            {
                GUILayout.Label($"{type.Name.Replace("Variable", "")}", labelTypeStyle);
                GUILayout.Label(GUIContent.none, labelEditStyle);//Placeholder
                GUILayout.Space(1);
                GUILayout.Label(variable.Key, labelNameStyle);
                GUILayout.Space(1);
                GUILayout.Label(variable.ToString(), labelValueStyle, GUILayout.ExpandWidth(true));
            }
            GUILayout.EndHorizontal();
        }

        private int GetIntFromModifierKeys(bool positive)
        {
            bool shiftDown = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
            bool ctrlDown = Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl);
            int result = shiftDown ? (ctrlDown ? 100 : 10) : 1;
            return positive ? result : -result;
        }

        private float GetFloatFromModifierKeys(bool positive)
        {
            bool shiftDown = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
            bool ctrlDown = Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl);
            float result = shiftDown ? (ctrlDown ? 1f : 0.1f) : 0.05f;
            return positive ? result : -result;
        }
    }
}


code:
using CheatMenu.Managers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using CheatMenu.Utils;
using Fungus;

namespace CheatMenu.Menus
{
    public class MenuTextEditor : MenuBase
    {
        public delegate void TextEditorButtonClickedDelegate(MenuTextEditor sender, DialogResult pressedButton);

        public event TextEditorButtonClickedDelegate ButtonClicked;
        protected void OnButtonClicked(DialogResult pressedButton)
        {
            Shown = false;
            ButtonClicked?.Invoke(this, pressedButton);
        }

        private GUIStyle defaultFontLabelStyle;
        private GUIStyle defaultFontLabelHeaderStyle;
        private GUIStyle defaultFontControlWidthHeightButtonStyle;
        private GUIStyle defaultTextFieldStyle;

        public string PromptText { get; set; }
        public string Result { get; set; }
        public StringVariable Variable { get; set; }
        public Flowchart Chart { get; set; }

        public MenuTextEditor(string name, string text = null) : base(name, text)
        {
            Alignment = Alignment.Centre;
        }

        protected override Vector2 InitializeSize()
        => new Vector2((GUIManager.ControlWidth * 3) + (GUIManager.PaddingSize * 2), (GUIManager.ControlHeight * 2) + (GUIManager.PaddingSize * 2));

        protected override void InitializeGUI()
        {
            defaultFontLabelStyle = new GUIStyle(GUI.skin.label)
            {
                fontSize = GUIManager.ControlFontSize,
                normal = new GUIStyleState
                {
                    textColor = GUIManager.LabelColor
                }
            };

            defaultFontLabelHeaderStyle = new GUIStyle(GUI.skin.label)
            {
                fontSize = GUIManager.ControlFontSize,
                fontStyle = FontStyle.Bold,
                normal = new GUIStyleState
                {
                    textColor = GUIManager.LabelHeaderColor
                }
            };

            defaultFontControlWidthHeightButtonStyle = new GUIStyle(GUI.skin.button)
            {
                fontSize = GUIManager.ControlFontSize,
                fixedWidth = GUIManager.ControlWidth,
                fixedHeight = GUIManager.ControlHeight
            };

            defaultTextFieldStyle = new GUIStyle(GUI.skin.textField)
            {
                fontSize = GUIManager.ControlFontSize,
                fixedWidth = GUIManager.ControlWidthTimesTwo,
            };
        }

        public bool Apply()
        {
            bool success = false;

            if(Variable != null && Chart != null)
            {
                Variable.Value = Result;
                Chart.SetStringVariable(Variable.Key, Variable.Value);
                PlayerPrefs.SetString(SetSaveProfile.SaveProfile + "_" + Chart.SubstituteVariables(Variable.Key), Variable.Value);
                success = true;
            }

            return success;
        }

        public void Populate(Flowchart chart, StringVariable stringVariable)
        {
            Chart = chart;
            Variable = stringVariable;
            PromptText = stringVariable.Key;
            Result = stringVariable.Value;
        }

        protected override void MenuWindow(int id)
        {
            GUILayout.BeginVertical();
            {
                GUILayout.BeginVertical(GUI.skin.box);
                {
                    GUILayout.Label("Edit Variable:", defaultFontLabelHeaderStyle);
                    GUILayout.Label(PromptText, defaultFontLabelStyle);
                }
                GUILayout.EndVertical();

                GUILayout.BeginHorizontal();
                {
                    GUILayout.Label("New Value:", defaultFontLabelStyle);
                    GUILayout.FlexibleSpace();
                    Result = GUILayout.TextField(Result, defaultTextFieldStyle);
                }
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();
                {
                    GUILayout.BeginHorizontal(GUI.skin.box);
                    {
                        if (GUILayout.Button(Enum.GetName(typeof(DialogResult), DialogResult.Apply), defaultFontControlWidthHeightButtonStyle))
                            OnButtonClicked(DialogResult.Apply);
                        GUILayout.FlexibleSpace();
                        if (GUILayout.Button(Enum.GetName(typeof(DialogResult), DialogResult.Cancel), defaultFontControlWidthHeightButtonStyle))
                            OnButtonClicked(DialogResult.Cancel);
                    }
                    GUILayout.EndHorizontal();
                }
                GUILayout.EndHorizontal();
            }
            GUILayout.EndVertical();
        }
    }
}


code:
using CheatMenu.Utils;
using Fungus;
using Harmony;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace CheatMenu.Patch
{
    public class InstantTextPatcher
    {
        public static bool Enabled { get; set; }

        public static void Patch(HarmonyInstance harmony)
        {
            BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
            var original = typeof(Writer).GetMethod("ProcessTokens", bindingFlags);
            var prefix = typeof(InstantTextPatcher).GetMethod("prefix_ProcessTokens");
            harmony.Patch(original, new HarmonyMethod(prefix), null);
        }

        public static void prefix_ProcessTokens(Writer __instance)
        {
            if (Enabled)
            {
                ReflectionUtil.SetPunctiationPauseOfWriter(__instance, 0f);
                ReflectionUtil.SetWritingSpeedOfWriter(__instance, 0f);
            }
        }
    }
}


code:
using Fungus;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CheatMenu.Patch
{
    public class RandomIntegerPatchState
    {
        public int Min { get; private set; }
        public int Max { get; private set; }
        public string VariableKey { get; private set; }
        public string BlockName { get; private set; }

        public RandomIntegerPatchState(int min, int max, string variableKey, string blockName)
        {
            Min = min;
            Max = max;
            VariableKey = variableKey;
            BlockName = blockName;
        }
    }
}


code:
using Fungus;
using Harmony;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Logger = BepInEx.Logger;
using BepInEx.Logging;
using CheatMenu.Utils;
using CheatMenu.Menus;
using CheatMenu.Managers;

namespace CheatMenu.Patch
{
    public static class RandomIntegerPatcher
    {
        public static bool Enabled { get; set; } = false;

        static RandomInteger lastInstance;
        static Lazy<MenuRandomIntegerPicker> RandomIntegerPickerMenu = new Lazy<MenuRandomIntegerPicker>(() => MenuManager.GetMenu<MenuRandomIntegerPicker>());

        public static void Patch(HarmonyInstance harmony)
        {
            var original = typeof(RandomInteger).GetMethod("OnEnter");
            var prefix = typeof(RandomIntegerPatcher).GetMethod("prefix_OnEnter");
            var postfix = typeof(RandomIntegerPatcher).GetMethod("postfix_OnEnter");
            harmony.Patch(original, new HarmonyMethod(prefix), new HarmonyMethod(postfix));
        }

        public static void prefix_OnEnter(RandomInteger __instance, ref RandomIntegerPatchState __state)
        {
            if (Enabled)
            {
                IntegerVariable variable = ReflectionUtil.GetVariableFromRandomInteger(__instance);
                if (variable != null)
                {
                    IntegerData min = ReflectionUtil.GetMinValueFromRandomInteger(__instance);
                    IntegerData max = ReflectionUtil.GetMaxValueFromRandomInteger(__instance);
                    __state = new RandomIntegerPatchState(min.Value, max.Value, variable.Key, __instance.ParentBlock?.BlockName);
                    __instance.IsExecuting = false;
                    Logger.Log(LogLevel.Info, $"RandomInteger - Prompting for Value..");
                }
            }
        }

        public static void postfix_OnEnter(RandomInteger __instance, RandomIntegerPatchState __state)
        {
            if (__state != null)
            {
                var menu = RandomIntegerPickerMenu.Value;
                menu.ResetScrollVector();
                menu.ClearCommandGroups();
                menu.HeaderText = $"Block: {__state.BlockName ?? "NULL"}";
                CommandGroup commandGroup = new CommandGroup($"Variable: {__state.VariableKey}");
                for (int i = __state.Min; i < __state.Max; i++)
                {
                    commandGroup.AddCommand(i.ToString(), HandleValueSelected);
                }
                menu.AddCommandGroup(commandGroup);

                lastInstance = __instance;
                menu.Shown = true;
                FungusManager.Instance.CameraManager.Fade(0f, 1f, null);
            }
        }

        private static void HandleValueSelected(Utils.Command command)
        {
            RandomIntegerPickerMenu.Value.Shown = false;
            IntegerVariable variable = ReflectionUtil.GetVariableFromRandomInteger(lastInstance);
            if (int.TryParse(command.Name, out int outValue) && variable != null)
            {
                Logger.Log(LogLevel.Info, $"RandomInteger - Selected Value: {outValue}");
                variable.Value = outValue;
            }
            lastInstance.IsExecuting = true;
            lastInstance.Continue();
        }
    }
}


code:
using System.Reflection;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("CheatMenu")]
[assembly: AssemblyDescription("CheatMenu for The Twist")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("dsconstructor")]
[assembly: AssemblyProduct("CheatMenu")]
[assembly: AssemblyCopyright("Copyright ©  2019")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components.  If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
//[assembly: Guid("a66a97b4-f32f-4748-8332-48f0876f0aac")]

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion(CheatMenu.CheatMenuPlugin.Version)]


code:
namespace CheatMenu.Utils
{
    public enum Alignment
    {
        None,
        TopLeft,
        TopCentre,
        TopRight,
        Right,
        BottomRight,
        BottomCentre,
        BottomLeft,
        Left,
        Centre
    }
}


code:
using System;

namespace CheatMenu.Utils
{
    public class Command
    {
        public string Name { get; set; }
        public Action<Command> Action { get; set; }
        public bool ToggleState { get; set; }

        public Command(string name, Action<Command> action, bool toggleState = false)
        {
            Name = name;
            Action = action;
            ToggleState = toggleState;
        }

        public void InvokeCommand()
        {
            Action?.Invoke(this);
        }
    }
}


code:
using System;
using System.Collections.Generic;
using System.Linq;
using Logger = BepInEx.Logger;
using BepInEx.Logging;

namespace CheatMenu.Utils
{
    public class CommandGroup
    {
        public string Name { get; set; }
        public List<Command> Commands { get; private set; } = new List<Command>();

        public CommandGroup(string name)
        {
            Name = name;
        }

        public void ClearCommands()
        {
            Commands.Clear();
        }

        public void AddCommand(string name, Action<Command> action, bool toggleState = false)
        {
            if (Commands.Where((c) => c.Name.Equals(name, StringComparison.OrdinalIgnoreCase)).Count() == 0)
                Commands.Add(new Command(name, action, toggleState));
            else
                Logger.Log(LogLevel.Warning, $"Trying to add existing command with name: {name}");
        }

        public void RemoveCommand(string name)
        {
            var existingCommand = Commands.Where((c) => c.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
            if (existingCommand.Count() == 1)
                Commands.Remove(existingCommand.First());
            else
                Logger.Log(LogLevel.Warning, $"Trying to remove non-existing command with name: {name}");
        }
    }
}


code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CheatMenu.Utils
{
    public enum DialogResult
    {
        Yes,
        No,
        Apply,
        Cancel,
    }
}


code:
namespace CheatMenu.Utils
{
    public enum FilterInputType
    {
        Name,
        Types
    }
}


code:
using Fungus;
using System.Collections.Generic;

namespace CheatMenu.Utils
{
    public class FilteredFlowchart
    {
        public Flowchart Flowchart { get; private set; }
        public List<Variable> Variables { get; private set; }

        public FilteredFlowchart(Flowchart flowchart, List<Variable> variables)
        {
            Flowchart = flowchart;
            Variables = variables;
        }
    }
}


code:
using UnityEngine;

namespace CheatMenu.Utils
{
    public static class GUIUtil
    {
        private static Texture2D backgroundTexture;

        public static Color BackgroundTintColor { get; set; } = new Color(1f, 1f, 1f, 1f);

        private static Color backgroundColor = new Color(0.6f, 0.6f, 0.6f, 1f);
        public static Color BackgroundColor
        {
            get => backgroundColor;
            set
            {
                backgroundColor = value;
                backgroundTexture = null;
            }
        }

        public static void DrawRoundedRectangle(Rect windowRect, float radius = 10f)
        {
            if (backgroundTexture == null)
                backgroundTexture = CreateColorTexture(backgroundColor);

            GUI.DrawTexture(windowRect, backgroundTexture, ScaleMode.StretchToFill, false, 0f, BackgroundTintColor, 0f, radius);
        }

        private static Texture2D CreateColorTexture(Color color)
        {
            Texture2D result = new Texture2D(1, 1, TextureFormat.RGBA32, false);
            result.SetPixel(0, 0, color);
            result.Apply();

            return result;
        }

        public static bool MouseScrollingAndContained(Rect windowRect)
        {
            var mouseScreenSpace = Input.mousePosition;
            mouseScreenSpace.y = Screen.height - mouseScreenSpace.y;
            return Input.GetAxis("Mouse ScrollWheel") != 0 && windowRect.Contains(mouseScreenSpace);
        }

        //AlignRect takes a width and a height returned a rect snapped to the edge of the screen as defined by the alignment
        //If you want a different rect than the screen, use the parameter parentRect
        //You can adjust the result position with xOffset and yOffset
        public static Rect AlignRect(float width, float height, Alignment alignment)
        => AlignRect(width, height, new Rect(0, 0, Screen.width, Screen.height), alignment, 0f, 0f);
        public static Rect AlignRect(float width, float height, Alignment alignment, float xOffset, float yOffset)
        => AlignRect(width, height, new Rect(0, 0, Screen.width, Screen.height), alignment, xOffset, yOffset);
        public static Rect AlignRect(float width, float height, Rect parentRect, Alignment alignment)
        => AlignRect(width, height, parentRect, alignment, 0f, 0f);

        public static Rect AlignRect(float width, float height, Rect parentRect, Alignment alignment, float xOffset, float yOffset)
        {
            Rect oRect;

            switch (alignment)
            {
                case Alignment.TopLeft:
                    oRect = new Rect(0f, 0f, width, height);
                    break;
                case Alignment.TopRight:
                    oRect = new Rect(parentRect.width - width, 0f, width, height);
                    break;
                case Alignment.TopCentre:
                    oRect = new Rect(parentRect.width * 0.5F - width * 0.5F, 0f, width, height);
                    break;
                case Alignment.Centre:
                    oRect = new Rect(parentRect.width * 0.5F - width * 0.5F, parentRect.height * 0.5F - height * 0.5F, width, height);
                    break;
                case Alignment.Right:
                    oRect = new Rect(parentRect.width - width, parentRect.height * 0.5F - height * 0.5F, width, height);
                    break;
                case Alignment.BottomRight:
                    oRect = new Rect(parentRect.width - width, parentRect.height - height, width, height);
                    break;
                case Alignment.BottomCentre:
                    oRect = new Rect(parentRect.width * 0.5F - width * 0.5F, parentRect.height - height, width, height);
                    break;
                case Alignment.BottomLeft:
                    oRect = new Rect(0f, parentRect.y + parentRect.height - height, width, height);
                    break;
                case Alignment.Left:
                    oRect = new Rect(0f, parentRect.height * 0.5F - height * 0.5F, width, height);
                    break;
                case Alignment.None:
                default:
                    oRect = new Rect(0f, 0f, width, height);
                    break;
            }

            oRect.x += parentRect.x + xOffset;
            oRect.y += parentRect.y + yOffset;
            return oRect;
        }

        // Rect extensions
        // Reduce the size of the rect from the center
        public static Rect Shrink(this Rect r, float nbPixels) => r.Shrink(nbPixels, nbPixels);
        public static Rect Shrink(this Rect r, float nbPixelX, float nbPixelY)
        {
            return new Rect(r.x + nbPixelX, r.y + nbPixelY, r.width - nbPixelX * 2f, r.height - nbPixelY * 2f);
        }

        // Enhance the size of the rect from the center
        public static Rect Grow(this Rect r, float nbPixels) => r.Shrink(-nbPixels, -nbPixels);
        public static Rect Grow(this Rect r, float nbPixelX, float nbPixelY) { return r.Shrink(-nbPixelX, -nbPixelY); }

        // Make sure the rect is contained inside another rect. It's size isn't changed.
        public static Rect ClampPosition(this Rect r, Rect borderRect)
        {
            return new Rect(Mathf.Clamp(r.x, borderRect.x, borderRect.x + borderRect.width - r.width),
                            Mathf.Clamp(r.y, borderRect.y, borderRect.y + borderRect.height - r.height),
                            r.width, r.height);
        }

        // Translate the rect
        public static Rect MoveX(this Rect r, float xMovement) => r.Move(xMovement, 0f);
        public static Rect MoveY(this Rect r, float yMovement) => r.Move(0f, yMovement);
        public static Rect Move(this Rect r, Vector2 movement) => r.Move(movement.x, movement.y);
        public static Rect Move(this Rect r, float xMovement, float yMovement)
        {
            return new Rect(r.x + xMovement, r.y + yMovement, r.width, r.height);
        }

        // Return the rect relatively to another one, like a groupe would do.
        public static Rect RelativeTo(this Rect r, Rect to)
        {
            return new Rect(r.x - to.x, r.y - to.y, r.width, r.height);
        }

        // Return the rect as one level of group higher.
        public static Rect InverseTransform(this Rect r, Rect from)
        {
            return new Rect(r.x + from.x, r.y + from.y, r.width, r.height);
        }

        // Quick access to the screen rect
        public static Rect ScreenRect { get { return new Rect(0f, 0f, Screen.width, Screen.height); } }

        // MOUSE FUNCTIONS
        // Easy access to the gui mouse pos
        public static Vector2 MousePos { get { return Event.current.mousePosition; } }
        // gui mouse pos with the y inverted
        public static Vector2 MousePosInvertY { get => FlipY(MousePos); }
        public static Vector2 FlipY(Vector2 inPos) { inPos.y = Screen.height - inPos.y; return inPos; }
        public static Vector2 MouseRelativePos(Rect rect) => RelativePos(rect, MousePos.x, MousePos.y);
        // Give the inPos relative to the input rect
        public static Vector2 RelativePos(Rect rect, Vector2 inPos) => RelativePos(rect, inPos.x, inPos.y);
        public static Vector2 RelativePos(Rect rect, Vector3 inPos) => RelativePos(rect, inPos.x, inPos.y);
        public static Vector2 RelativePos(Rect rect, float x, float y) => new Vector2(x - rect.x, y - rect.y);
        // Give the inPos as one group higher
        public static Vector2 InverseTransformPoint(Rect rect, Vector3 inPos)
        {
            return new Vector2(rect.x + inPos.x, rect.y + inPos.y);
        }

        // GUI Event extensions
        // Checks for Key Down / Up event of a certain key
        public static bool GetKeyDown(this Event aEvent, KeyCode aKey)
        {
            return (aEvent.type == EventType.KeyDown && aEvent.keyCode == aKey);
        }
        public static bool GetKeyUp(this Event aEvent, KeyCode aKey)
        {
            return (aEvent.type == EventType.KeyUp && aEvent.keyCode == aKey);
        }

        // Checks for mouse Down / Up event of a certain mouse button
        public static bool GetMouseDown(this Event aEvent, int aButton)
        {
            return (aEvent.type == EventType.MouseDown && aEvent.button == aButton);
        }
        public static bool GetMouseUp(this Event aEvent, int aButton)
        {
            return (aEvent.type == EventType.MouseUp && aEvent.button == aButton);
        }

        // Checks for mouse Down / Up event of a certain mouse button inside the given Rect
        public static bool GetMouseDown(this Event aEvent, int aButton, Rect aRect)
        {
            return (aEvent.type == EventType.MouseDown && aEvent.button == aButton && aRect.Contains(aEvent.mousePosition));
        }
        public static bool GetMouseUp(this Event aEvent, int aButton, Rect aRect)
        {
            return (aEvent.type == EventType.MouseUp && aEvent.button == aButton && aRect.Contains(aEvent.mousePosition));
        }
    }
}


code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CheatMenu.Utils
{
    public class Lazy<T>
    {
        private readonly Func<T> initializer;
        private T value;

        public bool IsValueCreated { get; private set; }

        public Lazy(Func<T> initializer)
        {
            this.initializer = initializer ?? throw new ArgumentNullException("initializer");
        }

        public T Value
        {
            get
            {
                if (!IsValueCreated)
                {
                    value = initializer();
                    IsValueCreated = true;
                }
                return value;
            }
        }
    }
}


code:
using CheatMenu.Menus;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

namespace CheatMenu.Utils
{
    public class Notification
    {
        public float BeginTime;
        public string HeaderText;
        public string BodyText;
        private bool firstUpdate = true;

        public Notification(string header, string body)
        {
            HeaderText = header;
            BodyText = body;
        }

        public bool UpdateAndCheckIfDone()
        {
            if (firstUpdate)
            {
                firstUpdate = false;
                BeginTime = Time.realtimeSinceStartup;
            }

            return  (Time.realtimeSinceStartup - BeginTime) > MenuNotifications.ShownTimeout;
        }
    }
}


code:
using Fungus;
using System;
using System.Reflection;
using System.Reflection.Emit;
using UnityEngine.Events;

namespace CheatMenu.Utils
{
    public static class ReflectionUtil
    {
        //Slow reflection
        //public static T GetField<T>(object instance, string fieldName)
        //{
        //    return (T)instance.GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance).GetValue(instance);
        //}

        //Fast reflection (up to 500 times faster, after delegate has been created)
        public static Func<S, T> CreateGetter<S, T>(string fieldName)
        {
            FieldInfo field = typeof(S).GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
            string methodName = field.ReflectedType.FullName + ".get_" + field.Name;
            DynamicMethod setterMethod = new DynamicMethod(methodName, typeof(T), new Type[1] { typeof(S) }, true);
            ILGenerator gen = setterMethod.GetILGenerator();
            if (field.IsStatic)
            {
                gen.Emit(OpCodes.Ldsfld, field);
            }
            else
            {
                gen.Emit(OpCodes.Ldarg_0);
                gen.Emit(OpCodes.Ldfld, field);
            }
            gen.Emit(OpCodes.Ret);
            return (Func<S, T>)setterMethod.CreateDelegate(typeof(Func<S, T>));
        }

        public static Action<S, T> CreateSetter<S, T>(string fieldName)
        {
            FieldInfo field = typeof(S).GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
            string methodName = field.ReflectedType.FullName + ".set_" + field.Name;
            DynamicMethod setterMethod = new DynamicMethod(methodName, null, new Type[2] { typeof(S), typeof(T) }, true);
            ILGenerator gen = setterMethod.GetILGenerator();
            if (field.IsStatic)
            {
                gen.Emit(OpCodes.Ldarg_1);
                gen.Emit(OpCodes.Stsfld, field);
            }
            else
            {
                gen.Emit(OpCodes.Ldarg_0);
                gen.Emit(OpCodes.Ldarg_1);
                gen.Emit(OpCodes.Stfld, field);
            }
            gen.Emit(OpCodes.Ret);
            return (Action<S, T>)setterMethod.CreateDelegate(typeof(Action<S, T>));
        }

        //================================================================
        //InvokeEvent
        //================================================================
        //InvokeEvent->invokeType InvokeType
        private static Func<InvokeEvent, InvokeType> invokeTypeFromInvokeEvent;
        public static InvokeType GetInvokeTypeFromInvokeEvent(InvokeEvent condition)
        {
            if (invokeTypeFromInvokeEvent == null)
                invokeTypeFromInvokeEvent = CreateGetter<InvokeEvent, InvokeType>("invokeType");

            return invokeTypeFromInvokeEvent(condition);
        }

        //InvokeEvent->staticEvent UnityEvent
        private static Func<InvokeEvent, UnityEvent> staticEventFromInvokeEvent;
        public static UnityEvent GetStaticEventFromInvokeEvent(InvokeEvent condition)
        {
            if (staticEventFromInvokeEvent == null)
                staticEventFromInvokeEvent = CreateGetter<InvokeEvent, UnityEvent>("staticEvent");

            return staticEventFromInvokeEvent(condition);
        }

        //InvokeEvent->booleanEvent BooleanEvent
        private static Func<InvokeEvent, InvokeEvent.BooleanEvent> booleanEventFromInvokeEvent;
        public static InvokeEvent.BooleanEvent GetBooleanEventFromInvokeEvent(InvokeEvent condition)
        {
            if (booleanEventFromInvokeEvent == null)
                booleanEventFromInvokeEvent = CreateGetter<InvokeEvent, InvokeEvent.BooleanEvent>("booleanEvent");

            return booleanEventFromInvokeEvent(condition);
        }

        //InvokeEvent->integerEvent IntegerEvent
        private static Func<InvokeEvent, InvokeEvent.IntegerEvent> integerEventFromInvokeEvent;
        public static InvokeEvent.IntegerEvent GetIntegerEventFromInvokeEvent(InvokeEvent condition)
        {
            if (integerEventFromInvokeEvent == null)
                integerEventFromInvokeEvent = CreateGetter<InvokeEvent, InvokeEvent.IntegerEvent>("integerEvent");

            return integerEventFromInvokeEvent(condition);
        }

        //InvokeEvent->floatEvent FloatEvent
        private static Func<InvokeEvent, InvokeEvent.FloatEvent> floatEventFromInvokeEvent;
        public static InvokeEvent.FloatEvent GetFloatEventFromInvokeEvent(InvokeEvent condition)
        {
            if (floatEventFromInvokeEvent == null)
                floatEventFromInvokeEvent = CreateGetter<InvokeEvent, InvokeEvent.FloatEvent>("floatEvent");

            return floatEventFromInvokeEvent(condition);
        }

        //InvokeEvent->stringEvent StringEvent
        private static Func<InvokeEvent, InvokeEvent.StringEvent> stringEventFromInvokeEvent;
        public static InvokeEvent.StringEvent GetStringEventFromInvokeEvent(InvokeEvent condition)
        {
            if (stringEventFromInvokeEvent == null)
                stringEventFromInvokeEvent = CreateGetter<InvokeEvent, InvokeEvent.StringEvent>("stringEvent");

            return stringEventFromInvokeEvent(condition);
        }

        //================================================================
        //SetActive
        //================================================================
        //SetActive->_targetGameObject GameObjectData
        private static Func<SetActive, GameObjectData> targetGameObjectFromSetActive;
        public static GameObjectData GetTargetGameObjectFromSetActive(SetActive condition)
        {
            if (targetGameObjectFromSetActive == null)
                targetGameObjectFromSetActive = CreateGetter<SetActive, GameObjectData>("_targetGameObject");

            return targetGameObjectFromSetActive(condition);
        }

        //SetActive->activeState BooleanData
        private static Func<SetActive, BooleanData> activeStateFromSetActive;
        public static BooleanData GetActiveStateFromSetActive(SetActive condition)
        {
            if (activeStateFromSetActive == null)
                activeStateFromSetActive = CreateGetter<SetActive, BooleanData>("activeState");

            return activeStateFromSetActive(condition);
        }

        //================================================================
        //SetText
        //================================================================
        //SetText->text StringData
        private static Func<SetText, StringData> textFromSetText;
        public static StringData GetTextFromSetText(SetText condition)
        {
            if (textFromSetText == null)
                textFromSetText = CreateGetter<SetText, StringData>("text");

            return textFromSetText(condition);
        }

        //================================================================
        //RandomInteger
        //================================================================
        //RandomInteger->variable IntegerVariable
        private static Func<RandomInteger, IntegerVariable> variableFromRandomInteger;
        public static IntegerVariable GetVariableFromRandomInteger(RandomInteger randomInteger)
        {
            if (variableFromRandomInteger == null)
                variableFromRandomInteger = CreateGetter<RandomInteger, IntegerVariable>("variable");

            return variableFromRandomInteger(randomInteger);
        }

        //RandomInteger->minValue IntegerData
        private static Func<RandomInteger, IntegerData> minValueFromRandomInteger;
        public static IntegerData GetMinValueFromRandomInteger(RandomInteger randomInteger)
        {
            if (minValueFromRandomInteger == null)
                minValueFromRandomInteger = CreateGetter<RandomInteger, IntegerData>("minValue");

            return minValueFromRandomInteger(randomInteger);
        }

        //RandomInteger->maxValue IntegerData
        private static Func<RandomInteger, IntegerData> maxValueFromRandomInteger;
        public static IntegerData GetMaxValueFromRandomInteger(RandomInteger randomInteger)
        {
            if (maxValueFromRandomInteger == null)
                maxValueFromRandomInteger = CreateGetter<RandomInteger, IntegerData>("maxValue");

            return maxValueFromRandomInteger(randomInteger);
        }

        //RandomInteger->minValue IntegerData
        private static Action<RandomInteger, IntegerData> minValueFromRandomIntegerSetter;
        public static void SetMinValueFromRandomInteger(RandomInteger randomInteger, IntegerData value)
        {
            if (minValueFromRandomIntegerSetter == null)
                minValueFromRandomIntegerSetter = CreateSetter<RandomInteger, IntegerData>("minValue");

            minValueFromRandomIntegerSetter(randomInteger, value);
        }

        //================================================================
        //SaveVariable
        //================================================================
        //SaveVariable->key string
        private static Func<SaveVariable, string> keyFromSaveVariable;
        public static string GetKeyFromSaveVariable(SaveVariable condition)
        {
            if (keyFromSaveVariable == null)
                keyFromSaveVariable = CreateGetter<SaveVariable, string>("key");

            return keyFromSaveVariable(condition);
        }

        //================================================================
        //LoadVariable
        //================================================================
        //LoadVariable->key string
        private static Func<LoadVariable, string> keyFromLoadVariable;
        public static string GetKeyFromLoadVariable(LoadVariable condition)
        {
            if (keyFromLoadVariable == null)
                keyFromLoadVariable = CreateGetter<LoadVariable, string>("key");

            return keyFromLoadVariable(condition);
        }

        //================================================================
        //Call
        //================================================================
        //Call->targetBlock Block
        private static Func<Call, Block> targetBlockFromCall;
        public static Block GetTargetBlockFromCall(Call condition)
        {
            if (targetBlockFromCall == null)
                targetBlockFromCall = CreateGetter<Call, Block>("targetBlock");

            return targetBlockFromCall(condition);
        }

        //Call->targetFlowchart Flowchart
        private static Func<Call, Flowchart> targetFlowchartFromCall;
        public static Flowchart GetTargetFlowchartFromCall(Call condition)
        {
            if (targetFlowchartFromCall == null)
                targetFlowchartFromCall = CreateGetter<Call, Flowchart>("targetFlowchart");

            return targetFlowchartFromCall(condition);
        }

        //================================================================
        //Say
        //================================================================
        //Say->character Character
        private static Func<Say, Character> characterFromSay;
        public static Character GetCharacterFromSay(Say condition)
        {
            if (characterFromSay == null)
                characterFromSay = CreateGetter<Say, Character>("character");

            return characterFromSay(condition);
        }

        //Say->storyText string
        private static Func<Say, string> storyTextFromSay;
        public static string GetStoryTextFromSay(Say condition)
        {
            if (storyTextFromSay == null)
                storyTextFromSay = CreateGetter<Say, string>("storyText");

            return storyTextFromSay(condition);
        }

        //================================================================
        //LoadScene
        //================================================================
        //LoadScene->_sceneName StringData
        private static Func<LoadScene, StringData> sceneNameFromLoadScene;
        public static StringData GetSceneNameFromLoadScene(LoadScene condition)
        {
            if (sceneNameFromLoadScene == null)
                sceneNameFromLoadScene = CreateGetter<LoadScene, StringData>("_sceneName");

            return sceneNameFromLoadScene(condition);
        }

        //================================================================
        //Menu
        //================================================================
        //Menu->targetBlock Block
        private static Func<Menu, Block> targetBlockFromMenu;
        public static Block GetTargetBlockFromMenu(Menu condition)
        {
            if (targetBlockFromMenu == null)
                targetBlockFromMenu = CreateGetter<Menu, Block>("targetBlock");

            return targetBlockFromMenu(condition);
        }

        //Menu->text string
        private static Func<Menu, string> textFromMenu;
        public static string GetTextFromMenu(Menu condition)
        {
            if (textFromMenu == null)
                textFromMenu = CreateGetter<Menu, string>("text");

            return textFromMenu(condition);
        }

        //================================================================
        //SetVariable
        //================================================================
        //SetVariable->setOperator SetOperator
        private static Func<SetVariable, SetOperator> setOperatorFromSetVariable;
        public static SetOperator GetSetOperatorFromSetVariable(SetVariable condition)
        {
            if (setOperatorFromSetVariable == null)
                setOperatorFromSetVariable = CreateGetter<SetVariable, SetOperator>("setOperator");

            return setOperatorFromSetVariable(condition);
        }

        //SetVariable->variable Variable
        private static Func<SetVariable, Variable> variableFromSetVariable;
        public static Variable GetVariableFromSetVariable(SetVariable condition)
        {
            if (variableFromSetVariable == null)
                variableFromSetVariable = CreateGetter<SetVariable, Variable>("variable");

            return variableFromSetVariable(condition);
        }

        //SetVariable->integerData IntegerData
        private static Func<SetVariable, IntegerData> integerDataFromSetVariable;
        public static IntegerData GetIntegerDataFromSetVariable(SetVariable condition)
        {
            if (integerDataFromSetVariable == null)
                integerDataFromSetVariable = CreateGetter<SetVariable, IntegerData>("integerData");

            return integerDataFromSetVariable(condition);
        }

        //SetVariable->booleanData BooleanData
        private static Func<SetVariable, BooleanData> booleanDataFromSetVariable;
        public static BooleanData GetBooleanDataFromSetVariable(SetVariable condition)
        {
            if (booleanDataFromSetVariable == null)
                booleanDataFromSetVariable = CreateGetter<SetVariable, BooleanData>("booleanData");

            return booleanDataFromSetVariable(condition);
        }

        //SetVariable->stringData StringDataMulti
        private static Func<SetVariable, StringDataMulti> stringDataFromSetVariable;
        public static StringDataMulti GetStringDataFromSetVariable(SetVariable condition)
        {
            if (stringDataFromSetVariable == null)
                stringDataFromSetVariable = CreateGetter<SetVariable, StringDataMulti>("stringData");

            return stringDataFromSetVariable(condition);
        }

        //SetVariable->floatData FloatData
        private static Func<SetVariable, FloatData> floatDataFromSetVariable;
        public static FloatData GetFloatDataFromSetVariable(SetVariable condition)
        {
            if (floatDataFromSetVariable == null)
                floatDataFromSetVariable = CreateGetter<SetVariable, FloatData>("floatData");

            return floatDataFromSetVariable(condition);
        }

        //================================================================
        //VariableCondition
        //================================================================
        //VariableCondition->compareOperator CompareOperator
        private static Func<VariableCondition, CompareOperator> compareOperatorFromVariableCondition;
        public static CompareOperator GetCompareOperatorFromVariableCondition(VariableCondition condition)
        {
            if (compareOperatorFromVariableCondition == null)
                compareOperatorFromVariableCondition = CreateGetter<VariableCondition, CompareOperator>("compareOperator");

            return compareOperatorFromVariableCondition(condition);
        }

        //VariableCondition->variable Variable
        private static Func<VariableCondition, Variable> variableFromVariableCondition;
        public static Variable GetVariableFromVariableCondition(VariableCondition condition)
        {

            if (variableFromVariableCondition == null)
                variableFromVariableCondition = CreateGetter<VariableCondition, Variable>("variable");

            return variableFromVariableCondition(condition);
        }

        //VariableCondition->integerData IntegerData
        private static Func<VariableCondition, IntegerData> integerDataFromVariableCondition;
        public static IntegerData GetIntegerDataFromVariableCondition(VariableCondition condition)
        {
            if (integerDataFromVariableCondition == null)
                integerDataFromVariableCondition = CreateGetter<VariableCondition, IntegerData>("integerData");

            return integerDataFromVariableCondition(condition);
        }

        //VariableCondition->booleanData BooleanData
        private static Func<VariableCondition, BooleanData> booleanDataFromVariableCondition;
        public static BooleanData GetBooleanDataFromVariableCondition(VariableCondition condition)
        {
            if (booleanDataFromVariableCondition == null)
                booleanDataFromVariableCondition = CreateGetter<VariableCondition, BooleanData>("booleanData");

            return booleanDataFromVariableCondition(condition);
        }

        //VariableCondition->stringData StringDataMulti
        private static Func<VariableCondition, StringDataMulti> stringDataFromVariableCondition;
        public static StringDataMulti GetStringDataFromVariableCondition(VariableCondition condition)
        {
            if (stringDataFromVariableCondition == null)
                stringDataFromVariableCondition = CreateGetter<VariableCondition, StringDataMulti>("stringData");

            return stringDataFromVariableCondition(condition);
        }

        //VariableCondition->floatData FloatData
        private static Func<VariableCondition, FloatData> floatDataFromVariableCondition;
        public static FloatData GetFloatDataFromVariableCondition(VariableCondition condition)
        {
            if (floatDataFromVariableCondition == null)
                floatDataFromVariableCondition = CreateGetter<VariableCondition, FloatData>("floatData");

            return floatDataFromVariableCondition(condition);
        }

        //================================================================
        //Writer
        //================================================================
        //Writer->writingSpeed float
        private static Action<Writer, float> writingSpeedOfWriter;
        public static void SetWritingSpeedOfWriter(Writer writer, float val)
        {
            if (writingSpeedOfWriter == null)
                writingSpeedOfWriter = CreateSetter<Writer, float>("writingSpeed");

            writingSpeedOfWriter(writer, val);
        }

        //Writer->punctuationPause float
        private static Action<Writer, float> punctiationPauseOfWriter;
        public static void SetPunctiationPauseOfWriter(Writer writer, float val)
        {
            if (punctiationPauseOfWriter == null)
                punctiationPauseOfWriter = CreateSetter<Writer, float>("punctuationPause");

            punctiationPauseOfWriter(writer, val);
        }
    }
}