public void RefreshState() { if (gameController.Area.CurrentArea == null) { return; } if (entityCollectSettingsContainer.NeedUpdate) { return; } if (Player == null || !Player.IsValid) { return; } while (Simple.Count > 0) { var entity = Simple.Pop(); if (entity == null) { DebugWindow.LogError($"{nameof(EntityListWrapper)}.{nameof(RefreshState)} entity is null. (Very strange)."); continue; } var entityId = entity.Id; if (entityCache.TryGetValue(entityId, out _)) { continue; } if (entityId >= int.MaxValue && !_settings.ParseServerEntities) { continue; } if (entity.Type == EntityType.Error) { continue; } EntityAddedAny?.Invoke(entity); if ((int)entity.Type >= 100) { EntityAdded?.Invoke(entity); } entityCache[entityId] = entity; } UpdateEntityCollections(); entityCollectSettingsContainer.NeedUpdate = true; }
private void DoWork() { while (running) { if (Job.IsCompleted && SecondJob.IsCompleted) { _event.WaitOne(); CountWait++; _wait = true; } if (!Job.IsCompleted) { try { sw.Restart(); Job.Work?.Invoke(); } catch (Exception e) { DebugWindow.LogError(e.ToString()); Job.IsFailed = true; } finally { Job.ElapsedMs = sw.Elapsed.TotalMilliseconds; Job.IsCompleted = true; sw.Restart(); } } if (!SecondJob.IsCompleted) { try { sw.Restart(); SecondJob.Work?.Invoke(); } catch (Exception e) { DebugWindow.LogError(e.ToString()); SecondJob.IsFailed = true; } finally { SecondJob.ElapsedMs = sw.Elapsed.TotalMilliseconds; SecondJob.IsCompleted = true; sw.Restart(); } } } }
public void Tick() { try { if (IsForeGroundLast != IsForeGroundCache) { IsForeGroundLast = IsForeGroundCache; eIsForegroundChanged(IsForeGroundCache); } AreaInstance.CurrentHash = Game.CurrentAreaHash; if (LeftPanel.Used) { LeftPanel.StartDrawPoint = LeftCornerMap.Value; } if (UnderPanel.Used) { UnderPanel.StartDrawPoint = UnderCornerMap.Value; } //Every 3 frame check area change and force garbage collect every new area if (Core.FramesCount % 3 == 0 && Area.RefreshState()) { debClearCache.TickAction(() => { RemoteMemoryObject.Cache.TryClearCache(); }); } InGame = Game.InGame; //Game.IngameState.InGame; IsLoading = Game.IsLoading; if (InGame) { if (!WasInGame) { // when core is created too early during game launch it will be missing some files pointers as they weren't loaded yet Game.ReloadFiles(); WasInGame = true; } Game.IngameState.UpdateData(); CachedValue.Latency = Game.IngameState.CurLatency; } } catch (Exception e) { DebugWindow.LogError(e.ToString()); } }
private void AreaChanged(AreaInstance area) { try { entityCollectSettingsContainer.Break = true; var dataLocalPlayer = gameController.Game.IngameState.Data.LocalPlayer; if (Player == null) { if (dataLocalPlayer.Path.StartsWith("Meta")) { Player = dataLocalPlayer; Player.IsValid = true; PlayerUpdate?.Invoke(this, Player); } } else { if (Player.Address != dataLocalPlayer.Address) { if (dataLocalPlayer.Path.StartsWith("Meta")) { Player = dataLocalPlayer; Player.IsValid = true; PlayerUpdate?.Invoke(this, Player); } } } entityCache.Clear(); OnlyValidEntities.Clear(); NotOnlyValidEntities.Clear(); foreach (var e in ValidEntitiesByType) { e.Value.Clear(); } // foreach (var e in NotValidEntitiesByType) e.Value.Clear(); } catch (Exception e) { DebugWindow.LogError($"{nameof(EntityListWrapper)} -> {e}"); } }
private static void CompilePluginIntoDll(string plugin) { var rootDirectory = AppDomain.CurrentDomain.BaseDirectory; var pathToSources = Path.Combine(rootDirectory, "Plugins", "Source"); var directories = new DirectoryInfo(pathToSources).GetDirectories(); var pluginDir = directories.FirstOrDefaultF(x => x.Name.Equals(plugin, StringComparison.OrdinalIgnoreCase)); if (pluginDir == null) { DebugWindow.LogError($"{plugin} directory not found."); return; } using (var provider = PrepareProvider()) { CompileSourceIntoDll(provider, pluginDir); } }
private static void GetDrawersRecurs(IList <ISettingsHolder> drawers, IList <ISettingsHolder> result) { foreach (var drawer in drawers) { if (!result.Contains(drawer)) { result.Add(drawer); } else { DebugWindow.LogError( $" Possible stashoverflow or duplicating drawers detected while generating menu. Drawer SettingName: {drawer.Name}, Id: {drawer.ID}", 5); } } drawers.ForEach(x => GetDrawersRecurs(x.Children, result)); }
private static void GetDrawersRecurs(IList <ISettingsHolder> drawers, IList <ISettingsHolder> settingsHolder) { foreach (var drawer in drawers) { if (settingsHolder.Contains(drawer)) { DebugWindow.LogError( $"SettingsParser => Possible overflow or duplicate drawers detected when generating menu. Name: {drawer.Name}, Id: {drawer.ID}", 5); } else { settingsHolder.Add(drawer); } } drawers.ForEach(x => GetDrawersRecurs(x.Children, settingsHolder)); }
public SoundController(string dir) { soundsDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, dir); if (!Directory.Exists(soundsDir)) { initialized = false; DebugWindow.LogError("Sounds dir not found, continue working without any sound."); return; } xAudio2 = new XAudio2(); xAudio2.StartEngine(); masteringVoice = new MasteringVoice(xAudio2); /*var reverb = new Reverb(xAudio2); * var effectDescriptor = new EffectDescriptor(reverb); * masteringVoice.SetEffectChain(effectDescriptor); * masteringVoice.EnableEffect(0);*/ var soundFiles = Directory.GetFiles(soundsDir, "*.wav"); Sounds = new Dictionary <string, MyWave>(soundFiles.Length); /* * foreach (var file in soundFiles) * { * var fileInfo = new FileInfo(file); * var soundStream = new SoundStream(File.OpenRead(file)); * var waveFormat = soundStream.Format; * * var buffer = new AudioBuffer() * { * Stream = soundStream.ToDataStream(), AudioBytes = (int) soundStream.Length, Flags = BufferFlags.EndOfStream * }; * soundStream.Close(); * Sounds[fileInfo.Name.Split('.').First()] = new MyWave() * { * Buffer = buffer, WaveFormat = waveFormat, DecodedPacketsInfo = soundStream.DecodedPacketsInfo * }; * } */ initialized = true; }
public void PlaySound(string name) { if (!initialized) { return; } if (Sounds.TryGetValue(name, out var wave)) { if (wave == null) { wave = LoadSound(name); } } else { wave = LoadSound(name); } if (wave == null) { DebugWindow.LogError($"Sound file: {name}.wav not found."); return; } var sourceVoice = new SourceVoice(xAudio2, wave.WaveFormat, true); sourceVoice.SubmitSourceBuffer(wave.Buffer, wave.DecodedPacketsInfo); sourceVoice.Start(); _list.Add(sourceVoice); for (var i = 0; i < _list.Count; i++) { var sv = _list[i]; if (sv.State.BuffersQueued <= 0) { sv.Stop(); sv.DestroyVoice(); sv.Dispose(); _list.RemoveAt(i); } } }
public void Tick() { try { if (IsForeGroundLast != IsForeGroundCache) { IsForeGroundLast = IsForeGroundCache; eIsForegroundChanged(IsForeGroundCache); } AreaInstance.CurrentHash = Game.CurrentAreaHash; if (LeftPanel.Used) { LeftPanel.StartDrawPoint = LeftCornerMap.Value; } if (UnderPanel.Used) { UnderPanel.StartDrawPoint = UnderCornerMap.Value; } //Every 3 frame check area change and force garbage collect every new area if (Core.FramesCount % 3 == 0 && Area.RefreshState()) { debClearCache.TickAction(() => { RemoteMemoryObject.Cache.TryClearCache(); }); } InGame = Game.InGame; //Game.IngameState.InGame; IsLoading = Game.IsLoading; if (InGame) { CachedValue.Latency = Game.IngameState.CurLatency; } } catch (Exception e) { DebugWindow.LogError(e.ToString()); } }
public void Run() { if (IsCompleted) { return; } try { _stopwatch.Restart(); Work?.Invoke(); } catch (Exception e) { DebugWindow.LogError(e.ToString()); IsFailed = true; } finally { ElapsedMs = _stopwatch.Elapsed.TotalMilliseconds; IsCompleted = true; } }
public void RefreshState() { if (gameController.Area.CurrentArea == null /*|| !EntitiesStack.CanRead */ || entityCollectSettingsContainer.NeedUpdate || !Player.IsValid) { return; } // var entities = EntitiesStack.Read(); while (Simple.Count > 0) { var entity = Simple.Pop(); if (entity == null) { DebugWindow.LogError($"{nameof(EntityListWrapper)}.{nameof(RefreshState)} entity is null. (Very strange)."); continue; } var entityId = entity.Id; if (entityCache.TryGetValue(entityId, out _)) { continue; } if (entityId >= int.MaxValue && !_settings.ParseServerEntities) { continue; } if (/*!entity.IsValid ||*/ entity.Type == EntityType.Error) { continue; } /*if (entity.Type == EntityType.Monster && (entity.GetComponent<Life>() == null || * entity.GetComponent<ObjectMagicProperties>() == null)) * { * entity.IsValid = false; * continue; * }*/ if (entity.League == LeagueType.Legion) { if (entity.Stats == null) { continue; } } EntityAddedAny?.Invoke(entity); if ((int)entity.Type >= 100) { EntityAdded?.Invoke(entity); } entityCache[entityId] = entity; } UpdateEntityCollections(); entityCollectSettingsContainer.NeedUpdate = true; }
public GameController(Memory memory, SoundController soundController, SettingsContainer settings, MultiThreadManager multiThreadManager) { _settings = settings.CoreSettings; Memory = memory; SoundController = soundController; Settings = settings; MultiThreadManager = multiThreadManager; try { Cache = new Cache(); Game = new TheGame(memory, Cache); Area = new AreaController(Game); Window = new GameWindow(memory.Process); Files = Game.Files; EntityListWrapper = new EntityListWrapper(this, _settings, multiThreadManager); } catch (Exception e) { DebugWindow.LogError(e.ToString()); } PluginBridge = new PluginBridge(); IsForeGroundCache = WinApi.IsForegroundWindow(Window.Process.MainWindowHandle); var values = Enum.GetValues(typeof(IconPriority)); LeftPanel = new PluginPanel(GetLeftCornerMap()); UnderPanel = new PluginPanel(GetUnderCornerMap()); var debParseFile = new DebugInformation("Parse files", false); debClearCache = new DebugInformation("Clear cache", false); // Core.DebugInformations.Add(debParseFile); /*Area.OnAreaChange += controller => * { * * debParseFile.TickAction(() => * { * Files.LoadFiles(); * }); * };*/ debDeltaTime = Core.DebugInformations.FirstOrDefault(x => x.Name == "Delta Time"); NativeMethods.LogError = _settings.LogReadMemoryError; _settings.LogReadMemoryError.OnValueChanged += (obj, b) => NativeMethods.LogError = _settings.LogReadMemoryError; LeftCornerMap = new TimeCache <Vector2>(GetLeftCornerMap, 500); UnderCornerMap = new TimeCache <Vector2>(GetUnderCornerMap, 500); eIsForegroundChanged += b => { if (b) { Core.MainRunner.ResumeCoroutines(Core.MainRunner.Coroutines); Core.ParallelRunner.ResumeCoroutines(Core.ParallelRunner.Coroutines); } else { Core.MainRunner.PauseCoroutines(Core.MainRunner.Coroutines); Core.ParallelRunner.PauseCoroutines(Core.ParallelRunner.Coroutines); } // DebugWindow.LogMsg($"Foreground: {b}"); }; _settings.RefreshArea.OnPressed += () => { Area.ForceRefreshArea(_settings.AreaChangeMultiThread); }; Area.RefreshState(); EntityListWrapper.StartWork(); Initialized = true; }
public MenuWindow(Core core, SettingsContainer settingsContainer, Dictionary <string, FontContainer> fonts) { this.core = core; _settingsContainer = settingsContainer; _CoreSettings = settingsContainer.CoreSettings; Fonts = fonts; themeEditor = new ThemeEditor(_CoreSettings); /*Input.RegisterKey(Keys.F12); * Input.ReleaseKey += (sender, keys) => * { * if (keys== SettingsCoreSettings.MainMenuKeyToggle.Value) * { * Enable = !Enable; * } * };*/ CoreSettingsDrawers = new List <ISettingsHolder>(); SettingsParser.Parse(_CoreSettings, CoreSettingsDrawers); Selected = CoreSettings; CoreSettings = () => { foreach (var drawer in CoreSettingsDrawers) { drawer.Draw(); } }; _index = -1; Selected = CoreSettings; Core.DebugInformations.CollectionChanged += OnDebugInformationsOnCollectionChanged; debugInformation = new DebugInformation("DebugWindow", false); OpenWindow = Windows.MainDebugs; WindowsName = Enum.GetValues(typeof(Windows)); OnWindowChange += () => { MoreInformation = null; selectedName = ""; }; Input.RegisterKey(_CoreSettings.MainMenuKeyToggle); _CoreSettings.MainMenuKeyToggle.OnValueChanged += () => { Input.RegisterKey(_CoreSettings.MainMenuKeyToggle); }; _CoreSettings.Enable.OnValueChanged += (sender, b) => { if (!_CoreSettings.Enable) { try { _settingsContainer.SaveCoreSettings(); foreach (var plugin in core.pluginManager.Plugins) { try { _settingsContainer.SaveSettings(plugin.Plugin); } catch (Exception e) { DebugWindow.LogError($"SaveSettings for plugin error: {e}"); } } } catch (Exception e) { DebugWindow.LogError($"SaveSettings error: {e}"); } } }; }
public static void Parse(ISettings settings, List <ISettingsHolder> draws, int id = -1) { if (settings == null) { DebugWindow.LogError("Cant parse null settings."); return; } var props = settings.GetType().GetProperties(); foreach (var property in props) { if (property.GetCustomAttribute <IgnoreMenuAttribute>() != null) { continue; } var menuAttribute = property.GetCustomAttribute <MenuAttribute>(); var isSettings = property.PropertyType.GetInterfaces().ContainsF(typeof(ISettings)); if (property.Name == "Enable" && menuAttribute == null) { continue; } if (menuAttribute == null) { menuAttribute = new MenuAttribute(Regex.Replace(property.Name, "(\\B[A-Z])", " $1")); } var holder = new SettingsHolder { Name = menuAttribute.MenuName, Tooltip = menuAttribute.Tooltip, ID = menuAttribute.index == -1 ? MathHepler.Randomizer.Next(int.MaxValue) : menuAttribute.index }; if (isSettings) { var innerSettings = (ISettings)property.GetValue(settings); if (menuAttribute.index != -1) { holder.Type = HolderChildType.Tab; draws.Add(holder); Parse(innerSettings, draws, menuAttribute.index); var parent = GetAllDrawers(draws).Find(x => x.ID == menuAttribute.parentIndex); parent?.Children.Add(holder); } else { Parse(innerSettings, draws); } continue; } var type = property.GetValue(settings); if (menuAttribute.parentIndex != -1) { var parent = GetAllDrawers(draws).Find(x => x.ID == menuAttribute.parentIndex); parent?.Children.Add(holder); } else if (id != -1) { var parent = GetAllDrawers(draws).Find(x => x.ID == id); parent?.Children.Add(holder); } else { draws.Add(holder); } switch (type) { case ButtonNode n: holder.DrawDelegate = () => { if (ImGui.Button(holder.Unique)) { n.OnPressed(); } }; break; case EmptyNode n: break; case HotkeyNode n: holder.DrawDelegate = () => { var holderName = $"{holder.Name} {n.Value}##{n.Value}"; var open = true; if (ImGui.Button(holderName)) { ImGui.OpenPopup(holderName); open = true; } if (ImGui.BeginPopupModal(holderName, ref open, (ImGuiWindowFlags)35)) { if (Input.GetKeyState(Keys.Escape)) { ImGui.CloseCurrentPopup(); ImGui.EndPopup(); return; } foreach (var key in Enum.GetValues(typeof(Keys))) { var keyState = Input.GetKeyState((Keys)key); if (keyState) { n.Value = (Keys)key; ImGui.CloseCurrentPopup(); break; } } ImGui.Text($" Press new key to change '{n.Value}' or Esc for exit."); ImGui.EndPopup(); } }; break; case ToggleNode n: holder.DrawDelegate = () => { var value = n.Value; ImGui.Checkbox(holder.Unique, ref value); n.Value = value; }; break; case ColorNode n: holder.DrawDelegate = () => { var vector4 = n.Value.ToVector4().ToVector4Num(); if (ImGui.ColorEdit4(holder.Unique, ref vector4, ImGuiColorEditFlags.AlphaBar | ImGuiColorEditFlags.NoInputs | ImGuiColorEditFlags.AlphaPreviewHalf)) { n.Value = vector4.ToSharpColor(); } }; break; case ListNode n: holder.DrawDelegate = () => { if (ImGui.BeginCombo(holder.Unique, n.Value)) { foreach (var t in n.Values) { if (ImGui.Selectable(t)) { n.Value = t; ImGui.EndCombo(); return; } } ImGui.EndCombo(); } }; break; case FileNode n: holder.DrawDelegate = () => { if (ImGui.TreeNode(holder.Unique)) { var selected = n.Value; if (ImGui.BeginChildFrame(1, new Vector2(0, 300))) { var di = new DirectoryInfo("config"); if (di.Exists) { foreach (var file in di.GetFiles()) { if (ImGui.Selectable(file.Name, selected == file.FullName)) { n.Value = file.FullName; } } } ImGui.EndChildFrame(); } ImGui.TreePop(); } }; break; case RangeNode <int> n: holder.DrawDelegate = () => { var r = n.Value; ImGui.SliderInt(holder.Unique, ref r, n.Min, n.Max); n.Value = r; }; break; case RangeNode <float> n: holder.DrawDelegate = () => { var r = n.Value; ImGui.SliderFloat(holder.Unique, ref r, n.Min, n.Max); n.Value = r; }; break; case RangeNode <long> n: holder.DrawDelegate = () => { var r = (int)n.Value; ImGui.SliderInt(holder.Unique, ref r, (int)n.Min, (int)n.Max); n.Value = r; }; break; case RangeNode <Vector2> n: holder.DrawDelegate = () => { var vect = n.Value; ImGui.SliderFloat2(holder.Unique, ref vect, n.Min.X, n.Max.X); n.Value = vect; }; break; default: Core.Logger.Warning($"{type} not supported for menu now. Ask developers to add this type."); break; } } }
public MenuWindow(Core core, SettingsContainer settingsContainer, Dictionary <string, FontContainer> fonts, ref VersionChecker versionChecker) { this.Core = core; _settingsContainer = settingsContainer; CoreSettings = settingsContainer.CoreSettings; Fonts = fonts; CoreSettingsDrawers = new List <ISettingsHolder>(); SettingsParser.Parse(CoreSettings, CoreSettingsDrawers); PluginsUpdateSettings = settingsContainer.PluginsUpdateSettings; PluginsUpdateSettingsDrawers = new List <ISettingsHolder>(); SettingsParser.Parse(PluginsUpdateSettings, PluginsUpdateSettingsDrawers); VersionChecker = versionChecker; Selected = CoreSettingsAction; CoreSettingsAction = () => { foreach (var drawer in CoreSettingsDrawers) { drawer.Draw(); } }; _index = -1; Selected = CoreSettingsAction; Core.DebugInformations.CollectionChanged += OnDebugInformationsOnCollectionChanged; debugInformation = new DebugInformation("DebugWindow", false); OpenWindow = Windows.MainDebugs; WindowsName = Enum.GetValues(typeof(Windows)); OnWindowChange += () => { MoreInformation = null; selectedName = ""; }; Input.RegisterKey(CoreSettings.MainMenuKeyToggle); CoreSettings.MainMenuKeyToggle.OnValueChanged += () => { Input.RegisterKey(CoreSettings.MainMenuKeyToggle); }; CoreSettings.Enable.OnValueChanged += (sender, b) => { if (!CoreSettings.Enable) { try { _settingsContainer.SaveCoreSettings(); try { _settingsContainer.SavePluginAutoUpdateSettings(); } catch (Exception e) { DebugWindow.LogError($"SaveSettings for PluginAutoUpdate error: {e}"); } foreach (var plugin in core.pluginManager.Plugins) { try { _settingsContainer.SaveSettings(plugin.Plugin); } catch (Exception e) { DebugWindow.LogError($"SaveSettings for plugin error: {e}"); } } } catch (Exception e) { DebugWindow.LogError($"SaveSettings error: {e}"); } } }; }
public static void Parse(ISettings settings, List <ISettingsHolder> draws, int id = -1) { if (settings == null) { DebugWindow.LogError("Cant parse null settings."); return; } var props = settings.GetType().GetProperties(); foreach (var property in props) { if (property.GetCustomAttribute <IgnoreMenuAttribute>() != null) { continue; } var menuAttribute = property.GetCustomAttribute <MenuAttribute>(); var isSettings = property.PropertyType.GetInterfaces().ContainsF(typeof(ISettings)); if (property.Name == "Enable" && menuAttribute == null) { continue; } if (menuAttribute == null) { menuAttribute = new MenuAttribute(Regex.Replace(property.Name, "(\\B[A-Z])", " $1")); } var holder = new SettingsHolder { Name = menuAttribute.MenuName, Tooltip = menuAttribute.Tooltip, ID = menuAttribute.index == -1 ? MathHepler.Randomizer.Next(int.MaxValue) : menuAttribute.index }; if (isSettings) { HandleSubSettings(settings, draws, property, menuAttribute, holder); continue; } if (IsISettingsList(property, settings)) { IList list = property.GetValue(settings) as IList; foreach (var item in list) { Parse(item as ISettings, draws); } continue; } if (menuAttribute.parentIndex != -1) { var parent = GetAllDrawers(draws).Find(x => x.ID == menuAttribute.parentIndex); parent?.Children.Add(holder); } else if (id != -1) { var parent = GetAllDrawers(draws).Find(x => x.ID == id); parent?.Children.Add(holder); } else { draws.Add(holder); } var type = property.GetValue(settings); HandleType(menuAttribute, holder, type); } }
public void LogError(string msg, float time = 1f) { DebugWindow.LogError(msg, time); }
private static void Parse(ISettings settings, List <ISettingsHolder> draws, int id, ref int nextAvailableKey) { if (settings == null) { DebugWindow.LogError("Cant parse null settings."); return; } var props = settings.GetType().GetProperties(); foreach (var property in props) { if (property.GetCustomAttribute <IgnoreMenuAttribute>() != null) { continue; } var menuAttribute = property.GetCustomAttribute <MenuAttribute>(); if (property.Name == "Enable" && menuAttribute == null) { continue; } menuAttribute ??= new MenuAttribute(Regex.Replace(property.Name, "(\\B[A-Z])", " $1")); var holder = new SettingsHolder { Name = menuAttribute.MenuName, Tooltip = menuAttribute.Tooltip, ID = menuAttribute.index == -1 ? nextAvailableKey-- : menuAttribute.index }; if (property.PropertyType.GetInterfaces().ContainsF(typeof(ISettings))) { var innerSettings = (ISettings)property.GetValue(settings); if (menuAttribute.index == -1) { Parse(innerSettings, draws, id, ref nextAvailableKey); continue; } holder.Type = HolderChildType.Tab; draws.Add(holder); Parse(innerSettings, draws, menuAttribute.index, ref nextAvailableKey); var parent = GetAllDrawers(draws).Find(x => x.ID == menuAttribute.parentIndex); parent?.Children.Add(holder); continue; } if (IsISettingsList(property, settings)) { if (!(property.GetValue(settings) is IList list)) { continue; } foreach (var item in list) { Parse(item as ISettings, draws, id, ref nextAvailableKey); } continue; } if (menuAttribute.parentIndex != -1) { var parent = GetAllDrawers(draws).Find(x => x.ID == menuAttribute.parentIndex); if (parent != null) { // TODO - Check if the new setting index collides with any children. parent.Children.Add(holder); } else { DebugWindow.LogDebug( $"SettingsParser => ParentIndex used before created. [Menu(\"{menuAttribute.MenuName}\", ..., {menuAttribute.parentIndex})] added as a top-level setting."); draws.Add(holder); } } else if (id != -1) { var parent = GetAllDrawers(draws).Find(x => x.ID == id); if (parent != null) { // debug log spam during startup due to HealthBars, temporarly disabled for now //DebugWindow.LogDebug( // $"SettingsParser => Index collision. '[Menu(\"{menuAttribute.MenuName}\", ..., {id}, ...)] added as sub-setting of \"{parent.Name}\"."); parent.Children.Add(holder); } else { draws.Add(holder); } } else { draws.Add(holder); } var type = property.GetValue(settings); HandleType(holder, type, property.ToString()); } }