Cloning Rework (#8972)

Co-authored-by: fishfish458 <fishfish458>
This commit is contained in:
Rane
2022-08-04 00:05:17 -04:00
committed by GitHub
parent 37f9e825ea
commit 2f4849eae1
41 changed files with 928 additions and 1227 deletions

View File

@@ -1,4 +1,4 @@
using System;
using System;
using Content.Shared.Body.Components;
using JetBrains.Annotations;
using Robust.Client.GameObjects;

View File

@@ -1,56 +0,0 @@
using System.Collections.Generic;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Shared.GameObjects;
using static Content.Shared.Cloning.SharedCloningPodComponent;
namespace Content.Client.Cloning.UI
{
[UsedImplicitly]
public sealed class CloningPodBoundUserInterface : BoundUserInterface
{
public CloningPodBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
{
}
private CloningPodWindow? _window;
protected override void Open()
{
base.Open();
_window = new CloningPodWindow(new Dictionary<int, string?>());
_window.OnClose += Close;
_window.CloneButton.OnPressed += _ =>
{
if (_window.SelectedScan != null)
{
SendMessage(new CloningPodUiButtonPressedMessage(UiButton.Clone, (int) _window.SelectedScan));
}
};
_window.EjectButton.OnPressed += _ =>
{
SendMessage(new CloningPodUiButtonPressedMessage(UiButton.Eject, null));
};
_window.OpenCentered();
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
_window?.Populate((CloningPodBoundUserInterfaceState) state);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_window?.Dispose();
}
}
}
}

View File

