From 5ae7542c388e03d9a1d5f0ef13a443a0938260a7 Mon Sep 17 00:00:00 2001 From: Robert Altner Date: Thu, 1 Aug 2019 22:40:01 +0200 Subject: [PATCH] Pushed for version v0.3 --- CrosshairMod/Crosshair.cs | 65 +++++++++++--- CrosshairMod/CrosshairMod.csproj | 1 + CrosshairMod/Interface.cs | 99 ++++++++++++++++++++++ CrosshairMod/Main.cs | 39 +++++---- CrosshairMod/Settings.cs | 57 ++++++++++++- CrosshairMod/bin/Release/CrosshairMod.dll | Bin 0 -> 13312 bytes 6 files changed, 227 insertions(+), 34 deletions(-) create mode 100644 CrosshairMod/Interface.cs create mode 100644 CrosshairMod/bin/Release/CrosshairMod.dll diff --git a/CrosshairMod/Crosshair.cs b/CrosshairMod/Crosshair.cs index 7d36e26..1b6c7ee 100644 --- a/CrosshairMod/Crosshair.cs +++ b/CrosshairMod/Crosshair.cs @@ -13,11 +13,44 @@ namespace CrosshairMod private static Texture2D m_texture = new Texture2D(0, 0); private static GUIStyle m_style; private static bool m_enabled = true; + private static bool m_validState = true; // Toggles visibilty of the crosshair public static void Toggle() { m_enabled = !m_enabled; + Settings.SetSetting("crosshairVisible", 1, true); + } + + // Change Color + public static void SetColor(int r, int g, int b, int a) + { + Settings.SetSetting("crosshairColorRed", r); + Settings.SetSetting("crosshairColorGreen", g); + Settings.SetSetting("crosshairColorBlue", b); + Settings.SetSetting("crosshairColorAlpha", a); + + Create(); + } + + // Change Size + public static void ChangeSize(int difference) + { + int currentLength = Settings.GetValue("crosshairLength"); + Settings.SetSetting("crosshairLength", currentLength + difference); + + // Re-create crosshair with new settings + Create(); + } + + // Change Thickness + public static void ChangeThickness(int difference) + { + int currentThickness = Settings.GetValue("crosshairThickness"); + Settings.SetSetting("crosshairThickness", currentThickness + difference); + + // Re-create crosshair with new settings + Create(); } // This must be called, or else no crosshair will be rendered @@ -25,12 +58,12 @@ namespace CrosshairMod { // Creates a crosshair texture // Assign dictionary values to variables - int m_crosshairLength = Settings.GetValue("crosshairLength"); - int m_crosshairThickness = Settings.GetValue("crosshairThickness"); - int m_crosshairColorRed = Settings.GetValue("crosshairColorRed"); - int m_crosshairColorGreen = Settings.GetValue("crosshairColorGreen"); - int m_crosshairColorBlue = Settings.GetValue("crosshairColorBlue"); - int m_crosshairColorAlpha = Settings.GetValue("crosshairColorAlpha"); + int m_crosshairLength = Settings.GetValue("crosshairLength", true, 15); + int m_crosshairThickness = Settings.GetValue("crosshairThickness", true, 3); + int m_crosshairColorRed = Settings.GetValue("crosshairColorRed", true, 255); + int m_crosshairColorGreen = Settings.GetValue("crosshairColorGreen", true, 94); + int m_crosshairColorBlue = Settings.GetValue("crosshairColorBlue", true, 244); + int m_crosshairColorAlpha = Settings.GetValue("crosshairColorAlpha", true, 255); // Construct color object from RGBA values Color m_crosshairColor = new Color(m_crosshairColorRed / 255f, @@ -81,22 +114,26 @@ namespace CrosshairMod public static void Render() { - if(InvalidCrosshair()) + if (m_validState) { - Logging.LogWarning("Crosshair was either not initialized, or has an invalid size of (0, 0). Check your settings file and adjust your settings accordingly"); - return; - } + if (InvalidCrosshair()) + { + Logging.LogWarning("Crosshair was either not initialized, or has an invalid size of (0, 0). Check your settings file and adjust your settings accordingly"); + return; + } - if (m_enabled) - GUI.Label(new Rect(Screen.width / 2 - m_texture.width / 2, Screen.height / 2 - m_texture.height / 2, m_texture.width, m_texture.height), - m_texture, m_style); + if (m_enabled) + GUI.Label(new Rect(Screen.width / 2 - m_texture.width / 2, Screen.height / 2 - m_texture.height / 2, m_texture.width, m_texture.height), + m_texture, m_style); + } } private static bool InvalidCrosshair() { // Check if the texture is bigger than (0, 0) to see if it was initialized. - return (m_texture.width == 0 && m_texture.height == 0); + m_validState = (m_texture.width != 0 && m_texture.height != 0); + return !m_validState; } } } diff --git a/CrosshairMod/CrosshairMod.csproj b/CrosshairMod/CrosshairMod.csproj index fda3ef3..1f918ef 100644 --- a/CrosshairMod/CrosshairMod.csproj +++ b/CrosshairMod/CrosshairMod.csproj @@ -46,6 +46,7 @@ + diff --git a/CrosshairMod/Interface.cs b/CrosshairMod/Interface.cs new file mode 100644 index 0000000..d8e4634 --- /dev/null +++ b/CrosshairMod/Interface.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using UnityEngine; + +namespace CrosshairMod +{ + static class Interface + { + private static bool m_visible = false; + + private static Dictionary m_buttons = new Dictionary(); + private static int rSliderValue, gSliderValue, bSliderValue, aSliderValue; + + private static Texture2D m_background = new Texture2D(1, 1); + private static GUIStyle m_style = new GUIStyle(); + + + private static Vector2 m_position; + private static Vector2 m_dimension; + + // Initializes all Buttons, gives them their function etc + public static void Init() + { + m_dimension = new Vector2(Screen.width / 4, Screen.height / 4); + m_position = new Vector2((Screen.width - m_dimension.x) / 2, (Screen.height - m_dimension.y) / 2); + + m_background.SetPixel(0, 0, new Color(0.4f, 0.4f, 0.4f, 0.4f)); + m_background.wrapMode = TextureWrapMode.Repeat; + m_background.Apply(); + + m_style.normal.background = m_background; + + m_buttons.Add("visibility", new GUIButton((uint)m_position.x + 20, (uint)m_position.y + 20, 200, 30, "Toggle Crosshair")); + m_buttons["visibility"].OnClick += (object sender, EventArgs e) => { Crosshair.Toggle(); }; + + m_buttons.Add("size-", new GUIButton((uint)m_position.x + 20, (uint)m_position.y + 60, 30, 30, "-")); + m_buttons.Add("size+", new GUIButton((uint)m_position.x + 190, (uint)m_position.y + 60, 30, 30, "+")); + m_buttons["size-"].OnClick += (object sender, EventArgs e) => { Crosshair.ChangeSize(-1); }; + m_buttons["size+"].OnClick += (object sender, EventArgs e) => { Crosshair.ChangeSize(+1); }; + + m_buttons.Add("thick-", new GUIButton((uint)m_position.x + 20, (uint)m_position.y + 100, 30, 30, "-")); + m_buttons.Add("thick+", new GUIButton((uint)m_position.x + 190, (uint)m_position.y + 100, 30, 30, "+")); + m_buttons["thick-"].OnClick += (object sender, EventArgs e) => { Crosshair.ChangeThickness(-1); }; + m_buttons["thick+"].OnClick += (object sender, EventArgs e) => { Crosshair.ChangeThickness(+1); }; + + rSliderValue = Settings.GetValue("crosshairColorRed"); + gSliderValue = Settings.GetValue("crosshairColorGreen"); + bSliderValue = Settings.GetValue("crosshairColorBlue"); + aSliderValue = Settings.GetValue("crosshairColorAlpha"); + } + + // Displays / Hides the menu + public static void Toggle() + { + m_visible = !m_visible; + } + + // Renders the Panel, but also handles Updating the buttons + public static void Render() + { + if(m_visible) + { + GUI.Label(new Rect(m_position, m_dimension), m_background, m_style); + + GUI.Label(new Rect(m_position.x + 60, m_position.y + 70, 120, 30), "Length: " + Settings.GetValue("crosshairLength")); + GUI.Label(new Rect(m_position.x + 60, m_position.y + 110, 120, 30), "Thickness: " + Settings.GetValue("crosshairThickness")); + + GUI.Label(new Rect(m_position.x + m_dimension.x / 2 + 20, m_position.y + 30, 200, 30), "R: " + rSliderValue); + rSliderValue = (int)GUI.HorizontalSlider(new Rect(m_position.x + m_dimension.x / 2 + 60, m_position.y + 20, 200, 30), (int)rSliderValue, 0f, 255f); + + GUI.Label(new Rect(m_position.x + m_dimension.x / 2 + 20, m_position.y + 70, 200, 30), "G: " + gSliderValue); + gSliderValue = (int)GUI.HorizontalSlider(new Rect(m_position.x + m_dimension.x / 2 + 60, m_position.y + 60, 200, 30), (int)gSliderValue, 0f, 255f); + + GUI.Label(new Rect(m_position.x + m_dimension.x / 2 + 20, m_position.y + 110, 200, 30), "B: " + bSliderValue); + bSliderValue = (int)GUI.HorizontalSlider(new Rect(m_position.x + m_dimension.x / 2 + 60, m_position.y + 100, 200, 30), (int)bSliderValue, 0f, 255f); + + GUI.Label(new Rect(m_position.x + m_dimension.x / 2 + 20, m_position.y + 150, 200, 30), "A: " + aSliderValue); + aSliderValue = (int)GUI.HorizontalSlider(new Rect(m_position.x + m_dimension.x / 2 + 60, m_position.y + 140, 200, 30), (int)aSliderValue, 0f, 255f); + + Crosshair.SetColor(rSliderValue, gSliderValue, bSliderValue, aSliderValue); + + // Update Buttons + HandleButtons(); + } + } + + private static void HandleButtons() + { + foreach(KeyValuePair pair in m_buttons) + { + pair.Value.Update(); + } + } + } +} diff --git a/CrosshairMod/Main.cs b/CrosshairMod/Main.cs index 3c07673..f6fb2ea 100644 --- a/CrosshairMod/Main.cs +++ b/CrosshairMod/Main.cs @@ -17,16 +17,8 @@ namespace CrosshairMod { public class Main : MonoBehaviour { - // Initialize State checker. If this is false, the crosshair won't be drawn - // This is a temporary fix to stop this mod from spamming errors in the log - private bool m_validState = true; - private bool m_renderCrosshair = true; - - // Reads settings file and sets all variables - - - - + private const string MENU_OPEN_KEY = "H"; + private const string CH_TOGGLE_KEY = "J"; // This will be executed first void Start() @@ -35,19 +27,34 @@ namespace CrosshairMod Settings.LoadSettings(".\\Blackwake_Data\\Managed\\Mods\\chSettings.sett"); // Create Crosshair Crosshair.Create(); - - // Add function to Button - crosshairButton.OnClick += (object sender, EventArgs e) => { Crosshair.Toggle(); }; + // Create Panel + Interface.Init(); } - private GUIButton crosshairButton = new GUIButton(200, 10, 100, 20, "Toggle Crosshair"); - void OnGUI() { - crosshairButton.Update(); + // Check for Key press + if(Event.current.Equals(Event.KeyboardEvent(MENU_OPEN_KEY))) + { + Interface.Toggle(); + } + if (Event.current.Equals(Event.KeyboardEvent(CH_TOGGLE_KEY))) + { + Crosshair.Toggle(); + } + + //Render GUI + Interface.Render(); //Render Crosshair Crosshair.Render(); } + + void OnApplicationQuit() + { + // Save settings + Settings.SaveSettings(".\\Blackwake_Data\\Managed\\Mods\\chSettings.sett"); + Logging.Log("Saved Settings"); + } } } diff --git a/CrosshairMod/Settings.cs b/CrosshairMod/Settings.cs index f4e283c..7bf7b2e 100644 --- a/CrosshairMod/Settings.cs +++ b/CrosshairMod/Settings.cs @@ -46,20 +46,69 @@ namespace CrosshairMod Logging.Log("Successfully loaded settings!"); } - public static void writeSettings(string filepath) + // Converts the dictionary to a sett file + public static void SaveSettings(string filepath) { - //TODO: Implement saving + string filecontent = ""; + foreach(KeyValuePair pair in m_settings) + { + filecontent += (pair.Key + "=" + pair.Value + "\n"); + } + + System.IO.File.WriteAllText(filepath, filecontent); + } + + // Adds a setting to the settings + public static void AddSetting(string key, int value) + { + if (m_settings.ContainsKey(key)) + return; + + m_settings.Add(key, value); + } + + // Changes a settings value + public static void SetSetting(string key, int newVal, bool addIfDoesntExist = false) + { + + if(!m_settings.ContainsKey(key)) + { + if (!addIfDoesntExist) + { + Logging.LogError("Tried to change a setting with key \"" + key + "\" that doesn't exist."); + return; + } + else + { + AddSetting(key, newVal); + Logging.LogWarning("Tried to change a setting with key \"" + key + "\" that doesn't exist. It has been added now."); + } + } + + m_settings[key] = newVal; } // Tries to return the value belonging to a certain key // If the specified key doesn't exist, it returns 0 and logs an error - public static int GetValue(string key) + // One can also specify that the setting should be created with some initial value + public static int GetValue(string key, bool addIfDoesntExist = false, int initialValue = 0) { int value = 0; bool valExists = m_settings.TryGetValue(key, out value); if (!valExists) - Logging.LogError("Tried to access unknown setting: \"" + key + "\". Check your chSettings.sett for errors."); + { + if (!addIfDoesntExist) + { + Logging.LogError("Tried to access unknown setting: \"" + key + "\". Check your chSettings.sett for errors."); + } + else + { + AddSetting(key, initialValue); + Logging.LogWarning("Tried to access unknown setting: \"" + key + "\". A new setting with this key was created."); + return initialValue; + } + } return value; } diff --git a/CrosshairMod/bin/Release/CrosshairMod.dll b/CrosshairMod/bin/Release/CrosshairMod.dll new file mode 100644 index 0000000000000000000000000000000000000000..1080c7e0adf46aa0f8645a74ac5c34d330599e94 GIT binary patch literal 13312 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 U+wo|Fv3v2KGJm=L|3%=x0dvWuGXMYp literal 0 HcmV?d00001