ECS characterinfo (#5669)

This commit is contained in:
ShadowCommander
2021-12-11 15:12:55 -08:00
committed by GitHub
parent 237a90cd48
commit 703c23d8a5
9 changed files with 272 additions and 306 deletions

View File

@@ -1,67 +1,31 @@
using System;
using Content.Client.CharacterInterface; using Content.Client.CharacterInterface;
using Content.Client.HUD.UI; using Content.Client.HUD.UI;
using Content.Client.Stylesheets; using Content.Client.Stylesheets;
using Content.Shared.CharacterInfo;
using Robust.Client.GameObjects;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface; using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
using Robust.Client.Utility;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Localization; using Robust.Shared.Localization;
using Robust.Shared.Maths; using Robust.Shared.Maths;
using Robust.Shared.Network;
using Robust.Shared.Players;
namespace Content.Client.CharacterInfo.Components namespace Content.Client.CharacterInfo.Components
{ {
[RegisterComponent] [RegisterComponent]
public sealed class CharacterInfoComponent : SharedCharacterInfoComponent, ICharacterUI public sealed class CharacterInfoComponent : Component, ICharacterUI
{ {
[Dependency] private readonly IResourceCache _resourceCache = default!; public override string Name => "CharacterInfo";
private CharacterInfoControl _control = default!; public CharacterInfoControl Control = default!;
public Control Scene { get; private set; } = default!; public Control Scene { get; set; } = default!;
public UIPriority Priority => UIPriority.Info; public UIPriority Priority => UIPriority.Info;
protected override void OnAdd()
{
base.OnAdd();
Scene = _control = new CharacterInfoControl(_resourceCache);
}
public void Opened() public void Opened()
{ {
#pragma warning disable 618 EntitySystem.Get<CharacterInfoSystem>().RequestCharacterInfo(Owner);
SendNetworkMessage(new RequestCharacterInfoMessage());
#pragma warning restore 618
} }
[Obsolete("Component Messages are deprecated, use Entity Events instead.")] public sealed class CharacterInfoControl : BoxContainer
public override void HandleNetworkMessage(ComponentMessage message, INetChannel netChannel, ICommonSession? session = null)
{
base.HandleNetworkMessage(message, netChannel, session);
switch (message)
{
case CharacterInfoMessage characterInfoMessage:
_control.UpdateUI(characterInfoMessage);
var entityManager = IoCManager.Resolve<IEntityManager>();
if (entityManager.TryGetComponent(Owner, out ISpriteComponent? spriteComponent))
{
_control.SpriteView.Sprite = spriteComponent;
}
_control.NameLabel.Text = entityManager.GetComponent<MetaDataComponent>(Owner).EntityName;
break;
}
}
private sealed class CharacterInfoControl : BoxContainer
{ {
public SpriteView SpriteView { get; } public SpriteView SpriteView { get; }
public Label NameLabel { get; } public Label NameLabel { get; }
@@ -69,7 +33,7 @@ namespace Content.Client.CharacterInfo.Components
public BoxContainer ObjectivesContainer { get; } public BoxContainer ObjectivesContainer { get; }
public CharacterInfoControl(IResourceCache resourceCache) public CharacterInfoControl()
{ {
IoCManager.InjectDependencies(this); IoCManager.InjectDependencies(this);
@@ -91,7 +55,7 @@ namespace Content.Client.CharacterInfo.Components
(SubText = new Label (SubText = new Label
{ {
VerticalAlignment = VAlignment.Top, VerticalAlignment = VAlignment.Top,
StyleClasses = {StyleNano.StyleClassLabelSubText}, StyleClasses = {StyleBase.StyleClassLabelSubText},
}) })
} }
@@ -115,57 +79,6 @@ namespace Content.Client.CharacterInfo.Components
PlaceholderText = Loc.GetString("character-info-roles-antagonist-text") PlaceholderText = Loc.GetString("character-info-roles-antagonist-text")
}); });
} }
public void UpdateUI(CharacterInfoMessage characterInfoMessage)
{
SubText.Text = characterInfoMessage.JobTitle;
ObjectivesContainer.RemoveAllChildren();
foreach (var (groupId, objectiveConditions) in characterInfoMessage.Objectives)
{
var vbox = new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
Modulate = Color.Gray
};
vbox.AddChild(new Label
{
Text = groupId,
Modulate = Color.LightSkyBlue
});
foreach (var objectiveCondition in objectiveConditions)
{
var hbox = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal
};
hbox.AddChild(new ProgressTextureRect
{
Texture = objectiveCondition.SpriteSpecifier.Frame0(),
Progress = objectiveCondition.Progress,
VerticalAlignment = VAlignment.Center
});
hbox.AddChild(new Control
{
MinSize = (10,0)
});
hbox.AddChild(new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
Children =
{
new Label{Text = objectiveCondition.Title},
new Label{Text = objectiveCondition.Description}
}
}
);
vbox.AddChild(hbox);
}
ObjectivesContainer.AddChild(vbox);
}
}
} }
} }
} }

