using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Diagnostics; using System.Runtime.CompilerServices; using System.IO; using System.Globalization; using Barotrauma; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Graphics; using HarmonyLib; namespace QICrabUI { [CUIInternal] public static partial class CUIExtensions { public static int Fit(this int i, int bottom, int top) => Math.Max(bottom, Math.Min(i, top)); public static Vector2 Rotate(this Vector2 v, float angle) => Vector2.Transform(v, Matrix.CreateRotationZ(angle)); public static string SubstringSafe(this string s, int start) { try { int safeStart = start.Fit(0, s.Length); return s.Substring(safeStart, s.Length - safeStart); } catch (Exception e) { CUI.Log($"SubstringSafe {e}"); return ""; } } public static string SubstringSafe(this string s, int start, int length) { int end = (start + length).Fit(0, s.Length); int safeStart = start.Fit(0, s.Length); int safeLength = end - safeStart; try { return s.Substring(safeStart, safeLength); } catch (Exception e) { CUI.Log($"SubstringSafe {e.Message}\ns:\"{s}\" start: {start}->{safeStart} end: {end} length: {length}->{safeLength} ", Color.Orange); return ""; } } public static Dictionary ParseKVPairs(string raw) { Dictionary props = new(); if (raw == null || raw == "") return props; string content = raw.Split('{', '}')[1]; List expressions = new(); int start = 0; int end = 0; int depth = 0; for (int i = 0; i < content.Length; i++) { char c = content[i]; end = i; if (c == '[' || c == '{') depth++; if (c == ']' || c == '}') depth--; if (depth <= 0 && c == ',') { expressions.Add(content.Substring(start, end - start)); start = end + 1; } } expressions.Add(content.Substring(start, end - start)); var pairs = expressions.Select(s => s.Split(':').Select(sub => sub.Trim()).ToArray()); foreach (var pair in pairs) { props[pair[0].ToLower()] = pair[1]; } return props; } public static string ColorToString(Color c) => $"{c.R},{c.G},{c.B},{c.A}"; public static string Vector2ToString(Vector2 v) => $"[{v.X},{v.Y}]"; public static string NullVector2ToString(Vector2? v) => v.HasValue ? $"[{v.Value.X},{v.Value.Y}]" : "null"; public static string NullIntToString(int? i) => i.HasValue ? $"{i}" : "null"; public static string RectangleToString(Rectangle r) => $"[{r.X},{r.Y},{r.Width},{r.Height}]"; public static string GUIFontToString(GUIFont f) => f.Identifier.Value; public static string SpriteEffectsToString(SpriteEffects e) { if ((int)e == 3) return "FlipBothSides"; else return e.ToString(); } public static string IEnumerableStringToString(IEnumerable e) => $"[{string.Join(',', e.ToArray())}]"; public static IEnumerable ParseIEnumerableString(string raw) { if (raw == null || raw == "") return new List(); string content = raw.Split('[', ']')[1]; return content.Split(','); } public static string ParseString(string s) => s; // BaroDev (wide) //public static GUISoundType ParseGUISoundType(string s) => Enum.Parse(s); public static GUIFont ParseGUIFont(string raw) { GUIFont font = GUIStyle.Fonts.GetValueOrDefault(new Identifier(raw.Trim())); font ??= GUIStyle.Font; return font; } public static SpriteEffects ParseSpriteEffects(string raw) { if (raw == "FlipBothSides") return SpriteEffects.FlipHorizontally | SpriteEffects.FlipVertically; else return Enum.Parse(raw); } public static int? ParseNullInt(string raw) { if (raw == "null") return null; return int.Parse(raw); } public static Vector2? ParseNullVector2(string raw) { if (raw == "null") return null; return ParseVector2(raw); } public static Vector2 ParseVector2(string raw) { if (raw == null || raw == "") return new Vector2(0, 0); string content = raw.Split('[', ']')[1]; List coords = content.Split(',').Select(s => s.Trim()).ToList(); float x = 0; float y = 0; float.TryParse(coords.ElementAtOrDefault(0), out x); float.TryParse(coords.ElementAtOrDefault(1), out y); return new Vector2(x, y); } public static Rectangle ParseRectangle(string raw) { if (raw == null || raw == "") return new Rectangle(0, 0, 1, 1); string content = raw.Split('[', ']')[1]; List coords = content.Split(',').Select(s => s.Trim()).ToList(); int x = 0; int y = 0; int w = 0; int h = 0; int.TryParse(coords.ElementAtOrDefault(0), out x); int.TryParse(coords.ElementAtOrDefault(1), out y); int.TryParse(coords.ElementAtOrDefault(2), out w); int.TryParse(coords.ElementAtOrDefault(3), out h); return new Rectangle(x, y, w, h); } public static Color ParseColor(string s) => XMLExtensions.ParseColor(s, false); public static Dictionary Parse; public static Dictionary CustomToString; internal static void InitStatic() { CUI.OnInit += () => { Stopwatch sw = Stopwatch.StartNew(); Parse = new Dictionary(); CustomToString = new Dictionary(); Parse[typeof(string)] = typeof(CUIExtensions).GetMethod("ParseString"); //Parse[typeof(GUISoundType)] = typeof(CUIExtensions).GetMethod("ParseGUISoundType"); Parse[typeof(Rectangle)] = typeof(CUIExtensions).GetMethod("ParseRectangle"); Parse[typeof(GUIFont)] = typeof(CUIExtensions).GetMethod("ParseGUIFont"); Parse[typeof(Vector2?)] = typeof(CUIExtensions).GetMethod("ParseNullVector2"); Parse[typeof(Vector2)] = typeof(CUIExtensions).GetMethod("ParseVector2"); Parse[typeof(SpriteEffects)] = typeof(CUIExtensions).GetMethod("ParseSpriteEffects"); Parse[typeof(Color)] = typeof(CUIExtensions).GetMethod("ParseColor"); Parse[typeof(int?)] = typeof(CUIExtensions).GetMethod("ParseNullInt"); Parse[typeof(IEnumerable)] = typeof(CUIExtensions).GetMethod("ParseIEnumerableString"); CustomToString[typeof(IEnumerable)] = typeof(CUIExtensions).GetMethod("IEnumerableStringToString"); CustomToString[typeof(int?)] = typeof(CUIExtensions).GetMethod("NullIntToString"); CustomToString[typeof(Color)] = typeof(CUIExtensions).GetMethod("ColorToString"); CustomToString[typeof(SpriteEffects)] = typeof(CUIExtensions).GetMethod("SpriteEffectsToString"); CustomToString[typeof(Vector2)] = typeof(CUIExtensions).GetMethod("Vector2ToString"); CustomToString[typeof(Vector2?)] = typeof(CUIExtensions).GetMethod("NullVector2ToString"); CustomToString[typeof(GUIFont)] = typeof(CUIExtensions).GetMethod("GUIFontToString"); CustomToString[typeof(Rectangle)] = typeof(CUIExtensions).GetMethod("RectangleToString"); CUIDebug.Log($"CUIExtensions.Initialize took {sw.ElapsedMilliseconds}ms"); }; CUI.OnDispose += () => { Parse.Clear(); CustomToString.Clear(); }; } } }