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.HUD.UI;
using Content.Client.Stylesheets;
using Content.Shared.CharacterInfo;
using Robust.Client.GameObjects;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.Utility;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Network;
using Robust.Shared.Players;
namespace Content.Client.CharacterInfo.Components
{
[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;
protected override void OnAdd()
{
base.OnAdd();
Scene = _control = new CharacterInfoControl(_resourceCache);
}
public void Opened()
{
#pragma warning disable 618
SendNetworkMessage(new RequestCharacterInfoMessage());
#pragma warning restore 618
EntitySystem.Get<CharacterInfoSystem>().RequestCharacterInfo(Owner);
}
[Obsolete("Component Messages are deprecated, use Entity Events instead.")]
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 sealed class CharacterInfoControl : BoxContainer
{
public SpriteView SpriteView { get; }
public Label NameLabel { get; }
@@ -69,7 +33,7 @@ namespace Content.Client.CharacterInfo.Components
public BoxContainer ObjectivesContainer { get; }
public CharacterInfoControl(IResourceCache resourceCache)
public CharacterInfoControl()
{
IoCManager.InjectDependencies(this);
@@ -91,7 +55,7 @@ namespace Content.Client.CharacterInfo.Components
(SubText = new Label
{
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")
});
}
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.Linq;
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.CustomControls;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Content.Client.CharacterInterface
@@ -20,8 +14,6 @@ namespace Content.Client.CharacterInterface
[RegisterComponent]
public class CharacterInterfaceComponent : Component
{
[Dependency] private readonly IGameHud _gameHud = default!;
public override string Name => "Character Interface Component";
/// <summary>
@@ -30,104 +22,31 @@ namespace Content.Client.CharacterInterface
/// <remarks>
/// Null if it would otherwise be empty.
/// </remarks>
public CharacterWindow? Window { get; private set; }
public CharacterWindow? Window { get; set; }
private 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();
}
};
}
}
public List<ICharacterUI>? UIComponents;
/// <summary>
/// A window that collects and shows all the individual character user interfaces
/// </summary>
public class CharacterWindow : SS14Window
{
private readonly BoxContainer _contentsVBox;
private readonly List<ICharacterUI> _windowComponents;
public CharacterWindow(List<ICharacterUI> windowComponents)
{
Title = "Character";
_contentsVBox = new BoxContainer
var contentsVBox = new BoxContainer
{
Orientation = LayoutOrientation.Vertical
};
Contents.AddChild(_contentsVBox);
Contents.AddChild(contentsVBox);
windowComponents.Sort((a, b) => ((int) a.Priority).CompareTo((int) b.Priority));
foreach (var element in windowComponents)
{
_contentsVBox.AddChild(element.Scene);
contentsVBox.AddChild(element.Scene);
}
_windowComponents = windowComponents;

View File

@@ -1,7 +1,10 @@
using System.Linq;
using Content.Client.CharacterInfo.Components;
using Content.Client.HUD;
using Content.Shared.Input;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.Input;
using Robust.Client.Player;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.GameObjects;
@@ -15,6 +18,7 @@ namespace Content.Client.CharacterInterface
{
[Dependency] private readonly IGameHud _gameHud = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IInputManager _inputManager = default!;
public override void Initialize()
{
@@ -22,11 +26,13 @@ namespace Content.Client.CharacterInterface
CommandBinds.Builder
.Bind(ContentKeyFunctions.OpenCharacterMenu,
InputCmdHandler.FromDelegate(s => HandleOpenCharacterMenu()))
InputCmdHandler.FromDelegate(_ => HandleOpenCharacterMenu()))
.Register<CharacterInterfaceSystem>();
SubscribeLocalEvent<CharacterInterfaceComponent, PlayerAttachedEvent>((_, component, _) => component.PlayerAttached());
SubscribeLocalEvent<CharacterInterfaceComponent, PlayerDetachedEvent>((_, component, _) => component.PlayerDetached());
SubscribeLocalEvent<CharacterInterfaceComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<CharacterInterfaceComponent, ComponentRemove>(OnComponentRemove);
SubscribeLocalEvent<CharacterInterfaceComponent, PlayerAttachedEvent>(OnPlayerAttached);
SubscribeLocalEvent<CharacterInterfaceComponent, PlayerDetachedEvent>(OnPlayerDetached);
}
public override void Shutdown()
@@ -35,31 +41,77 @@ namespace Content.Client.CharacterInterface
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()
{
if (!EntityManager.TryGetComponent(_playerManager.LocalPlayer?.ControlledEntity, out CharacterInterfaceComponent? characterInterface))
{
if (_playerManager.LocalPlayer?.ControlledEntity == null
|| !EntityManager.TryGetComponent(_playerManager.LocalPlayer.ControlledEntity, out CharacterInterfaceComponent? characterInterface))
return;
}
var menu = characterInterface.Window;
if (menu == null)
{
return;
}
if (menu.IsOpen)
{
if (menu.IsAtFront())
{
_setOpenValue(menu, false);
}
else
{
menu.MoveToFront();
}
}
else
{
_setOpenValue(menu, true);
@@ -68,16 +120,11 @@ namespace Content.Client.CharacterInterface
private void _setOpenValue(SS14Window menu, bool value)
{
_gameHud.CharacterButtonDown = value;
if (value)
{
_gameHud.CharacterButtonDown = true;
menu.OpenCentered();
}
else
{
_gameHud.CharacterButtonDown = false;
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",
"Icon",
"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;
}
}