Crayons ECS (#6364)

This commit is contained in:
metalgearsloth
2022-02-06 23:32:32 +11:00
committed by GitHub
parent 1e10314900
commit 627cbba2b6
6 changed files with 207 additions and 187 deletions

View File

@@ -1,72 +1,15 @@
using Content.Client.Items.Components;
using Content.Client.Message;
using Content.Client.Stylesheets;
using Content.Shared.Crayon;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.GameObjects;
using Robust.Shared.Localization;
using Robust.Shared.Timing;
using Robust.Shared.ViewVariables;
namespace Content.Client.Crayon
{
[RegisterComponent]
public class CrayonComponent : SharedCrayonComponent, IItemStatus
public sealed class CrayonComponent : SharedCrayonComponent
{
[ViewVariables(VVAccess.ReadWrite)] private bool _uiUpdateNeeded;
[ViewVariables(VVAccess.ReadWrite)] private string Color => _color;
[ViewVariables] private int Charges { get; set; }
[ViewVariables] private int Capacity { get; set; }
Control IItemStatus.MakeControl()
{
return new StatusControl(this);
}
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
{
if (curState is not CrayonComponentState state)
return;
_color = state.Color;
SelectedState = state.State;
Charges = state.Charges;
Capacity = state.Capacity;
_uiUpdateNeeded = true;
}
private sealed class StatusControl : Control
{
private readonly CrayonComponent _parent;
private readonly RichTextLabel _label;
public StatusControl(CrayonComponent parent)
{
_parent = parent;
_label = new RichTextLabel { StyleClasses = { StyleNano.StyleClassItemStatus } };
AddChild(_label);
parent._uiUpdateNeeded = true;
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
if (!_parent._uiUpdateNeeded)
{
return;
}
_parent._uiUpdateNeeded = false;
_label.SetMarkup(Loc.GetString("crayon-drawing-label",
("color",_parent.Color),
("state",_parent.SelectedState),
("charges", _parent.Charges),
("capacity",_parent.Capacity)));
}
}
[ViewVariables(VVAccess.ReadWrite)] public bool UIUpdateNeeded;
[ViewVariables(VVAccess.ReadWrite)] public string Color => _color;
[ViewVariables] public int Charges { get; set; }
[ViewVariables] public int Capacity { get; set; }
}
}

View File

@@ -0,0 +1,72 @@
using Content.Client.Items;
using Content.Client.Message;
using Content.Client.Stylesheets;
using Content.Shared.Crayon;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.Localization;
using Robust.Shared.Timing;
namespace Content.Client.Crayon;
public sealed class CrayonSystem : EntitySystem
{
// Didn't do in shared because I don't think most of the server stuff can be predicted.
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CrayonComponent, ComponentHandleState>(OnCrayonHandleState);
SubscribeLocalEvent<CrayonComponent, ItemStatusCollectMessage>(OnCrayonItemStatus);
}
private static void OnCrayonHandleState(EntityUid uid, CrayonComponent component, ref ComponentHandleState args)
{
if (args.Current is not CrayonComponentState state) return;
component._color = state.Color;
component.SelectedState = state.State;
component.Charges = state.Charges;
component.Capacity = state.Capacity;
component.UIUpdateNeeded = true;
}
private static void OnCrayonItemStatus(EntityUid uid, CrayonComponent component, ItemStatusCollectMessage args)
{
args.Controls.Add(new StatusControl(component));
}
private sealed class StatusControl : Control
{
private readonly CrayonComponent _parent;
private readonly RichTextLabel _label;
public StatusControl(CrayonComponent parent)
{
_parent = parent;
_label = new RichTextLabel { StyleClasses = { StyleNano.StyleClassItemStatus } };
AddChild(_label);
parent.UIUpdateNeeded = true;
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
if (!_parent.UIUpdateNeeded)
{
return;
}
_parent.UIUpdateNeeded = false;
_label.SetMarkup(Loc.GetString("crayon-drawing-label",
("color",_parent.Color),
("state",_parent.SelectedState),
("charges", _parent.Charges),
("capacity",_parent.Capacity)));
}
}
}

View File

@@ -47,6 +47,7 @@ namespace Content.Client.Crayon.UI
if (disposing)
{
_menu?.Close();
_menu = null;
}
}
}

View File