View File

@@ -0,0 +1,99 @@
using System.Collections.Generic;
using Content.Shared.CharacterInfo;
using Content.Shared.Objectives;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.Utility;
using Robust.Shared.GameObjects;
using Robust.Shared.Maths;
namespace Content.Client.CharacterInfo.Components;
public class CharacterInfoSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeNetworkEvent<CharacterInfoEvent>(OnCharacterInfoEvent);
SubscribeLocalEvent<CharacterInfoComponent, ComponentAdd>(OnComponentAdd);
}
private void OnComponentAdd(EntityUid uid, CharacterInfoComponent component, ComponentAdd args)
{
component.Scene = component.Control = new CharacterInfoComponent.CharacterInfoControl();
}
public void RequestCharacterInfo(EntityUid entityUid)
{
RaiseNetworkEvent(new RequestCharacterInfoEvent(entityUid));
}
private void OnCharacterInfoEvent(CharacterInfoEvent msg, EntitySessionEventArgs args)
{
if (!EntityManager.TryGetComponent(msg.EntityUid, out CharacterInfoComponent characterInfoComponent))
return;
UpdateUI(characterInfoComponent, msg.JobTitle, msg.Objectives);
if (EntityManager.TryGetComponent(msg.EntityUid, out ISpriteComponent? spriteComponent))
{
characterInfoComponent.Control.SpriteView.Sprite = spriteComponent;
}
if (!EntityManager.TryGetComponent(msg.EntityUid, out MetaDataComponent metadata))
return;
characterInfoComponent.Control.NameLabel.Text = metadata.EntityName;
}
private void UpdateUI(CharacterInfoComponent comp, string jobTitle, Dictionary<string, List<ConditionInfo>> objectives)
{
comp.Control.SubText.Text = jobTitle;
comp.Control.ObjectivesContainer.RemoveAllChildren();
foreach (var (groupId, objectiveConditions) in objectives)
{
var vbox = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Vertical,
Modulate = Color.Gray
};
vbox.AddChild(new Label
{
Text = groupId,
Modulate = Color.LightSkyBlue
});
foreach (var objectiveCondition in objectiveConditions)
{
var hbox = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Horizontal
};
hbox.AddChild(new ProgressTextureRect
{
Texture = objectiveCondition.SpriteSpecifier.Frame0(),
Progress = objectiveCondition.Progress,
VerticalAlignment = Control.VAlignment.Center
});
hbox.AddChild(new Control
{
MinSize = (10,0)
});
hbox.AddChild(new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Vertical,
Children =
{
new Label{Text = objectiveCondition.Title},
new Label{Text = objectiveCondition.Description}
}
}
);
vbox.AddChild(hbox);
}
comp.Control.ObjectivesContainer.AddChild(vbox);
}
}
}

View File