@@ -1,254 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Timing;
using static Content.Shared.Cloning.SharedCloningPodComponent;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Content.Client.Cloning.UI
{
public sealed class CloningPodWindow : DefaultWindow
{
private Dictionary<int, string?> _scanManager;
private readonly BoxContainer _scanList;
public readonly Button CloneButton;
public readonly Button EjectButton;
private CloningScanButton? _selectedButton;
private readonly Label _progressLabel;
private readonly ProgressBar _cloningProgressBar;
private readonly Label _mindState;
private CloningPodBoundUserInterfaceState? _lastUpdate;
public int? SelectedScan;
public CloningPodWindow(Dictionary<int, string?> scanManager)
{
SetSize = MinSize = (250, 300);
_scanManager = scanManager;
Title = Loc.GetString("cloning-pod-window-title");
Contents.AddChild(new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
Children =
{
new ScrollContainer
{
MinSize = new Vector2(200.0f, 0.0f),
VerticalExpand = true,
Children =
{
(_scanList = new BoxContainer
{
Orientation = LayoutOrientation.Vertical
})
}
},
new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
Children =
{
(CloneButton = new Button
{
Text = Loc.GetString("cloning-pod-clone-button")
})
}
},
(_cloningProgressBar = new ProgressBar
{
MinSize = (200, 20),
MinValue = 0,
MaxValue = 120,
Page = 0,
Value = 0.5f,
Children =
{
(_progressLabel = new Label())
}
}),
(EjectButton = new Button
{
Text = Loc.GetString("cloning-pod-eject-body-button")
}),
new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
Children =
{
new Label()
{
Text = Loc.GetString($"{Loc.GetString("cloning-pod-neural-interface-label")} ")
},
(_mindState = new Label()
{
Text = Loc.GetString("cloning-pod-no-activity-text"),
FontColorOverride = Color.Red
}),
}
}
}
});
BuildCloneList();
}
public void Populate(CloningPodBoundUserInterfaceState state)
{
//Ignore useless updates or we can't interact with the UI
//TODO: come up with a better comparision, probably write a comparator because '.Equals' doesn't work
if (_lastUpdate == null || _lastUpdate.MindIdName.Count != state.MindIdName.Count)
{
_scanManager = state.MindIdName;
BuildCloneList();
}
_lastUpdate = state;
_cloningProgressBar.MaxValue = state.Maximum;
UpdateProgress();
_mindState.Text = Loc.GetString(state.MindPresent ? "cloning-pod-mind-present-text" : "cloning-pod-no-activity-text");
_mindState.FontColorOverride = state.MindPresent ? Color.LimeGreen : Color.Red;
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
UpdateProgress();
}
private void UpdateProgress()
{
if (_lastUpdate == null)
return;
float simulatedProgress = _lastUpdate.Progress;
if (_lastUpdate.Progressing)
{
TimeSpan sinceReference = IoCManager.Resolve<IGameTiming>().CurTime - _lastUpdate.ReferenceTime;
simulatedProgress += (float) sinceReference.TotalSeconds;
simulatedProgress = MathHelper.Clamp(simulatedProgress, 0f, _lastUpdate.Maximum);
}
var percentage = simulatedProgress / _cloningProgressBar.MaxValue * 100;
_progressLabel.Text = $"{percentage:0}%";
_cloningProgressBar.Value = simulatedProgress;
}
private void BuildCloneList()
{
_scanList.RemoveAllChildren();
_selectedButton = null;
foreach (var scan in _scanManager)
{
var button = new CloningScanButton
{
Scan = scan.Value ?? string.Empty,
Id = scan.Key
};
button.ActualButton.OnToggled += OnItemButtonToggled;
var entityLabelText = scan.Value;
button.EntityLabel.Text = entityLabelText;
if (scan.Key == SelectedScan)
{
_selectedButton = button;
_selectedButton.ActualButton.Pressed = true;
}
//TODO: replace with body's face
/*var tex = IconComponent.GetScanIcon(scan, resourceCache);
var rect = button.EntityTextureRect;
if (tex != null)
{
rect.Texture = tex.Default;
}
else
{
rect.Dispose();
}
rect.Dispose();
*/
_scanList.AddChild(button);
}
//TODO: set up sort
//_filteredScans.Sort((a, b) => string.Compare(a.ToString(), b.ToString(), StringComparison.Ordinal));
}
private void OnItemButtonToggled(BaseButton.ButtonToggledEventArgs args)
{
var item = (CloningScanButton) args.Button.Parent!;
if (_selectedButton == item)
{
_selectedButton = null;
SelectedScan = null;
return;
}
else if (_selectedButton != null)
{
_selectedButton.ActualButton.Pressed = false;
}
_selectedButton = null;
SelectedScan = null;
_selectedButton = item;
SelectedScan = item.Id;
}
[DebuggerDisplay("cloningbutton {" + nameof(Index) + "}")]
private sealed class CloningScanButton : Control
{
public string Scan { get; set; } = default!;
public int Id { get; set; }
public Button ActualButton { get; private set; }
public Label EntityLabel { get; private set; }
public TextureRect EntityTextureRect { get; private set; }
public int Index { get; set; }
public CloningScanButton()
{
AddChild(ActualButton = new Button
{
HorizontalExpand = true,
VerticalExpand = true,
ToggleMode = true,
});
AddChild(new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
Children =
{
(EntityTextureRect = new TextureRect
{
MinSize = (32, 32),
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Center,
Stretch = TextureRect.StretchMode.KeepAspectCentered,
CanShrink = true
}),
(EntityLabel = new Label
{
VerticalAlignment = VAlignment.Center,
HorizontalExpand = true,
Text = string.Empty,
ClipText = true
})
}
});
}
}
}
}

View File

@@ -0,0 +1,51 @@
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Content.Shared.Cloning.CloningConsole;
namespace Content.Client.CloningConsole.UI
{
[UsedImplicitly]
public sealed class CloningConsoleBoundUserInterface : BoundUserInterface
{
private CloningConsoleWindow? _window;
public CloningConsoleBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
base.Open();
_window = new CloningConsoleWindow
{
Title = Loc.GetString("cloning-console-window-title")
};
_window.OnClose += Close;
_window.CloneButton.OnPressed += _ => SendMessage(new UiButtonPressedMessage(UiButton.Clone));
_window.EjectButton.OnPressed += _ => SendMessage(new UiButtonPressedMessage(UiButton.Eject));
_window.OpenCentered();
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
_window?.Populate((CloningConsoleBoundUserInterfaceState) state);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
if (_window != null)
{
_window.OnClose -= Close;
_window.CloneButton.OnPressed -= _ => SendMessage(new UiButtonPressedMessage(UiButton.Clone));
_window.EjectButton.OnPressed -= _ => SendMessage(new UiButtonPressedMessage(UiButton.Eject));
}
_window?.Dispose();
}
}
}

View File

