| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- using Content.Shared.Administration;
- using Content.Shared.Chemistry.Components;
- using Content.Shared.Chemistry.Reagent;
- using Robust.Client.AutoGenerated;
- using Robust.Client.Console;
- using Robust.Client.Timing;
- using Robust.Client.UserInterface.Controls;
- using Robust.Client.UserInterface.CustomControls;
- using Robust.Client.UserInterface.XAML;
- using Robust.Shared.Timing;
- namespace Content.Client.Administration.UI.ManageSolutions
- {
- /// <summary>
- /// A simple window that displays solutions and their contained reagents. Allows you to edit the reagent quantities and add new reagents.
- /// </summary>
- [GenerateTypedNameReferences]
- public sealed partial class EditSolutionsWindow : DefaultWindow
- {
- [Dependency] private readonly IClientConsoleHost _consoleHost = default!;
- [Dependency] private readonly IEntityManager _entityManager = default!;
- [Dependency] private readonly IClientGameTiming _timing = default!;
- private NetEntity _target = NetEntity.Invalid;
- private string? _selectedSolution;
- private AddReagentWindow? _addReagentWindow;
- private Dictionary<string, EntityUid>? _solutions;
- private EditSolutionsEuiState? _nextState;
- public EditSolutionsWindow()
- {
- IoCManager.InjectDependencies(this);
- RobustXamlLoader.Load(this);
- SolutionOption.OnItemSelected += SolutionSelected;
- AddButton.OnPressed += OpenAddReagentWindow;
- }
- public override void Close()
- {
- base.Close();
- _addReagentWindow?.Close();
- _addReagentWindow?.Dispose();
- }
- public void SetTargetEntity(NetEntity target)
- {
- _target = target;
- var uid = _entityManager.GetEntity(target);
- var targetName = _entityManager.EntityExists(uid)
- ? _entityManager.GetComponent<MetaDataComponent>(uid).EntityName
- : string.Empty;
- Title = Loc.GetString("admin-solutions-window-title", ("targetName", targetName));
- }
- /// <summary>
- /// Update the capacity label and re-create the reagent list
- /// </summary>
- public void UpdateReagents()
- {
- ReagentList.DisposeAllChildren();
- if (_selectedSolution == null || _solutions == null)
- return;
- if (!_solutions.TryGetValue(_selectedSolution, out var solutionId) ||
- !_entityManager.TryGetComponent(solutionId, out SolutionComponent? solutionComp))
- return;
- var solution = solutionComp.Solution;
- UpdateVolumeBox(solution);
- UpdateThermalBox(solution);
- foreach (var reagent in solution)
- {
- AddReagentEntry(reagent);
- }
- }
- /// <summary>
- /// Updates the entry displaying the current and maximum volume of the selected solution.
- /// </summary>
- /// <param name="solution">The selected solution.</param>
- private void UpdateVolumeBox(Solution solution)
- {
- VolumeBox.DisposeAllChildren();
- var volumeLabel = new Label();
- volumeLabel.HorizontalExpand = true;
- volumeLabel.Margin = new Thickness(0, 4);
- volumeLabel.Text = Loc.GetString("admin-solutions-window-volume-label",
- ("currentVolume", solution.Volume),
- ("maxVolume", solution.MaxVolume));
- var capacityBox = new BoxContainer();
- capacityBox.Orientation = BoxContainer.LayoutOrientation.Horizontal;
- capacityBox.HorizontalExpand = true;
- capacityBox.Margin = new Thickness(0, 4);
- var capacityLabel = new Label();
- capacityLabel.HorizontalExpand = true;
- capacityLabel.Margin = new Thickness(0, 1);
- capacityLabel.Text = Loc.GetString("admin-solutions-window-capacity-label");
- var capacitySpin = new FloatSpinBox(1, 2);
- capacitySpin.HorizontalExpand = true;
- capacitySpin.Margin = new Thickness(0, 1);
- capacitySpin.Value = (float) solution.MaxVolume;
- capacitySpin.OnValueChanged += SetCapacity;
- capacityBox.AddChild(capacityLabel);
- capacityBox.AddChild(capacitySpin);
- VolumeBox.AddChild(volumeLabel);
- VolumeBox.AddChild(capacityBox);
- }
- /// <summary>
- /// Updates the entry displaying the current specific heat, heat capacity, temperature, and thermal energy
- /// of the selected solution.
- /// </summary>
- /// <param name="solution">The selected solution.</param>
- private void UpdateThermalBox(Solution solution)
- {
- ThermalBox.DisposeAllChildren();
- var heatCap = solution.GetHeatCapacity(null);
- var specificHeatLabel = new Label();
- specificHeatLabel.HorizontalExpand = true;
- specificHeatLabel.Margin = new Thickness(0, 1);
- specificHeatLabel.Text = Loc.GetString("admin-solutions-window-specific-heat-label", ("specificHeat", heatCap.ToString("G3")));
- var heatCapacityLabel = new Label();
- heatCapacityLabel.HorizontalExpand = true;
- heatCapacityLabel.Margin = new Thickness(0, 1);
- heatCapacityLabel.Text = Loc.GetString("admin-solutions-window-heat-capacity-label", ("heatCapacity", (heatCap/solution.Volume.Float()).ToString("G3")));
- // Temperature entry:
- var temperatureBox = new BoxContainer();
- temperatureBox.Orientation = BoxContainer.LayoutOrientation.Horizontal;
- temperatureBox.HorizontalExpand = true;
- temperatureBox.Margin = new Thickness(0, 1);
- var temperatureLabel = new Label();
- temperatureLabel.HorizontalExpand = true;
- temperatureLabel.Margin = new Thickness(0, 1);
- temperatureLabel.Text = Loc.GetString("admin-solutions-window-temperature-label");
- var temperatureSpin = new FloatSpinBox(1, 2);
- temperatureSpin.HorizontalExpand = true;
- temperatureSpin.Margin = new Thickness(0, 1);
- temperatureSpin.Value = solution.Temperature;
- temperatureSpin.OnValueChanged += SetTemperature;
- temperatureBox.AddChild(temperatureLabel);
- temperatureBox.AddChild(temperatureSpin);
- // Thermal energy entry:
- var thermalEnergyBox = new BoxContainer();
- thermalEnergyBox.Orientation = BoxContainer.LayoutOrientation.Horizontal;
- thermalEnergyBox.HorizontalExpand = true;
- thermalEnergyBox.Margin = new Thickness(0, 1);
- var thermalEnergyLabel = new Label();
- thermalEnergyLabel.HorizontalExpand = true;
- thermalEnergyLabel.Margin = new Thickness(0, 1);
- thermalEnergyLabel.Text = Loc.GetString("admin-solutions-window-thermal-energy-label");
- var thermalEnergySpin = new FloatSpinBox(1, 2);
- thermalEnergySpin.HorizontalExpand = true;
- thermalEnergySpin.Margin = new Thickness(0, 1);
- thermalEnergySpin.Value = solution.Temperature * heatCap;
- thermalEnergySpin.OnValueChanged += SetThermalEnergy;
- thermalEnergyBox.AddChild(thermalEnergyLabel);
- thermalEnergyBox.AddChild(thermalEnergySpin);
- ThermalBox.AddChild(specificHeatLabel);
- ThermalBox.AddChild(heatCapacityLabel);
- ThermalBox.AddChild(temperatureBox);
- ThermalBox.AddChild(thermalEnergyBox);
- }
- /// <summary>
- /// Add a single reagent entry to the list
- /// </summary>
- private void AddReagentEntry(ReagentQuantity reagentQuantity)
- {
- var box = new BoxContainer();
- var spin = new FloatSpinBox(1, 2);
- spin.Value = reagentQuantity.Quantity.Float();
- spin.OnValueChanged += (args) => SetReagent(args, reagentQuantity.Reagent.Prototype);
- spin.HorizontalExpand = true;
- box.AddChild(new Label() { Text = reagentQuantity.Reagent.Prototype , HorizontalExpand = true});
- box.AddChild(spin);
- ReagentList.AddChild(box);
- }
- /// <summary>
- /// Execute a command to modify the reagents in the solution.
- /// </summary>
- private void SetReagent(FloatSpinBox.FloatSpinBoxEventArgs args, string prototype)
- {
- if (_solutions == null || _selectedSolution == null ||
- !_solutions.TryGetValue(_selectedSolution, out var solutionId) ||
- !_entityManager.TryGetComponent(solutionId, out SolutionComponent? solutionComp))
- return;
- var solution = solutionComp.Solution;
- var current = solution.GetTotalPrototypeQuantity(prototype);
- var delta = args.Value - current.Float();
- if (MathF.Abs(delta) < 0.01)
- return;
- var command = $"addreagent {_target} {_selectedSolution} {prototype} {delta}";
- _consoleHost.ExecuteCommand(command);
- }
- private void SetCapacity(FloatSpinBox.FloatSpinBoxEventArgs args)
- {
- if (_solutions == null || _selectedSolution == null)
- return;
- var command = $"setsolutioncapacity {_target} {_selectedSolution} {args.Value}";
- _consoleHost.ExecuteCommand(command);
- }
- /// <summary>
- /// Sets the temperature of the selected solution to a value.
- /// </summary>
- /// <param name="args">An argument struct containing the value to set the temperature to.</param>
- private void SetTemperature(FloatSpinBox.FloatSpinBoxEventArgs args)
- {
- if (_solutions == null || _selectedSolution == null)
- return;
- var command = $"setsolutiontemperature {_target} {_selectedSolution} {args.Value}";
- _consoleHost.ExecuteCommand(command);
- }
- /// <summary>
- /// Sets the thermal energy of the selected solution to a value.
- /// </summary>
- /// <param name="args">An argument struct containing the value to set the thermal energy to.</param>
- private void SetThermalEnergy(FloatSpinBox.FloatSpinBoxEventArgs args)
- {
- if (_solutions == null || _selectedSolution == null)
- return;
- var command = $"setsolutionthermalenergy {_target} {_selectedSolution} {args.Value}";
- _consoleHost.ExecuteCommand(command);
- }
- /// <summary>
- /// Open a new window that has options to add new reagents to the solution.
- /// </summary>
- private void OpenAddReagentWindow(BaseButton.ButtonEventArgs obj)
- {
- if (string.IsNullOrEmpty(_selectedSolution))
- return;
- _addReagentWindow?.Close();
- _addReagentWindow?.Dispose();
- _addReagentWindow = new AddReagentWindow(_target, _selectedSolution);
- _addReagentWindow.OpenCentered();
- }
- /// <summary>
- /// When a new solution is selected, set _selectedSolution and update the reagent list.
- /// </summary>
- private void SolutionSelected(OptionButton.ItemSelectedEventArgs args)
- {
- SolutionOption.SelectId(args.Id);
- _selectedSolution = (string?) SolutionOption.SelectedMetadata;
- _addReagentWindow?.UpdateSolution(_selectedSolution);
- UpdateReagents();
- }
- /// <summary>
- /// Update the solution options.
- /// </summary>
- public void UpdateSolutions(List<(string, NetEntity)>? solutions)
- {
- SolutionOption.Clear();
- if (solutions is { Count: > 0 })
- {
- if (_solutions is { Count: > 0 })
- _solutions.Clear();
- else
- _solutions = new(solutions.Count);
- foreach (var (name, netSolution) in solutions)
- {
- if (_entityManager.TryGetEntity(netSolution, out var solution))
- _solutions.Add(name, solution.Value);
- }
- }
- else
- _solutions = null;
- if (_solutions == null)
- return;
- int i = 0;
- int selectedIndex = 0; // Default to the first solution if none are found.
- foreach (var (name, _) in _solutions)
- {
- SolutionOption.AddItem(name, i);
- SolutionOption.SetItemMetadata(i, name);
- if (name == _selectedSolution)
- selectedIndex = i;
- i++;
- }
- if (SolutionOption.ItemCount == 0)
- {
- // No applicable solutions
- Close();
- Dispose();
- return;
- }
- SolutionOption.Select(selectedIndex);
- _selectedSolution = (string?) SolutionOption.SelectedMetadata;
- }
- protected override void FrameUpdate(FrameEventArgs args)
- {
- // TODO: THIS IS FUCKING TERRIBLE.
- // Ok so the problem is that this shouldn't be via an EUI at all. Why?
- // The EUI update notification comes in *before* the game state it updates from.
- // So the UI doesn't update properly. Heck.
- // I didn't wanna completely rewrite this thing to work properly so instead you get terrible hacks.
- if (_nextState != null && _timing.LastRealTick >= _nextState.Tick)
- {
- SetTargetEntity(_nextState.Target);
- UpdateSolutions(_nextState.Solutions);
- UpdateReagents();
- _nextState = null;
- }
- }
- public void SetState(EditSolutionsEuiState state)
- {
- _nextState = state;
- }
- }
- }
|