@@ -1,14 +1,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Content.Client.CharacterInfo.Components; using Content.Client.CharacterInfo.Components;
using Content.Client.HUD;
using Content.Shared.Input;
using Robust.Client.GameObjects;
using Robust.Client.Input;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using static Robust.Client.UserInterface.Controls.BoxContainer; using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Content.Client.CharacterInterface namespace Content.Client.CharacterInterface
@@ -20,8 +14,6 @@ namespace Content.Client.CharacterInterface
[RegisterComponent] [RegisterComponent]
public class CharacterInterfaceComponent : Component public class CharacterInterfaceComponent : Component
{ {
[Dependency] private readonly IGameHud _gameHud = default!;
public override string Name => "Character Interface Component"; public override string Name => "Character Interface Component";
/// <summary> /// <summary>
@@ -30,104 +22,31 @@ namespace Content.Client.CharacterInterface
/// <remarks> /// <remarks>
/// Null if it would otherwise be empty. /// Null if it would otherwise be empty.
/// </remarks> /// </remarks>
public CharacterWindow? Window { get; private set; } public CharacterWindow? Window { get; set; }
private List<ICharacterUI>? _uiComponents; public List<ICharacterUI>? UIComponents;
/// <summary>
/// Create the window with all character UIs and bind it to a keypress
/// </summary>
protected override void Initialize()
{
base.Initialize();
//Use all the character ui interfaced components to create the character window
_uiComponents = IoCManager.Resolve<IEntityManager>().GetComponents<ICharacterUI>(Owner).ToList();
if (_uiComponents.Count == 0)
{
return;
}
Window = new CharacterWindow(_uiComponents);
Window.OnClose += () => _gameHud.CharacterButtonDown = false;
}
/// <summary>
/// Dispose of window and the keypress binding
/// </summary>
protected override void OnRemove()
{
base.OnRemove();
if (_uiComponents != null)
{
foreach (var component in _uiComponents)
{
// Make sure these don't get deleted when the window is disposed.
component.Scene.Orphan();
}
}
_uiComponents = null;
Window?.Close();
Window = null;
var inputMgr = IoCManager.Resolve<IInputManager>();
inputMgr.SetInputCommand(ContentKeyFunctions.OpenCharacterMenu, null);
}
public void PlayerDetached()
{
if (Window != null)
{
_gameHud.CharacterButtonVisible = false;
Window.Close();
}
}
public void PlayerAttached()
{
if (Window != null)
{
_gameHud.CharacterButtonVisible = true;
_gameHud.CharacterButtonToggled = b =>
{
if (b)
{
Window.OpenCentered();
}
else
{
Window.Close();
}
};
}
}
/// <summary> /// <summary>
/// A window that collects and shows all the individual character user interfaces /// A window that collects and shows all the individual character user interfaces
/// </summary> /// </summary>
public class CharacterWindow : SS14Window public class CharacterWindow : SS14Window
{ {
private readonly BoxContainer _contentsVBox;
private readonly List<ICharacterUI> _windowComponents; private readonly List<ICharacterUI> _windowComponents;
public CharacterWindow(List<ICharacterUI> windowComponents) public CharacterWindow(List<ICharacterUI> windowComponents)
{ {
Title = "Character"; Title = "Character";
_contentsVBox = new BoxContainer var contentsVBox = new BoxContainer
{ {
Orientation = LayoutOrientation.Vertical Orientation = LayoutOrientation.Vertical
}; };
Contents.AddChild(_contentsVBox); Contents.AddChild(contentsVBox);
windowComponents.Sort((a, b) => ((int) a.Priority).CompareTo((int) b.Priority)); windowComponents.Sort((a, b) => ((int) a.Priority).CompareTo((int) b.Priority));
foreach (var element in windowComponents) foreach (var element in windowComponents)
{ {
_contentsVBox.AddChild(element.Scene); contentsVBox.AddChild(element.Scene);
} }
_windowComponents = windowComponents; _windowComponents = windowComponents;

View File

@@ -1,7 +1,10 @@
using System.Linq;
using Content.Client.CharacterInfo.Components;
using Content.Client.HUD; using Content.Client.HUD;
using Content.Shared.Input; using Content.Shared.Input;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Robust.Client.Input;
using Robust.Client.Player; using Robust.Client.Player;
using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
@@ -15,6 +18,7 @@ namespace Content.Client.CharacterInterface
{ {
[Dependency] private readonly IGameHud _gameHud = default!; [Dependency] private readonly IGameHud _gameHud = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IInputManager _inputManager = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -22,11 +26,13 @@ namespace Content.Client.CharacterInterface
CommandBinds.Builder CommandBinds.Builder
.Bind(ContentKeyFunctions.OpenCharacterMenu, .Bind(ContentKeyFunctions.OpenCharacterMenu,
InputCmdHandler.FromDelegate(s => HandleOpenCharacterMenu())) InputCmdHandler.FromDelegate(_ => HandleOpenCharacterMenu()))
.Register<CharacterInterfaceSystem>(); .Register<CharacterInterfaceSystem>();
SubscribeLocalEvent<CharacterInterfaceComponent, PlayerAttachedEvent>((_, component, _) => component.PlayerAttached()); SubscribeLocalEvent<CharacterInterfaceComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<CharacterInterfaceComponent, PlayerDetachedEvent>((_, component, _) => component.PlayerDetached()); SubscribeLocalEvent<CharacterInterfaceComponent, ComponentRemove>(OnComponentRemove);
SubscribeLocalEvent<CharacterInterfaceComponent, PlayerAttachedEvent>(OnPlayerAttached);
SubscribeLocalEvent<CharacterInterfaceComponent, PlayerDetachedEvent>(OnPlayerDetached);
} }
public override void Shutdown() public override void Shutdown()
@@ -35,30 +41,76 @@ namespace Content.Client.CharacterInterface
base.Shutdown(); base.Shutdown();
} }
private void OnComponentInit(EntityUid uid, CharacterInterfaceComponent comp, ComponentInit args)
{
//Use all the character ui interfaced components to create the character window
comp.UIComponents = EntityManager.GetComponents<ICharacterUI>(uid).ToList();
if (comp.UIComponents.Count == 0)
return;
comp.Window = new CharacterInterfaceComponent.CharacterWindow(comp.UIComponents);
comp.Window.OnClose += () => _gameHud.CharacterButtonDown = false;
}
private void OnComponentRemove(EntityUid uid, CharacterInterfaceComponent comp, ComponentRemove args)
{
if (comp.UIComponents != null)
{
foreach (var component in comp.UIComponents)
{
// Make sure these don't get deleted when the window is disposed.
component.Scene.Orphan();
}
}
comp.UIComponents = null;
comp.Window?.Close();
comp.Window = null;
_inputManager.SetInputCommand(ContentKeyFunctions.OpenCharacterMenu, null);
}
private void OnPlayerAttached(EntityUid uid, CharacterInterfaceComponent comp, PlayerAttachedEvent args)
{
if (comp.Window == null)
return;
_gameHud.CharacterButtonVisible = true;
_gameHud.CharacterButtonToggled = b =>
{
if (b)
comp.Window.OpenCentered();
else
comp.Window.Close();
};
}
private void OnPlayerDetached(EntityUid uid, CharacterInterfaceComponent comp, PlayerDetachedEvent args)
{
if (comp.Window == null)
return;
_gameHud.CharacterButtonVisible = false;
comp.Window.Close();
}
private void HandleOpenCharacterMenu() private void HandleOpenCharacterMenu()
{ {
if (!EntityManager.TryGetComponent(_playerManager.LocalPlayer?.ControlledEntity, out CharacterInterfaceComponent? characterInterface)) if (_playerManager.LocalPlayer?.ControlledEntity == null
{ || !EntityManager.TryGetComponent(_playerManager.LocalPlayer.ControlledEntity, out CharacterInterfaceComponent? characterInterface))
return; return;
}
var menu = characterInterface.Window; var menu = characterInterface.Window;
if (menu == null) if (menu == null)
{
return; return;
}
if (menu.IsOpen) if (menu.IsOpen)
{ {
if (menu.IsAtFront()) if (menu.IsAtFront())
{
_setOpenValue(menu, false); _setOpenValue(menu, false);
}
else else
{
menu.MoveToFront(); menu.MoveToFront();
}
} }
else else
{ {
@@ -68,16 +120,11 @@ namespace Content.Client.CharacterInterface
private void _setOpenValue(SS14Window menu, bool value) private void _setOpenValue(SS14Window menu, bool value)
{ {
_gameHud.CharacterButtonDown = value;
if (value) if (value)
{
_gameHud.CharacterButtonDown = true;
menu.OpenCentered(); menu.OpenCentered();
}
else else
{
_gameHud.CharacterButtonDown = false;
menu.Close(); menu.Close();
}
} }
} }
} }

View File

@@ -1,63 +0,0 @@
using System;
using System.Collections.Generic;
using Content.Server.Mind.Components;
using Content.Server.Roles;
using Content.Shared.CharacterInfo;
using Content.Shared.Objectives;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Network;
using Robust.Shared.Players;
namespace Content.Server.CharacterInfo
{
[RegisterComponent]
public class CharacterInfoComponent : SharedCharacterInfoComponent
{
[Obsolete("Component Messages are deprecated, use Entity Events instead.")]
public override void HandleNetworkMessage(ComponentMessage message, INetChannel netChannel, ICommonSession? session = null)
{
if(session?.AttachedEntity != Owner) return;
switch (message)
{
case RequestCharacterInfoMessage _:
var conditions = new Dictionary<string, List<ConditionInfo>>();
var jobTitle = "No Profession";
if (IoCManager.Resolve<IEntityManager>().TryGetComponent(Owner, out MindComponent? mindComponent))
{
var mind = mindComponent.Mind;
if (mind != null)
{
// getting conditions
foreach (var objective in mind.AllObjectives)
{
if (!conditions.ContainsKey(objective.Prototype.Issuer))
conditions[objective.Prototype.Issuer] = new List<ConditionInfo>();
foreach (var condition in objective.Conditions)
{
conditions[objective.Prototype.Issuer].Add(new ConditionInfo(condition.Title,
condition.Description, condition.Icon, condition.Progress));
}
}
// getting jobtitle
foreach (var role in mind.AllRoles)
{
if (role.GetType() == typeof(Job))
{
jobTitle = role.Name;
break;
}
}
}
}
#pragma warning disable 618
SendNetworkMessage(new CharacterInfoMessage(jobTitle, conditions));
#pragma warning restore 618
break;
}
}
}
}

View File

@@ -0,0 +1,59 @@
using System.Collections.Generic;
using Content.Server.Mind.Components;
using Content.Server.Roles;
using Content.Shared.CharacterInfo;
using Content.Shared.Objectives;
using Robust.Shared.GameObjects;
using Robust.Shared.Player;
namespace Content.Server.CharacterInfo;
public class CharacterInfoSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeNetworkEvent<RequestCharacterInfoEvent>(OnRequestCharacterInfoEvent);
}
private void OnRequestCharacterInfoEvent(RequestCharacterInfoEvent msg, EntitySessionEventArgs args)
{
if (!args.SenderSession.AttachedEntity.HasValue
|| args.SenderSession.AttachedEntity != msg.EntityUid)
return;
var entity = args.SenderSession.AttachedEntity.Value;
var conditions = new Dictionary<string, List<ConditionInfo>>();
var jobTitle = "No Profession";
if (EntityManager.TryGetComponent(entity, out MindComponent? mindComponent) && mindComponent.Mind != null)
{
var mind = mindComponent.Mind;
// Get objectives
foreach (var objective in mind.AllObjectives)
{
if (!conditions.ContainsKey(objective.Prototype.Issuer))
conditions[objective.Prototype.Issuer] = new List<ConditionInfo>();
foreach (var condition in objective.Conditions)
{
conditions[objective.Prototype.Issuer].Add(new ConditionInfo(condition.Title,
condition.Description, condition.Icon, condition.Progress));
}
}
// Get job title
foreach (var role in mind.AllRoles)
{
if (role.GetType() != typeof(Job)) continue;
jobTitle = role.Name;
break;
}
}
RaiseNetworkEvent(new CharacterInfoEvent(entity, jobTitle, conditions),
Filter.SinglePlayer(args.SenderSession));
}
}

View File

@@ -17,7 +17,8 @@ namespace Content.Server.Entry
"RadiatingLight", "RadiatingLight",
"Icon", "Icon",
"ClientEntitySpawner", "ClientEntitySpawner",
"ToySingularity" "ToySingularity",
"CharacterInfo"
}; };
} }
} }