@@ -0,0 +1,65 @@
<DefaultWindow xmlns="https://spacestation14.io"
Title="{Loc 'comp-pda-ui-menu-title'}"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
SetSize="400 400"
MinSize="400 400">
<TabContainer Name="MasterTabContainer">
<BoxContainer Name="Scanner"
Orientation="Vertical"
VerticalExpand="True"
HorizontalExpand="True"
MinSize="100 150">
<PanelContainer VerticalExpand="True" StyleClasses="Inset">
<BoxContainer Name="GeneticScannerContents" Margin="5 5 5 5" Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True">
<Label HorizontalAlignment="Center" Text="{Loc 'cloning-console-window-scanner-details-label'}" />
<BoxContainer Orientation="Horizontal" VerticalExpand="True" HorizontalExpand="True">
<RichTextLabel Name="ScannerInfoLabel"
Access="Public"
HorizontalExpand="True" />
<Button Name="CloneButton"
Access="Public"
Text="{Loc 'cloning-console-window-clone-button-text'}"
HorizontalAlignment="Right"
VerticalAlignment="Center" />
</BoxContainer>
<Label Name="CloningActivity"
Text="{Loc 'cloning-console-component-msg-empty'}"
Access="Public"
HorizontalAlignment="Center"
HorizontalExpand="True" />
</BoxContainer>
<BoxContainer Name="GeneticScannerMissing" Margin="5 5 5 5" Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True">
<Label HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Loc 'cloning-console-window-no-scanner-detected-label'}" />
</BoxContainer>
<BoxContainer Name="GeneticScannerFar" Margin="5 5 5 5" Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True">
<Label HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Loc 'cloning-console-window-scanner-far-label'}" />
</BoxContainer>
</PanelContainer>
<Control MinSize="50 5" />
<PanelContainer VerticalExpand="True" StyleClasses="Inset">
<BoxContainer Name="CloningPodContents" Margin="5 5 5 5" Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True">
<Label HorizontalAlignment="Center" Text="{Loc 'cloning-console-window-pod-details-label'}" />
<BoxContainer Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True">
<RichTextLabel Name="ClonerInfoLabel"
Access="Public"
HorizontalExpand="True" />
<RichTextLabel Name="ClonerBrainActivity"
Access="Public"
HorizontalExpand="True"/>
<Button Name="EjectButton"
Access="Public"
Text="{Loc 'cloning-console-eject-body-button'}"
HorizontalAlignment="Right"
VerticalAlignment="Center" />
</BoxContainer>
</BoxContainer>
<BoxContainer Name="CloningPodMissing" Margin="5 5 5 5" Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True">
<Label HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Loc 'cloning-console-window-no-clone-pod-detected-label'}" />
</BoxContainer>
<BoxContainer Name="CloningPodFar" Margin="5 5 5 5" Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True">
<Label HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Loc 'cloning-console-window-clone-pod-far-label'}" />
</BoxContainer>
</PanelContainer>
</BoxContainer>
</TabContainer>
</DefaultWindow>

View File