@@ -1,25 +1,9 @@
using System.Linq;
using System.Threading.Tasks;
using Content.Server.Administration.Logs;
using Content.Server.UserInterface;
using Content.Shared.Audio;
using Content.Shared.Crayon;
using Content.Server.Decals;
using Content.Shared.Decals;
using Content.Shared.Database;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Helpers;
using Content.Shared.Popups;
using Content.Shared.Sound;
using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Player;
using Robust.Shared.Players;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
@@ -27,16 +11,12 @@ using Robust.Shared.ViewVariables;
namespace Content.Server.Crayon
{
[RegisterComponent]
public class CrayonComponent : SharedCrayonComponent, IAfterInteract, IUse, IDropped, ISerializationHooks
public sealed class CrayonComponent : SharedCrayonComponent, ISerializationHooks
{
[Dependency] private readonly IEntityManager _entMan = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[DataField("useSound")]
private SoundSpecifier? _useSound = null;
[DataField("useSound")] public SoundSpecifier? UseSound;
[ViewVariables]
public Color Color { get; set; }
public Color Color { get; private set; }
[ViewVariables(VVAccess.ReadWrite)]
public int Charges { get; set; }
@@ -45,104 +25,11 @@ namespace Content.Server.Crayon
[DataField("capacity")]
public int Capacity { get; set; } = 30;
[ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(CrayonUiKey.Key);
[ViewVariables] public BoundUserInterface? UserInterface => Owner.GetUIOrNull(CrayonUiKey.Key);
void ISerializationHooks.AfterDeserialization()
{
Color = Color.FromName(_color);
}
protected override void Initialize()
{
base.Initialize();
if (UserInterface != null)
{
UserInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
}
Charges = Capacity;
// Get the first one from the catalog and set it as default
var decal = _prototypeManager.EnumeratePrototypes<DecalPrototype>().FirstOrDefault(x => x.Tags.Contains("crayon"));
SelectedState = decal?.ID ?? string.Empty;
Dirty();
}
private void UserInterfaceOnReceiveMessage(ServerBoundUserInterfaceMessage serverMsg)
{
switch (serverMsg.Message)
{
case CrayonSelectMessage msg:
// Check if the selected state is valid
if (_prototypeManager.TryIndex<DecalPrototype>(msg.State, out var prototype) && prototype.Tags.Contains("crayon"))
{
SelectedState = msg.State;
Dirty();
}
break;
default:
break;
}
}
public override ComponentState GetComponentState()
{
return new CrayonComponentState(_color, SelectedState, Charges, Capacity);
}
// Opens the selection window
bool IUse.UseEntity(UseEntityEventArgs eventArgs)
{
if (_entMan.TryGetComponent(eventArgs.User, out ActorComponent? actor))
{
UserInterface?.Toggle(actor.PlayerSession);
if (UserInterface?.SessionHasOpen(actor.PlayerSession) == true)
{
// Tell the user interface the selected stuff
UserInterface.SetState(
new CrayonBoundUserInterfaceState(SelectedState, Color));
}
return true;
}
return false;
}
async Task<bool> IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
{
if (!eventArgs.User.InRangeUnobstructed(eventArgs.ClickLocation, ignoreInsideBlocker: false, popup: true,
collisionMask: Shared.Physics.CollisionGroup.MobImpassable))
{
return true;
}
if (Charges <= 0)
{
eventArgs.User.PopupMessage(Loc.GetString("crayon-interact-not-enough-left-text"));
return true;
}
if (!eventArgs.ClickLocation.IsValid(_entMan))
{
eventArgs.User.PopupMessage(Loc.GetString("crayon-interact-invalid-location"));
return true;
}
if(!EntitySystem.Get<DecalSystem>().TryAddDecal(SelectedState, eventArgs.ClickLocation.Offset(new Vector2(-0.5f,-0.5f)), out _, Color.FromName(_color), cleanable: true))
return false;
if (_useSound != null)
SoundSystem.Play(Filter.Pvs(Owner), _useSound.GetSound(), Owner, AudioHelpers.WithVariation(0.125f));
// Decrease "Ammo"
Charges--;
Dirty();
EntitySystem.Get<AdminLogSystem>().Add(LogType.CrayonDraw, LogImpact.Low, $"{_entMan.ToPrettyString(eventArgs.User):user} drew a {_color:color} {SelectedState}");
return true;
}
void IDropped.Dropped(DroppedEventArgs eventArgs)
{
if (_entMan.TryGetComponent(eventArgs.User, out ActorComponent? actor))
UserInterface?.Close(actor.PlayerSession);
}
}
}

View File

@@ -0,0 +1,121 @@
using System.Linq;
using Content.Server.Administration.Logs;
using Content.Server.Decals;
using Content.Server.Popups;
using Content.Shared.Audio;
using Content.Shared.Crayon;
using Content.Shared.Database;
using Content.Shared.Decals;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Helpers;
using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
namespace Content.Server.Crayon;
public sealed class CrayonSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly AdminLogSystem _logs = default!;
[Dependency] private readonly DecalSystem _decals = default!;
[Dependency] private readonly PopupSystem _popup = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CrayonComponent, ComponentInit>(OnCrayonInit);
SubscribeLocalEvent<CrayonComponent, CrayonSelectMessage>(OnCrayonBoundUI);
SubscribeLocalEvent<CrayonComponent, UseInHandEvent>(OnCrayonUse);
SubscribeLocalEvent<CrayonComponent, AfterInteractEvent>(OnCrayonAfterInteract);
SubscribeLocalEvent<CrayonComponent, DroppedEvent>(OnCrayonDropped);
SubscribeLocalEvent<CrayonComponent, ComponentGetState>(OnCrayonGetState);
}
private static void OnCrayonGetState(EntityUid uid, CrayonComponent component, ref ComponentGetState args)
{
args.State = new CrayonComponentState(component._color, component.SelectedState, component.Charges, component.Capacity);
}
private void OnCrayonAfterInteract(EntityUid uid, CrayonComponent component, AfterInteractEvent args)
{
if (args.Handled || !args.CanReach)
return;
if (component.Charges <= 0)
{
_popup.PopupEntity(Loc.GetString("crayon-interact-not-enough-left-text"), uid, Filter.Entities(args.User));
args.Handled = true;
return;
}
if (!args.ClickLocation.IsValid(EntityManager))
{
_popup.PopupEntity(Loc.GetString("crayon-interact-invalid-location"), uid, Filter.Entities(args.User));
args.Handled = true;
return;
}
if(!_decals.TryAddDecal(component.SelectedState, args.ClickLocation.Offset(new Vector2(-0.5f,-0.5f)), out _, Color.FromName(component._color), cleanable: true))
return;
if (component.UseSound != null)
SoundSystem.Play(Filter.Pvs(uid), component.UseSound.GetSound(), uid, AudioHelpers.WithVariation(0.125f));
// Decrease "Ammo"
component.Charges--;
Dirty(component);
_logs.Add(LogType.CrayonDraw, LogImpact.Low, $"{EntityManager.ToPrettyString(args.User):user} drew a {component._color:color} {component.SelectedState}");
args.Handled = true;
}
private void OnCrayonUse(EntityUid uid, CrayonComponent component, UseInHandEvent args)
{
// Open crayon window if neccessary.
if (args.Handled)
return;
if (!TryComp<ActorComponent>(args.User, out var actor)) return;
component.UserInterface?.Toggle(actor.PlayerSession);
if (component.UserInterface?.SessionHasOpen(actor.PlayerSession) == true)
{
// Tell the user interface the selected stuff
component.UserInterface.SetState(new CrayonBoundUserInterfaceState(component.SelectedState, component.Color));
}
args.Handled = true;
}
private void OnCrayonBoundUI(EntityUid uid, CrayonComponent component, CrayonSelectMessage args)
{
// Check if the selected state is valid
if (!_prototypeManager.TryIndex<DecalPrototype>(args.State, out var prototype) || !prototype.Tags.Contains("crayon")) return;
component.SelectedState = args.State;
Dirty(component);
}
private void OnCrayonInit(EntityUid uid, CrayonComponent component, ComponentInit args)
{
component.Charges = component.Capacity;
// Get the first one from the catalog and set it as default
var decal = _prototypeManager.EnumeratePrototypes<DecalPrototype>().FirstOrDefault(x => x.Tags.Contains("crayon"));
component.SelectedState = decal?.ID ?? string.Empty;
Dirty(component);
}
private void OnCrayonDropped(EntityUid uid, CrayonComponent component, DroppedEvent args)
{
if (TryComp<ActorComponent>(args.UserUid, out var actor))
component.UserInterface?.Close(actor.PlayerSession);
}
}

View File

@@ -1,25 +1,21 @@
using System;
using System.Collections.Generic;
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
namespace Content.Shared.Crayon
{
[NetworkedComponent()]
public class SharedCrayonComponent : Component
[NetworkedComponent, ComponentProtoName("Crayon")]
public abstract class SharedCrayonComponent : Component
{
public string SelectedState { get; set; } = string.Empty;
[DataField("color")]
protected string _color = "white";
[DataField("color")] public string _color = "white";
[Serializable, NetSerializable]
public enum CrayonUiKey
public enum CrayonUiKey : byte
{
Key,
}