using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using CitizenFX.Core; using CitizenFX.Core.Native; namespace TaxiJob.Shared { public sealed class ClientConfig { private sealed class ConfigReader { private const char SplitChar = ' '; private const string SectionStart = "{"; private const string SectionEnd = "}"; private const string CommentPrefix = "//"; private readonly string _fileName; private readonly List>> _loadedData = new List>>(); private readonly List _allSections = new List(); public ConfigReader(string fileName, bool load = false) { _fileName = fileName; if (!load) return; Read(); } public string this[string section, string key, string result = ""] => GetValue(section, key, result); public T GetValue(string section, string key, T result) { if (!SectionExists(section)) return result; string data = GetData(section, key, result.ToString()); try { return (T)Convert.ChangeType(data, typeof(T)); } catch (InvalidCastException) { return result; } } public Vector3 GetVector3(string section, string key, Vector3 result) { if (!SectionExists(section)) return result; string data = GetData(section, key, result.ToString()); data = data.Replace("[", "").Replace("]", "").Replace(" ", ""); return new Vector3(data.Split(',').Select(Convert.ToSingle).ToArray()); } public Vector4 GetVector4(string section, string key, Vector4 result) { if (!SectionExists(section)) return result; string data = GetData(section, key, result.ToString()); data = data.Replace("[", "").Replace("]", "").Replace(" ", ""); return new Vector4(data.Split(',').Select(Convert.ToSingle).ToArray()); } public int[] GetIntArray(string section, string key, int[] result) { if (!SectionExists(section)) return result; string data = GetData(section, key, result.ToString()); data = data.Replace("[", "").Replace("]", "").Replace(" ", ""); return data.Split(',').Select(n => Convert.ToInt32(n)).ToArray(); } public Vector3[] GetVector3Array(string section) { List vectors = new List(); foreach (Tuple> tuple in _loadedData) { if (!tuple.Item1.Equals(section)) continue; foreach (var key in tuple.Item2.Values) { var data = key.Replace("[", "").Replace("]", "").Replace(" ", ""); var array = data.Split(',').Select(Convert.ToSingle).ToArray(); var vector = new Vector3(array); vectors.Add(vector); } } return vectors.ToArray(); } public string[] GetStringArray(string section) { List strings = new List(); foreach (Tuple> tuple in _loadedData) { if (!tuple.Item1.Equals(section)) continue; foreach (var key in tuple.Item2.Values) { strings.Add(key); } } return strings.ToArray(); } public MarkerConfig GetMarkerConfig(string section) { var color = GetIntArray(section, "Color", new int[3]); return new MarkerConfig { Position = GetVector3(section, "Position", Vector3.Zero), Size = GetVector3(section, "Size", Vector3.Zero), Color = Color.FromArgb(color[0], color[1], color[2]), Type = (MarkerType)GetValue(section, "Type", 0), Rotate = GetValue(section, "Rotate", false) }; } public string GetData(string section, string key, string result) { foreach (Tuple> tuple in _loadedData) { if (tuple.Item1.Equals(section)) return tuple.Item2.ContainsKey(key) ? tuple.Item2[key] : result; } return result; } public bool SectionExists(string section) => _allSections.Contains(section); public void Read() { _loadedData.Clear(); _allSections.Clear(); string str1 = ""; Dictionary source = new Dictionary(); string str2 = API.LoadResourceFile(API.GetCurrentResourceName(), _fileName); char[] chArray = { '\n' }; foreach (string str3 in str2.Split(chArray).Select(str => str.Trim())) { string text = str3.Replace("\r", ""); if (!string.IsNullOrEmpty(text) && !string.IsNullOrWhiteSpace(text)) { if (text.StartsWith(SectionStart)) { str1 = text.Substring(1); if (text.EndsWith(SectionEnd) && !str1.Contains(SectionStart)) { str1 = str1.Remove(str1.Length - 1, 1); _loadedData.Add( new Tuple>(str1, new Dictionary())); if (!_allSections.Contains(str1)) _allSections.Add(str1); source.Clear(); } } else if (text.EndsWith(SectionEnd) || text.StartsWith(SectionEnd)) { Dictionary dictionary = source.ToDictionary( entry => entry.Key, entry => entry.Value); _loadedData.Add(new Tuple>(str1, dictionary)); if (!_allSections.Contains(str1)) _allSections.Add(str1); source.Clear(); } else if (!text.StartsWith(CommentPrefix)) { Tuple data = ConvertToData(text); if (!source.ContainsKey(data.Item1)) source.Add(data.Item1, data.Item2); } } } } private Tuple ConvertToData(string text) { int length = text.IndexOf(SplitChar); if (length == -1) return new Tuple(text, ""); string str = ""; if (length - 1 < text.Length) str = text.Substring(length + 1, text.Length - length - 1); return new Tuple(text.Substring(0, length), str); } } public ClientConfig() { var reader = new ConfigReader("settings.ini", true); DrawDistance = reader.GetValue("[General]", "DrawDistance", 0); VehicleSpawnPoint = reader.GetVector4("[General]", "VehicleSpawnPoint", Vector4.Zero); VehicleDeleter = reader.GetVector3("[General]", "VehicleDeleter", Vector3.Zero); VehicleModel = reader.GetValue("[General]", "VehicleModel", "taxi"); TimeToNpcJob = reader.GetValue("[General]", "TimeToNpcJob", 0); Cloakroom = reader.GetMarkerConfig("[Cloakroom]"); VehicleSpawner = reader.GetMarkerConfig("[VehicleSpawner]"); Npcs = reader.GetStringArray("[Npcs]"); Positions = reader.GetVector3Array("[Positions]"); } public float DrawDistance { get; } public Vector4 VehicleSpawnPoint { get; } public Vector3 VehicleDeleter { get; } public string VehicleModel { get; } public int TimeToNpcJob { get; } public MarkerConfig Cloakroom { get; } public MarkerConfig VehicleSpawner { get; } public string[] Npcs { get; } public Vector3[] Positions { get; } } public struct MarkerConfig { public Vector3 Position { get; set; } public Vector3 Size { get; set; } public Color Color { get; set; } public MarkerType Type { get; set; } public bool Rotate { get; set; } public void Render() { World.DrawMarker(Type, Position, Vector3.Zero, Vector3.Zero, Size, Color, rotateY: Rotate); } } }