@@ -0,0 +1,113 @@
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Content.Client.Message;
using Robust.Shared.Timing;
using Content.Shared.Cloning.CloningConsole;
namespace Content.Client.CloningConsole.UI
{
[GenerateTypedNameReferences]
public partial class CloningConsoleWindow : DefaultWindow
{
[Dependency] private readonly IGameTiming _timing = default!;
public CloningConsoleWindow()
{
IoCManager.InjectDependencies(this);
RobustXamlLoader.Load(this);
}
private CloningConsoleBoundUserInterfaceState? _lastUpdate;
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
}
public void Populate(CloningConsoleBoundUserInterfaceState state)
{
_lastUpdate = state;
// BUILD SCANNER UI
if (state.ScannerConnected)
{
if (!state.ScannerInRange)
{
GeneticScannerFar.Visible = true;
GeneticScannerContents.Visible = false;
GeneticScannerMissing.Visible = false;
return;
}
GeneticScannerContents.Visible = true;
GeneticScannerFar.Visible = false;
GeneticScannerMissing.Visible = false;
CloneButton.Disabled = state.CloningStatus != ClonerStatus.Ready;
switch (state.CloningStatus)
{
case ClonerStatus.NoClonerDetected:
CloningActivity.Text = (Loc.GetString("cloning-console-component-msg-no-cloner"));
break;
case ClonerStatus.Ready:
CloningActivity.Text = (Loc.GetString("cloning-console-component-msg-ready"));
break;
case ClonerStatus.ClonerOccupied:
CloningActivity.Text = (Loc.GetString("cloning-console-component-msg-occupied"));
break;
case ClonerStatus.ScannerEmpty:
CloningActivity.Text = (Loc.GetString("cloning-console-component-msg-empty"));
break;
case ClonerStatus.ScannerOccupantAlive:
CloningActivity.Text = (Loc.GetString("cloning-console-component-msg-scanner-occupant-alive"));
break;
case ClonerStatus.OccupantMetaphyiscal:
CloningActivity.Text = (Loc.GetString("cloning-console-component-msg-already-alive"));
break;
case ClonerStatus.NoMindDetected:
CloningActivity.Text = (Loc.GetString("cloning-console-component-msg-no-mind"));
break;
}
// Set label depending on if scanner is occupied or not.
ScannerInfoLabel.SetMarkup(state.ScannerBodyInfo != null ?
Loc.GetString("cloning-console-window-scanner-id", ("scannerOccupantName", state.ScannerBodyInfo)) :
Loc.GetString("cloning-console-window-id-blank"));
}
else
{
// Scanner is missing, set error message visible
GeneticScannerContents.Visible = false;
GeneticScannerFar.Visible = false;
GeneticScannerMissing.Visible = true;
}
// BUILD ClONER UI
if (state.ClonerConnected)
{
if (!state.ClonerInRange)
{
CloningPodFar.Visible = true;
CloningPodContents.Visible = false;
CloningPodMissing.Visible = false;
return;
}
CloningPodContents.Visible = true;
CloningPodFar.Visible = false;
CloningPodMissing.Visible = false;
ClonerBrainActivity.SetMarkup(Loc.GetString(state.MindPresent ? "cloning-console-mind-present-text" : "cloning-console-no-mind-activity-text"));
// Set label depending if clonepod is occupied or not
ClonerInfoLabel.SetMarkup(state.ClonerBodyInfo != null ?
Loc.GetString("cloning-console-window-pod-id", ("podOccupantName", state.ClonerBodyInfo)) :
Loc.GetString("cloning-console-window-id-blank"));
}
else
{
// Clone pod is missing, set error message visible
CloningPodContents.Visible = false;
CloningPodFar.Visible = false;
CloningPodMissing.Visible = true;
}
}
}
}

View File

@@ -1,51 +0,0 @@
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using static Content.Shared.MedicalScanner.SharedMedicalScannerComponent;
namespace Content.Client.MedicalScanner.UI
{
[UsedImplicitly]
public sealed class MedicalScannerBoundUserInterface : BoundUserInterface
{
private MedicalScannerWindow? _window;
public MedicalScannerBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
base.Open();
_window = new MedicalScannerWindow
{
Title = IoCManager.Resolve<IEntityManager>().GetComponent<MetaDataComponent>(Owner.Owner).EntityName,
};
_window.OnClose += Close;
_window.ScanButton.OnPressed += _ => SendMessage(new ScanButtonPressedMessage());
_window.OpenCentered();
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
if (state is not MedicalScannerBoundUserInterfaceState cast)
return;
_window?.Populate(cast);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
if (_window != null)
_window.OnClose -= Close;
_window?.Dispose();
}
}
}

View File

@@ -1,11 +0,0 @@
<DefaultWindow xmlns="https://spacestation14.io"
MinSize="200 100"
SetSize="200 100">
<BoxContainer Orientation="Vertical">
<Label Name="OccupantName"/>
<Button Name="ScanButton"
Disabled="True"
Access="Public"
Text="{Loc 'medical-scanner-window-save-button-text'}" />
</BoxContainer>
</DefaultWindow>

View File

@@ -1,22 +0,0 @@
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using static Content.Shared.MedicalScanner.SharedMedicalScannerComponent;
namespace Content.Client.MedicalScanner.UI
{
[GenerateTypedNameReferences]
public sealed partial class MedicalScannerWindow : DefaultWindow
{
public MedicalScannerWindow()
{
RobustXamlLoader.Load(this);
}
public void Populate(MedicalScannerBoundUserInterfaceState state)
{
ScanButton.Disabled = !state.IsScannable;
}
}
}