View File

@@ -1,42 +0,0 @@
using System;
using System.Collections.Generic;
using Content.Shared.Objectives;
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
namespace Content.Shared.CharacterInfo
{
[NetworkedComponent()]
public class SharedCharacterInfoComponent : Component
{
public override string Name => "CharacterInfo";
[Serializable, NetSerializable]
#pragma warning disable 618
protected class RequestCharacterInfoMessage : ComponentMessage
#pragma warning restore 618
{
public RequestCharacterInfoMessage()
{
Directed = true;
}
}
[Serializable, NetSerializable]
#pragma warning disable 618
protected class CharacterInfoMessage : ComponentMessage
#pragma warning restore 618
{
public readonly Dictionary<string, List<ConditionInfo>> Objectives;
public readonly string JobTitle;
public CharacterInfoMessage(string jobTitle, Dictionary<string, List<ConditionInfo>> objectives)
{
Directed = true;
JobTitle = jobTitle;
Objectives = objectives;
}
}
}
}

View File

@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using Content.Shared.Objectives;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization;
namespace Content.Shared.CharacterInfo;
[Serializable, NetSerializable]
public class RequestCharacterInfoEvent : EntityEventArgs
{
public readonly EntityUid EntityUid;
public RequestCharacterInfoEvent(EntityUid entityUid)
{
EntityUid = entityUid;
}
}
[Serializable, NetSerializable]
public class CharacterInfoEvent : EntityEventArgs
{
public readonly EntityUid EntityUid;
public readonly string JobTitle;
public readonly Dictionary<string, List<ConditionInfo>> Objectives;
public CharacterInfoEvent(EntityUid entityUid, string jobTitle, Dictionary<string, List<ConditionInfo>> objectives)
{
EntityUid = entityUid;
JobTitle = jobTitle;
Objectives = objectives;
}
}