Files
NebulaLauncher/Nebula.Launcher/ViewModels/Pages/ConfigurationViewModel.cs

406 lines
12 KiB
C#
Raw Normal View History

2025-05-10 19:19:30 +03:00
using System;
2025-06-18 21:36:50 +03:00
using System.Collections;
2025-05-10 19:19:30 +03:00
using System.Collections.Generic;
using System.Collections.ObjectModel;
2025-06-18 21:36:50 +03:00
using System.Globalization;
2025-06-19 21:12:42 +03:00
using System.IO;
using System.IO.Compression;
2025-05-10 19:19:30 +03:00
using System.Linq;
2025-06-18 21:36:50 +03:00
using System.Reflection;
2025-07-02 21:32:51 +03:00
using System.Threading;
using System.Threading.Tasks;
2025-06-18 21:36:50 +03:00
using Avalonia;
using Avalonia.Controls;
using Avalonia.Layout;
2025-06-19 21:12:42 +03:00
using Nebula.Launcher.Services;
2025-07-02 21:32:51 +03:00
using Nebula.Launcher.ViewModels.Popup;
2025-05-10 19:19:30 +03:00
using Nebula.Launcher.Views.Pages;
2025-06-18 21:36:50 +03:00
using Nebula.Shared;
2025-05-10 19:19:30 +03:00
using Nebula.Shared.Services;
2025-07-02 21:32:51 +03:00
using Nebula.Shared.ViewHelper;
2025-05-10 19:19:30 +03:00
namespace Nebula.Launcher.ViewModels.Pages;
[ViewModelRegister(typeof(ConfigurationView))]
[ConstructGenerator]
2025-06-18 21:36:50 +03:00
public partial class ConfigurationViewModel : ViewModelBase
2025-05-10 19:19:30 +03:00
{
2025-06-18 21:36:50 +03:00
public ObservableCollection<IConfigControl> ConfigurationVerbose { get; } = new();
2025-05-10 19:19:30 +03:00
[GenerateProperty] private ConfigurationService ConfigurationService { get; } = default!;
2025-06-19 21:12:42 +03:00
[GenerateProperty] private PopupMessageService PopupService { get; } = default!;
[GenerateProperty] private FileService FileService { get; set; } = default!;
2025-07-02 21:32:51 +03:00
[GenerateProperty] private ContentService ContentService { get; set; } = default!;
[GenerateProperty] private CancellationService CancellationService { get; set; } = default!;
[GenerateProperty] private ViewHelperService ViewHelperService { get; set; } = default!;
2025-05-10 19:19:30 +03:00
2025-07-03 12:17:15 +03:00
private readonly List<(object, Type)> _conVarList = new();
2025-05-10 19:19:30 +03:00
2025-06-18 21:36:50 +03:00
public void AddCvarConf<T>(ConVar<T> cvar)
2025-05-10 19:19:30 +03:00
{
2025-06-18 21:36:50 +03:00
ConfigurationVerbose.Add(
2025-07-02 21:32:51 +03:00
ConfigControlHelper.GetConfigControl(cvar.Name, ConfigurationService.GetConfigValue(cvar)!));
2025-07-03 12:17:15 +03:00
_conVarList.Add((cvar, cvar.Type));
2025-05-10 19:19:30 +03:00
}
public void InvokeUpdateConfiguration()
{
2025-06-18 21:36:50 +03:00
for (int i = 0; i < ConfigurationVerbose.Count; i++)
2025-05-10 19:19:30 +03:00
{
2025-06-18 21:36:50 +03:00
var conVarControl = ConfigurationVerbose[i];
if(!conVarControl.Dirty)
continue;
2025-07-03 12:17:15 +03:00
var conVar = _conVarList[i];
2025-06-18 21:36:50 +03:00
var methodInfo = ConfigurationService.GetType().GetMethod("SetConfigValue")!.MakeGenericMethod(conVar.Item2);
methodInfo.Invoke(ConfigurationService, [conVar.Item1, conVarControl.GetValue()]);
2025-05-10 19:19:30 +03:00
}
}
2025-06-19 21:12:42 +03:00
public void ResetConfig()
{
2025-07-03 12:17:15 +03:00
foreach (var conVar in _conVarList)
2025-06-19 21:12:42 +03:00
{
var methodInfo = ConfigurationService.GetType().GetMethod("SetConfigValue")!.MakeGenericMethod(conVar.Item2);
methodInfo.Invoke(ConfigurationService, [conVar.Item1, null]);
}
2025-07-03 12:17:15 +03:00
_conVarList.Clear();
2025-06-19 21:12:42 +03:00
ConfigurationVerbose.Clear();
InitConfiguration();
PopupService.Popup("Configuration has been reset.");
}
public void OpenDataFolder()
{
ExplorerHelper.OpenFolder(FileService.RootPath);
}
public void ExportLogs()
{
var logPath = Path.Join(FileService.RootPath, "log");
var path = Path.Combine(Path.GetTempPath(), "tempThink"+Path.GetRandomFileName());
Directory.CreateDirectory(path);
ZipFile.CreateFromDirectory(logPath, Path.Join(path, DateTime.Now.ToString("yyyy-MM-dd") + ".zip"));
ExplorerHelper.OpenFolder(path);
}
2025-07-02 21:32:51 +03:00
public void RemoveAllContent()
{
Task.Run(() =>
{
using var loader = ViewHelperService.GetViewModel<LoadingContextViewModel>();
loader.LoadingName = "Removing content";
PopupService.Popup(loader);
ContentService.RemoveAllContent(loader, CancellationService.Token);
});
}
2025-06-19 21:12:42 +03:00
private void InitConfiguration()
{
2025-06-18 21:36:50 +03:00
AddCvarConf(LauncherConVar.ILSpyUrl);
AddCvarConf(LauncherConVar.Hub);
AddCvarConf(LauncherConVar.AuthServers);
AddCvarConf(CurrentConVar.EngineManifestUrl);
AddCvarConf(CurrentConVar.RobustAssemblyName);
AddCvarConf(CurrentConVar.ManifestDownloadProtocolVersion);
2025-05-10 19:19:30 +03:00
}
2025-06-19 21:12:42 +03:00
protected override void InitialiseInDesignMode()
{
InitConfiguration();
}
2025-05-10 19:19:30 +03:00
protected override void Initialise()
{
2025-06-19 21:12:42 +03:00
InitConfiguration();
2025-05-10 19:19:30 +03:00
}
2025-06-18 21:36:50 +03:00
}
2025-05-10 19:19:30 +03:00
2025-06-18 21:36:50 +03:00
public static class ConfigControlHelper{
public static IConfigControl GetConfigControl(string name,object value)
2025-05-10 19:19:30 +03:00
{
2025-06-18 21:36:50 +03:00
switch (value)
{
case string stringValue:
return new StringUnitConfigControl(name, stringValue);
case int intValue:
return new IntUnitConfigControl(name, intValue);
case float floatValue:
return new FloatUnitConfigControl(name, floatValue);
}
var valueType = value.GetType();
if (valueType.IsArray)
return new ArrayUnitConfigControl(name, value);
return new ComplexUnitConfigControl(name, value);
2025-05-10 19:19:30 +03:00
}
2025-06-18 21:36:50 +03:00
public static object? CreateDefaultValue(Type type)
2025-05-10 19:19:30 +03:00
{
2025-06-18 21:36:50 +03:00
if(type.IsValueType)
return Activator.CreateInstance(type);
var ctor = type.GetConstructors().First();
var parameters = ctor.GetParameters()
.Select(p => CreateDefaultValue(p.ParameterType))
.ToArray();
return ctor.Invoke(parameters);
2025-05-10 19:19:30 +03:00
}
}
2025-06-19 21:12:42 +03:00
public sealed class ComplexUnitConfigControl : Border, IConfigControl
2025-05-10 19:19:30 +03:00
{
2025-06-19 21:12:42 +03:00
private readonly List<(PropertyInfo, IConfigControl)> _units = [];
2025-06-18 21:36:50 +03:00
private Type _objectType = typeof(object);
2025-06-19 21:12:42 +03:00
private readonly StackPanel _panel = new();
2025-06-18 21:36:50 +03:00
public string ConfigName { get; }
public bool Dirty => _units.Any(dirty => dirty.Item2.Dirty);
2025-05-10 19:19:30 +03:00
2025-06-18 21:36:50 +03:00
public ComplexUnitConfigControl(string name, object obj)
2025-05-10 19:19:30 +03:00
{
2025-06-19 21:12:42 +03:00
Classes.Add("ConfigBorder");
_panel.Orientation = Orientation.Vertical;
_panel.Spacing = 4f;
2025-06-18 21:36:50 +03:00
ConfigName = name;
2025-06-19 21:12:42 +03:00
Child = _panel;
2025-06-18 21:36:50 +03:00
SetValue(obj);
2025-05-10 19:19:30 +03:00
}
2025-06-18 21:36:50 +03:00
public void SetValue(object value)
{
_units.Clear();
2025-06-19 21:12:42 +03:00
_panel.Children.Clear();
2025-06-18 21:36:50 +03:00
_objectType = value.GetType();
2025-06-19 21:12:42 +03:00
_panel.Children.Add(new Label()
2025-06-18 21:36:50 +03:00
{
Content = ConfigName
});
foreach (var propInfo in _objectType.GetProperties())
{
if(propInfo.PropertyType.IsInterface)
continue;
var propValue = propInfo.GetValue(value);
var control = ConfigControlHelper.GetConfigControl(propInfo.Name, propValue);
2025-06-19 21:12:42 +03:00
((Control)control).Margin = new Thickness(5);
_panel.Children.Add((Control)control);
2025-06-18 21:36:50 +03:00
_units.Add((propInfo,control));
}
}
2025-05-10 19:19:30 +03:00
2025-06-18 21:36:50 +03:00
public object GetValue()
2025-05-10 19:19:30 +03:00
{
2025-06-18 21:36:50 +03:00
var obj = ConfigControlHelper.CreateDefaultValue(_objectType);
foreach (var (fieldInfo, configControl) in _units)
{
fieldInfo.SetValue(obj, configControl.GetValue());
}
return obj;
2025-05-10 19:19:30 +03:00
}
2025-06-18 21:36:50 +03:00
}
2025-05-10 19:19:30 +03:00
2025-06-19 21:12:42 +03:00
public sealed class ArrayUnitConfigControl : Border, IConfigControl
2025-06-18 21:36:50 +03:00
{
private readonly List<IConfigControl> _itemControls = [];
private readonly StackPanel _itemsPanel = new StackPanel() { Orientation = Orientation.Vertical };
2025-06-23 16:39:30 +03:00
private readonly Button _addButton = new Button() { Content = new Label()
{
Content = "Add Item"
}, Classes = { "ConfigBorder" }};
2025-06-19 21:12:42 +03:00
private readonly int _oldCount;
2025-06-18 21:36:50 +03:00
private readonly Type _elementType;
2025-06-19 21:12:42 +03:00
private readonly StackPanel _panel = new();
2025-06-18 21:36:50 +03:00
public string ConfigName { get; }
2025-06-19 21:12:42 +03:00
public bool Dirty => _itemControls.Any(dirty => dirty.Dirty) || _itemControls.Count != _oldCount;
2025-06-18 21:36:50 +03:00
public ArrayUnitConfigControl(string name, object value)
{
2025-06-19 21:12:42 +03:00
Classes.Add("ConfigBorder");
_elementType = value.GetType().GetElementType()!;
2025-06-18 21:36:50 +03:00
ConfigName = name;
2025-06-19 21:12:42 +03:00
_panel.Orientation = Orientation.Vertical;
_panel.Spacing = 4f;
_itemsPanel.Spacing = 4f;
2025-06-18 21:36:50 +03:00
2025-06-19 21:12:42 +03:00
_panel.Children.Add(new Label { Content = name });
_panel.Children.Add(_itemsPanel);
_panel.Children.Add(_addButton);
2025-06-18 21:36:50 +03:00
2025-06-19 21:12:42 +03:00
_addButton.Click += (_, _) => AddItem(ConfigControlHelper.CreateDefaultValue(_elementType)!);
Child = _panel;
2025-06-18 21:36:50 +03:00
SetValue(value);
2025-06-19 21:12:42 +03:00
_oldCount = _itemControls.Count;
2025-06-18 21:36:50 +03:00
}
private void AddItem(object value)
2025-05-10 19:19:30 +03:00
{
2025-06-18 21:36:50 +03:00
var itemPanel = new StackPanel { Orientation = Orientation.Horizontal, Spacing = 2 };
var control = ConfigControlHelper.GetConfigControl(_itemControls.Count.ToString(), value);
2025-06-23 16:39:30 +03:00
var removeButton = new Button { Content = new Label(){ Content = "Remove" }, Classes = { "ConfigBorder" }};
2025-06-18 21:36:50 +03:00
removeButton.Click += (_, _) =>
{
_itemControls.Remove(control);
_itemsPanel.Children.Remove(itemPanel);
};
2025-06-19 21:12:42 +03:00
((Control)control).Margin = new Thickness(5);
2025-06-18 21:36:50 +03:00
itemPanel.Children.Add((Control)control);
itemPanel.Children.Add(removeButton);
_itemsPanel.Children.Add(itemPanel);
_itemControls.Add(control);
2025-05-10 19:19:30 +03:00
}
2025-06-18 21:36:50 +03:00
public void SetValue(object value)
2025-05-10 19:19:30 +03:00
{
2025-06-18 21:36:50 +03:00
_itemControls.Clear();
_itemsPanel.Children.Clear();
if (value is IEnumerable list)
{
foreach (var item in list)
{
AddItem(item);
}
}
2025-05-10 19:19:30 +03:00
}
2025-06-18 21:36:50 +03:00
public object GetValue()
2025-05-10 19:19:30 +03:00
{
2025-06-18 21:36:50 +03:00
return ConvertArray(_itemControls.Select(c => c.GetValue()).ToArray(), _elementType);
}
public static Array ConvertArray(Array sourceArray, Type targetType)
{
int length = sourceArray.Length;
var newArray = Array.CreateInstance(targetType, length);
for (int i = 0; i < length; i++)
{
var value = sourceArray.GetValue(i);
var converted = Convert.ChangeType(value, targetType);
newArray.SetValue(converted, i);
}
return newArray;
2025-05-10 19:19:30 +03:00
}
}
2025-06-19 21:12:42 +03:00
public abstract class UnitConfigControl<T> : Border, IConfigControl where T : notnull
2025-05-10 19:19:30 +03:00
{
2025-06-19 21:12:42 +03:00
private readonly Label _nameLabel = new();
private readonly TextBox _valueLabel = new();
2025-06-18 21:36:50 +03:00
private string _originalValue;
2025-06-19 21:12:42 +03:00
private StackPanel _panel = new();
2025-06-18 21:36:50 +03:00
2025-06-19 21:12:42 +03:00
public string ConfigName { get; }
2025-06-18 21:36:50 +03:00
2025-06-19 21:12:42 +03:00
public bool Dirty => _originalValue != ConfigValue;
2025-06-18 21:36:50 +03:00
2025-06-19 21:12:42 +03:00
protected string ConfigValue
2025-06-18 21:36:50 +03:00
{
2025-06-19 21:12:42 +03:00
get => _valueLabel.Text ?? string.Empty;
2025-06-18 21:36:50 +03:00
set => _valueLabel.Text = value;
}
public UnitConfigControl(string name, T value)
{
2025-06-19 21:12:42 +03:00
Classes.Add("ConfigBorder");
2025-06-18 21:36:50 +03:00
ConfigName = name;
2025-06-19 21:12:42 +03:00
_panel.Orientation = Orientation.Horizontal;
_panel.Children.Add(_nameLabel);
_panel.Children.Add(_valueLabel);
2025-06-18 21:36:50 +03:00
_nameLabel.Content = name;
_nameLabel.VerticalAlignment = VerticalAlignment.Center;
2025-06-19 21:12:42 +03:00
Child = _panel;
2025-06-18 21:36:50 +03:00
SetConfValue(value);
_originalValue = ConfigValue;
}
public abstract void SetConfValue(T value);
public abstract T GetConfValue();
public void SetValue(object value)
{
SetConfValue((T)value);
}
public object GetValue()
{
return GetConfValue()!;
}
2025-05-10 19:19:30 +03:00
}
2025-06-18 21:36:50 +03:00
public sealed class StringUnitConfigControl(string name, string value) : UnitConfigControl<string>(name, value)
2025-05-10 19:19:30 +03:00
{
2025-06-18 21:36:50 +03:00
public override void SetConfValue(string value)
{
ConfigValue = value;
}
public override string GetConfValue()
{
2025-06-19 21:12:42 +03:00
return ConfigValue;
2025-06-18 21:36:50 +03:00
}
2025-05-10 19:19:30 +03:00
}
2025-06-18 21:36:50 +03:00
public sealed class IntUnitConfigControl(string name, int value) : UnitConfigControl<int>(name, value)
2025-05-10 19:19:30 +03:00
{
2025-06-18 21:36:50 +03:00
public override void SetConfValue(int value)
2025-05-10 19:19:30 +03:00
{
2025-06-18 21:36:50 +03:00
ConfigValue = value.ToString();
2025-05-10 19:19:30 +03:00
}
2025-06-18 21:36:50 +03:00
public override int GetConfValue()
2025-05-10 19:19:30 +03:00
{
2025-06-18 21:36:50 +03:00
return int.Parse(ConfigValue);
2025-05-10 19:19:30 +03:00
}
2025-06-18 21:36:50 +03:00
}
public sealed class FloatUnitConfigControl(string name, float value) : UnitConfigControl<float>(name, value)
{
public CultureInfo CultureInfo = CultureInfo.InvariantCulture;
public override void SetConfValue(float value)
2025-05-10 19:19:30 +03:00
{
2025-06-18 21:36:50 +03:00
ConfigValue = value.ToString(CultureInfo);
2025-05-10 19:19:30 +03:00
}
2025-06-18 21:36:50 +03:00
public override float GetConfValue()
2025-05-10 19:19:30 +03:00
{
2025-06-18 21:36:50 +03:00
return float.Parse(ConfigValue, CultureInfo);
2025-05-10 19:19:30 +03:00
}
2025-06-18 21:36:50 +03:00
}
public interface IConfigControl
{
public string ConfigName { get; }
public bool Dirty {get;}
public abstract void SetValue(object value);
public abstract object GetValue();
2025-05-10 19:19:30 +03:00
}