diff --git a/Content.Client/CharacterAppearance/HumanoidAppearanceComponent.cs b/Content.Client/CharacterAppearance/Systems/HumanoidAppearanceSystem.cs similarity index 50% rename from Content.Client/CharacterAppearance/HumanoidAppearanceComponent.cs rename to Content.Client/CharacterAppearance/Systems/HumanoidAppearanceSystem.cs index 0280b27dd6..c1f5871bb3 100644 --- a/Content.Client/CharacterAppearance/HumanoidAppearanceComponent.cs +++ b/Content.Client/CharacterAppearance/Systems/HumanoidAppearanceSystem.cs @@ -1,85 +1,61 @@ using Content.Client.Cuffs.Components; using Content.Shared.Body.Components; -using Content.Shared.Body.Part; using Content.Shared.CharacterAppearance; using Content.Shared.CharacterAppearance.Components; +using Content.Shared.CharacterAppearance.Systems; using Robust.Client.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Maths; using Robust.Shared.Prototypes; -namespace Content.Client.CharacterAppearance +namespace Content.Client.CharacterAppearance.Systems { - [RegisterComponent] - public sealed class HumanoidAppearanceComponent : SharedHumanoidAppearanceComponent, IBodyPartAdded, IBodyPartRemoved + public class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem { [Dependency] private readonly SpriteAccessoryManager _accessoryManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - public override HumanoidCharacterAppearance Appearance + public override void Initialize() { - get => base.Appearance; - set - { - base.Appearance = value; - UpdateLooks(); - } + base.Initialize(); + + SubscribeLocalEvent(UpdateLooks); + SubscribeLocalEvent(BodyPartAdded); + SubscribeLocalEvent(BodyPartRemoved); } - public override Sex Sex + private void UpdateLooks(EntityUid uid, HumanoidAppearanceComponent component, ChangedHumanoidAppearanceEvent args) { - get => base.Sex; - set - { - base.Sex = value; - UpdateLooks(); - } - } - - protected override void Startup() - { - base.Startup(); - - UpdateLooks(); - } - - private void UpdateLooks() - { - // ReSharper disable once ConditionIsAlwaysTrueOrFalse - if (Appearance == null || - !Owner.TryGetComponent(out SpriteComponent? sprite)) - { + if(!EntityManager.TryGetComponent(uid, out SpriteComponent? sprite)) return; - } - if (Owner.TryGetComponent(out SharedBodyComponent? body)) + if (EntityManager.TryGetComponent(uid, out SharedBodyComponent? body)) { foreach (var (part, _) in body.Parts) { - if (!part.Owner.TryGetComponent(out SpriteComponent? partSprite)) + if (part.Owner.TryGetComponent(out SpriteComponent? partSprite)) { - continue; + partSprite!.Color = component.Appearance.SkinColor; } - partSprite.Color = Appearance.SkinColor; } } sprite.LayerSetColor(HumanoidVisualLayers.Hair, - CanColorHair ? Appearance.HairColor : Color.White); + component.CanColorHair ? component.Appearance.HairColor : Color.White); sprite.LayerSetColor(HumanoidVisualLayers.FacialHair, - CanColorFacialHair ? Appearance.FacialHairColor : Color.White); + component.CanColorFacialHair ? component.Appearance.FacialHairColor : Color.White); - sprite.LayerSetColor(HumanoidVisualLayers.Eyes, Appearance.EyeColor); + sprite.LayerSetColor(HumanoidVisualLayers.Eyes, component.Appearance.EyeColor); - sprite.LayerSetState(HumanoidVisualLayers.Chest, Sex == Sex.Male ? "torso_m" : "torso_f"); - sprite.LayerSetState(HumanoidVisualLayers.Head, Sex == Sex.Male ? "head_m" : "head_f"); + sprite.LayerSetState(HumanoidVisualLayers.Chest, component.Sex == Sex.Male ? "torso_m" : "torso_f"); + sprite.LayerSetState(HumanoidVisualLayers.Head, component.Sex == Sex.Male ? "head_m" : "head_f"); if (sprite.LayerMapTryGet(HumanoidVisualLayers.StencilMask, out _)) - sprite.LayerSetVisible(HumanoidVisualLayers.StencilMask, Sex == Sex.Female); + sprite.LayerSetVisible(HumanoidVisualLayers.StencilMask, component.Sex == Sex.Female); - if (Owner.TryGetComponent(out var cuffed)) + if (EntityManager.TryGetComponent(uid, out var cuffed)) { sprite.LayerSetVisible(HumanoidVisualLayers.Handcuffs, !cuffed.CanStillInteract); } @@ -88,16 +64,16 @@ namespace Content.Client.CharacterAppearance sprite.LayerSetVisible(HumanoidVisualLayers.Handcuffs, false); } - var hairStyle = Appearance.HairStyleId; + var hairStyle = component.Appearance.HairStyleId; if (string.IsNullOrWhiteSpace(hairStyle) || - !_accessoryManager.IsValidAccessoryInCategory(hairStyle, CategoriesHair)) + !_accessoryManager.IsValidAccessoryInCategory(hairStyle, component.CategoriesHair)) { hairStyle = HairStyles.DefaultHairStyle; } - var facialHairStyle = Appearance.FacialHairStyleId; + var facialHairStyle = component.Appearance.FacialHairStyleId; if (string.IsNullOrWhiteSpace(facialHairStyle) || - !_accessoryManager.IsValidAccessoryInCategory(facialHairStyle, CategoriesFacialHair)) + !_accessoryManager.IsValidAccessoryInCategory(facialHairStyle, component.CategoriesFacialHair)) { facialHairStyle = HairStyles.DefaultFacialHairStyle; } @@ -109,37 +85,40 @@ namespace Content.Client.CharacterAppearance sprite.LayerSetSprite(HumanoidVisualLayers.FacialHair, facialHairPrototype.Sprite); } - public void BodyPartAdded(BodyPartAddedEventArgs args) + // Scaffolding until Body is moved to ECS. + private void BodyPartAdded(HumanoidAppearanceBodyPartAddedEvent args) { - if (!Owner.TryGetComponent(out SpriteComponent? sprite)) + if(!EntityManager.TryGetEntity(args.Uid, out var owner)) return; + if (!owner.TryGetComponent(out SpriteComponent? sprite)) { return; } - if (!args.Part.Owner.HasComponent()) + if (!args.Args.Part.Owner.HasComponent()) { return; } - var layers = args.Part.ToHumanoidLayers(); + var layers = args.Args.Part.ToHumanoidLayers(); // TODO BODY Layer color, sprite and state foreach (var layer in layers) sprite.LayerSetVisible(layer, true); } - public void BodyPartRemoved(BodyPartRemovedEventArgs args) + private void BodyPartRemoved(HumanoidAppearanceBodyPartRemovedEvent args) { - if (!Owner.TryGetComponent(out SpriteComponent? sprite)) + if(!EntityManager.TryGetEntity(args.Uid, out var owner)) return; + if (!owner.TryGetComponent(out SpriteComponent? sprite)) { return; } - if (!args.Part.Owner.HasComponent()) + if (!args.Args.Part.Owner.HasComponent()) { return; } - var layers = args.Part.ToHumanoidLayers(); + var layers = args.Args.Part.ToHumanoidLayers(); // TODO BODY Layer color, sprite and state foreach (var layer in layers) sprite.LayerSetVisible(layer, false); diff --git a/Content.Client/Lobby/UI/LobbyCharacterPreviewPanel.cs b/Content.Client/Lobby/UI/LobbyCharacterPreviewPanel.cs index 473ca3f496..14a6a974bc 100644 --- a/Content.Client/Lobby/UI/LobbyCharacterPreviewPanel.cs +++ b/Content.Client/Lobby/UI/LobbyCharacterPreviewPanel.cs @@ -1,8 +1,8 @@ using System.Linq; -using Content.Client.CharacterAppearance; using Content.Client.HUD.UI; using Content.Client.Inventory; using Content.Client.Preferences; +using Content.Shared.CharacterAppearance.Systems; using Content.Shared.GameTicking; using Content.Shared.Preferences; using Content.Shared.Roles; @@ -130,9 +130,7 @@ namespace Content.Client.Lobby.UI else { _summaryLabel.Text = selectedCharacter.Summary; - var component = _previewDummy.GetComponent(); - component.UpdateFromProfile(selectedCharacter); - + EntitySystem.Get().UpdateFromProfile(_previewDummy.Uid, selectedCharacter); GiveDummyJobClothes(_previewDummy, selectedCharacter); } } diff --git a/Content.Client/Preferences/UI/CharacterSetupGui.xaml.cs b/Content.Client/Preferences/UI/CharacterSetupGui.xaml.cs index c0c8ad6c42..12d37b1345 100644 --- a/Content.Client/Preferences/UI/CharacterSetupGui.xaml.cs +++ b/Content.Client/Preferences/UI/CharacterSetupGui.xaml.cs @@ -1,10 +1,10 @@ using System.Linq; -using Content.Client.CharacterAppearance; using Content.Client.Info; using Content.Client.Lobby.UI; using Content.Client.Parallax; using Content.Client.Resources; using Content.Client.Stylesheets; +using Content.Shared.CharacterAppearance.Systems; using Content.Shared.Preferences; using Content.Shared.Roles; using Robust.Client.AutoGenerated; @@ -157,7 +157,7 @@ namespace Content.Client.Preferences.UI Group = group; _previewDummy = entityManager.SpawnEntity("MobHumanDummy", MapCoordinates.Nullspace); - _previewDummy.GetComponent().UpdateFromProfile(profile); + EntitySystem.Get().UpdateFromProfile(_previewDummy.Uid, profile); var humanoid = profile as HumanoidCharacterProfile; if (humanoid != null) { diff --git a/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs b/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs index b370dcc0dd..bbd2934ee9 100644 --- a/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs +++ b/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs @@ -6,6 +6,7 @@ using Content.Client.Lobby.UI; using Content.Client.Message; using Content.Client.Stylesheets; using Content.Shared.CharacterAppearance; +using Content.Shared.CharacterAppearance.Systems; using Content.Shared.GameTicking; using Content.Shared.Preferences; using Content.Shared.Roles; @@ -596,7 +597,7 @@ namespace Content.Client.Preferences.UI if (Profile is null) return; - _previewDummy.GetComponent().UpdateFromProfile(Profile); + EntitySystem.Get().UpdateFromProfile(_previewDummy.Uid, Profile); LobbyCharacterPreviewPanel.GiveDummyJobClothes(_previewDummy, Profile); } diff --git a/Content.Server/Actions/Actions/ScreamAction.cs b/Content.Server/Actions/Actions/ScreamAction.cs index cce2098322..3a18731d17 100644 --- a/Content.Server/Actions/Actions/ScreamAction.cs +++ b/Content.Server/Actions/Actions/ScreamAction.cs @@ -1,9 +1,9 @@ -using Content.Server.CharacterAppearance.Components; using Content.Shared.ActionBlocker; using Content.Shared.Actions.Behaviors; using Content.Shared.Actions.Components; using Content.Shared.Audio; using Content.Shared.CharacterAppearance; +using Content.Shared.CharacterAppearance.Components; using Content.Shared.Cooldown; using Content.Shared.Sound; using JetBrains.Annotations; diff --git a/Content.Server/CharacterAppearance/Components/HumanoidAppearanceComponent.cs b/Content.Server/CharacterAppearance/Components/HumanoidAppearanceComponent.cs deleted file mode 100644 index f0fa65c45e..0000000000 --- a/Content.Server/CharacterAppearance/Components/HumanoidAppearanceComponent.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Content.Shared.Body.Components; -using Content.Shared.CharacterAppearance; -using Content.Shared.CharacterAppearance.Components; -using Robust.Server.GameObjects; -using Robust.Shared.GameObjects; - -namespace Content.Server.CharacterAppearance.Components -{ - [RegisterComponent] - public sealed class HumanoidAppearanceComponent : SharedHumanoidAppearanceComponent - { - public override HumanoidCharacterAppearance Appearance - { - get => base.Appearance; - set - { - base.Appearance = value; - - if (Owner.TryGetComponent(out SharedBodyComponent? body)) - { - foreach (var (part, _) in body.Parts) - { - if (!part.Owner.TryGetComponent(out SpriteComponent? sprite)) - { - continue; - } - - sprite.Color = value.SkinColor; - } - } - } - } - - protected override void Startup() - { - base.Startup(); - - if (Appearance != null! && Owner.TryGetComponent(out SharedBodyComponent? body)) - { - foreach (var (part, _) in body.Parts) - { - if (!part.Owner.TryGetComponent(out SpriteComponent? sprite)) - { - continue; - } - - sprite.Color = Appearance.SkinColor; - } - } - } - } -} diff --git a/Content.Server/CharacterAppearance/Components/MagicMirrorComponent.cs b/Content.Server/CharacterAppearance/Components/MagicMirrorComponent.cs index d7993453d0..75957f76d0 100644 --- a/Content.Server/CharacterAppearance/Components/MagicMirrorComponent.cs +++ b/Content.Server/CharacterAppearance/Components/MagicMirrorComponent.cs @@ -1,3 +1,4 @@ +using Content.Server.CharacterAppearance.Systems; using Content.Server.UserInterface; using Content.Shared.CharacterAppearance; using Content.Shared.CharacterAppearance.Components; @@ -89,6 +90,8 @@ namespace Content.Server.CharacterAppearance.Components break; } + + EntitySystem.Get().ForceAppearanceUpdate(obj.Session.AttachedEntity.Uid); } void IActivate.Activate(ActivateEventArgs eventArgs) diff --git a/Content.Server/CharacterAppearance/Systems/HumanoidAppearanceSystem.cs b/Content.Server/CharacterAppearance/Systems/HumanoidAppearanceSystem.cs new file mode 100644 index 0000000000..1482c03c31 --- /dev/null +++ b/Content.Server/CharacterAppearance/Systems/HumanoidAppearanceSystem.cs @@ -0,0 +1,32 @@ +using Content.Shared.Body.Components; +using Content.Shared.CharacterAppearance.Components; +using Content.Shared.CharacterAppearance.Systems; +using Robust.Server.GameObjects; +using Robust.Shared.GameObjects; + +namespace Content.Server.CharacterAppearance.Systems +{ + public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem + { + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(UpdateSkinColor); + } + + private void UpdateSkinColor(EntityUid uid, HumanoidAppearanceComponent component, ChangedHumanoidAppearanceEvent _) + { + if (EntityManager.TryGetComponent(uid, out SharedBodyComponent? body)) + { + foreach (var (part, _) in body.Parts) + { + if (part.Owner.TryGetComponent(out SpriteComponent? sprite)) + { + sprite!.Color = component.Appearance.SkinColor; + } + } + } + } + } +} diff --git a/Content.Server/Cloning/Components/CloningPodComponent.cs b/Content.Server/Cloning/Components/CloningPodComponent.cs index 576652f654..bbc30da4b1 100644 --- a/Content.Server/Cloning/Components/CloningPodComponent.cs +++ b/Content.Server/Cloning/Components/CloningPodComponent.cs @@ -4,6 +4,7 @@ using Content.Server.EUI; using Content.Server.Mind.Components; using Content.Server.Power.Components; using Content.Server.UserInterface; +using Content.Shared.CharacterAppearance.Systems; using Content.Shared.Cloning; using Content.Shared.MobState; using Content.Shared.Popups; @@ -136,7 +137,8 @@ namespace Content.Server.Cloning.Components var mob = Owner.EntityManager.SpawnEntity("MobHuman", Owner.Transform.MapPosition); - mob.GetComponent().UpdateFromProfile(dna.Profile); + + EntitySystem.Get().UpdateFromProfile(mob.Uid, dna.Profile); mob.Name = dna.Profile.Name; var cloneMindReturn = mob.AddComponent(); diff --git a/Content.Server/GameTicking/GameTicker.Spawning.cs b/Content.Server/GameTicking/GameTicker.Spawning.cs index b93e7789f4..546c41855c 100644 --- a/Content.Server/GameTicking/GameTicker.Spawning.cs +++ b/Content.Server/GameTicking/GameTicker.Spawning.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Globalization; using Content.Server.Access.Components; -using Content.Server.CharacterAppearance.Components; using Content.Server.Ghost.Components; using Content.Server.Hands.Components; using Content.Server.Inventory.Components; @@ -12,6 +11,7 @@ using Content.Server.Players; using Content.Server.Roles; using Content.Server.Spawners.Components; using Content.Server.Speech.Components; +using Content.Shared.CharacterAppearance.Systems; using Content.Shared.GameTicking; using Content.Shared.Ghost; using Content.Shared.Inventory; @@ -171,7 +171,7 @@ namespace Content.Server.GameTicking if (profile != null) { - entity.GetComponent().UpdateFromProfile(profile); + EntitySystem.Get().UpdateFromProfile(entity.Uid, profile); entity.Name = profile.Name; } diff --git a/Content.Shared/Body/Components/SharedBodyComponent.cs b/Content.Shared/Body/Components/SharedBodyComponent.cs index eefea7d109..f3e0326c59 100644 --- a/Content.Shared/Body/Components/SharedBodyComponent.cs +++ b/Content.Shared/Body/Components/SharedBodyComponent.cs @@ -8,6 +8,7 @@ using Content.Shared.Body.Part.Property; using Content.Shared.Body.Preset; using Content.Shared.Body.Slot; using Content.Shared.Body.Template; +using Content.Shared.CharacterAppearance.Systems; using Content.Shared.Damage; using Content.Shared.Damage.Prototypes; using Content.Shared.Movement.Components; @@ -151,6 +152,7 @@ namespace Content.Shared.Body.Components var argsAdded = new BodyPartAddedEventArgs(slot.Id, part); + EntitySystem.Get().BodyPartAdded(Owner.Uid, argsAdded); foreach (var component in Owner.GetAllComponents().ToArray()) { component.BodyPartAdded(argsAdded); @@ -177,6 +179,8 @@ namespace Content.Shared.Body.Components var args = new BodyPartRemovedEventArgs(slot.Id, part); + + EntitySystem.Get().BodyPartRemoved(Owner.Uid, args); foreach (var component in Owner.GetAllComponents()) { component.BodyPartRemoved(args); diff --git a/Content.Shared/Body/Part/IBodyPartAdded.cs b/Content.Shared/Body/Part/IBodyPartAdded.cs index d299d80541..d8d8c4a5e9 100644 --- a/Content.Shared/Body/Part/IBodyPartAdded.cs +++ b/Content.Shared/Body/Part/IBodyPartAdded.cs @@ -1,5 +1,6 @@ using System; using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; namespace Content.Shared.Body.Part { @@ -17,6 +18,8 @@ namespace Content.Shared.Body.Part void BodyPartAdded(BodyPartAddedEventArgs args); } + + [Serializable, NetSerializable] public class BodyPartAddedEventArgs : EventArgs { public BodyPartAddedEventArgs(string slot, SharedBodyPartComponent part) diff --git a/Content.Shared/Body/Part/IBodyPartRemoved.cs b/Content.Shared/Body/Part/IBodyPartRemoved.cs index 04f5d2dfb5..ae9e83ed74 100644 --- a/Content.Shared/Body/Part/IBodyPartRemoved.cs +++ b/Content.Shared/Body/Part/IBodyPartRemoved.cs @@ -1,4 +1,5 @@ using System; +using Robust.Shared.Serialization; namespace Content.Shared.Body.Part { @@ -16,6 +17,7 @@ namespace Content.Shared.Body.Part void BodyPartRemoved(BodyPartRemovedEventArgs args); } + [Serializable, NetSerializable] public class BodyPartRemovedEventArgs : EventArgs { public BodyPartRemovedEventArgs(string slot, SharedBodyPartComponent part) diff --git a/Content.Shared/CharacterAppearance/Components/HumanoidAppearanceComponent.cs b/Content.Shared/CharacterAppearance/Components/HumanoidAppearanceComponent.cs new file mode 100644 index 0000000000..555072964a --- /dev/null +++ b/Content.Shared/CharacterAppearance/Components/HumanoidAppearanceComponent.cs @@ -0,0 +1,63 @@ +using System; +using Content.Shared.CharacterAppearance; +using Content.Shared.CharacterAppearance.Systems; +using Robust.Shared.Analyzers; +using Robust.Shared.Enums; +using Robust.Shared.GameObjects; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.ViewVariables; + +namespace Content.Shared.CharacterAppearance.Components +{ + [RegisterComponent] + [Friend(typeof(SharedHumanoidAppearanceSystem), typeof(SharedMagicMirrorComponent))] + [NetworkedComponent] + public class HumanoidAppearanceComponent : Component + { + public override string Name => "HumanoidAppearance"; + + [ViewVariables] + public HumanoidCharacterAppearance Appearance { get; set; } = HumanoidCharacterAppearance.Default(); + + [ViewVariables(VVAccess.ReadWrite)] + public Sex Sex { get; set; } = default!; + + [ViewVariables(VVAccess.ReadWrite)] + public Gender Gender { get; set; } = default!; + + [DataField("categoriesHair")] + [ViewVariables] + public SpriteAccessoryCategories CategoriesHair { get; set; } = SpriteAccessoryCategories.HumanHair; + + [DataField("categoriesFacialHair")] + [ViewVariables] + public SpriteAccessoryCategories CategoriesFacialHair { get; set; } = SpriteAccessoryCategories.HumanFacialHair; + + [ViewVariables] + [DataField("canColorHair")] + public bool CanColorHair { get; set; } = true; + + [ViewVariables] + [DataField("canColorFacialHair")] + public bool CanColorFacialHair { get; set; } = true; + } + + [Serializable, NetSerializable] + public sealed class HumanoidAppearanceComponentState : ComponentState + { + public HumanoidCharacterAppearance Appearance { get; } + public Sex Sex { get; } + public Gender Gender { get; } + + public HumanoidAppearanceComponentState(HumanoidCharacterAppearance appearance, + Sex sex, + Gender gender) + { + Appearance = appearance; + Sex = sex; + Gender = gender; + } + } +} diff --git a/Content.Shared/CharacterAppearance/Components/SharedHumanoidAppearanceComponent.cs b/Content.Shared/CharacterAppearance/Components/SharedHumanoidAppearanceComponent.cs deleted file mode 100644 index 9685f00d09..0000000000 --- a/Content.Shared/CharacterAppearance/Components/SharedHumanoidAppearanceComponent.cs +++ /dev/null @@ -1,119 +0,0 @@ -using System; -using Content.Shared.Preferences; -using Robust.Shared.Enums; -using Robust.Shared.GameObjects; -using Robust.Shared.GameObjects.Components.Localization; -using Robust.Shared.GameStates; -using Robust.Shared.Players; -using Robust.Shared.Serialization; -using Robust.Shared.Serialization.Manager.Attributes; -using Robust.Shared.ViewVariables; - -namespace Content.Shared.CharacterAppearance.Components -{ - [NetworkedComponent()] - public abstract class SharedHumanoidAppearanceComponent : Component - { - private HumanoidCharacterAppearance _appearance = HumanoidCharacterAppearance.Default(); - private Sex _sex; - private Gender _gender; - - public sealed override string Name => "HumanoidAppearance"; - - [DataField("categoriesHair")] - [ViewVariables] - public SpriteAccessoryCategories CategoriesHair { get; set; } = SpriteAccessoryCategories.HumanHair; - - [DataField("categoriesFacialHair")] - [ViewVariables] - public SpriteAccessoryCategories CategoriesFacialHair { get; set; } = SpriteAccessoryCategories.HumanFacialHair; - - [ViewVariables] - [DataField("canColorHair")] - public bool CanColorHair { get; set; } = true; - - [ViewVariables] - [DataField("canColorFacialHair")] - public bool CanColorFacialHair { get; set; } = true; - - [ViewVariables(VVAccess.ReadWrite)] - public virtual HumanoidCharacterAppearance Appearance - { - get => _appearance; - set - { - _appearance = value; - Dirty(); - } - } - - [ViewVariables(VVAccess.ReadWrite)] - public virtual Sex Sex - { - get => _sex; - set - { - _sex = value; - Dirty(); - } - } - - [ViewVariables(VVAccess.ReadWrite)] - public virtual Gender Gender - { - get => _gender; - set - { - _gender = value; - - if (Owner.TryGetComponent(out GrammarComponent? g)) - { - g.Gender = value; - } - - Dirty(); - } - } - - public override ComponentState GetComponentState(ICommonSession player) - { - return new HumanoidAppearanceComponentState(Appearance, Sex, Gender); - } - - public override void HandleComponentState(ComponentState? curState, ComponentState? nextState) - { - base.HandleComponentState(curState, nextState); - - if (curState is not HumanoidAppearanceComponentState cast) - return; - - Appearance = cast.Appearance; - Sex = cast.Sex; - Gender = cast.Gender; - } - - public void UpdateFromProfile(ICharacterProfile profile) - { - var humanoid = (HumanoidCharacterProfile) profile; - Appearance = (HumanoidCharacterAppearance) humanoid.CharacterAppearance; - Sex = humanoid.Sex; - Gender = humanoid.Gender; - } - - [Serializable] - [NetSerializable] - private sealed class HumanoidAppearanceComponentState : ComponentState - { - public HumanoidAppearanceComponentState(HumanoidCharacterAppearance appearance, Sex sex, Gender gender) - { - Appearance = appearance; - Sex = sex; - Gender = gender; - } - - public HumanoidCharacterAppearance Appearance { get; } - public Sex Sex { get; } - public Gender Gender { get; } - } - } -} diff --git a/Content.Shared/CharacterAppearance/Systems/SharedHumanoidAppearanceSystem.cs b/Content.Shared/CharacterAppearance/Systems/SharedHumanoidAppearanceSystem.cs new file mode 100644 index 0000000000..1b0b5c9342 --- /dev/null +++ b/Content.Shared/CharacterAppearance/Systems/SharedHumanoidAppearanceSystem.cs @@ -0,0 +1,120 @@ +using System; +using Content.Shared.Body.Part; +using Content.Shared.CharacterAppearance.Components; +using Content.Shared.Preferences; +using Robust.Shared.Enums; +using Robust.Shared.GameObjects; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; + +namespace Content.Shared.CharacterAppearance.Systems +{ + public abstract class SharedHumanoidAppearanceSystem : EntitySystem + { + public override void Initialize() + { + SubscribeLocalEvent(OnAppearanceGetState); + SubscribeLocalEvent(OnAppearanceHandleState); + } + + public void UpdateFromProfile(EntityUid uid, ICharacterProfile profile) + { + var humanoid = (HumanoidCharacterProfile) profile; + UpdateAppearance(uid, humanoid.Appearance, humanoid.Sex, humanoid.Gender); + } + + // The magic mirror otherwise wouldn't work. (it directly modifies the component server-side) + public void ForceAppearanceUpdate(EntityUid uid, HumanoidAppearanceComponent? component = null) + { + if (!Resolve(uid, ref component)) return; + component.Dirty(); + } + + private void UpdateAppearance(EntityUid uid, HumanoidCharacterAppearance appearance, Sex sex, Gender gender, HumanoidAppearanceComponent? component = null) + { + if (!Resolve(uid, ref component)) return; + + component.Appearance = appearance; + component.Sex = sex; + component.Gender = gender; + + component.Dirty(); + + RaiseLocalEvent(uid, new ChangedHumanoidAppearanceEvent(appearance, sex, gender)); + } + + private void OnAppearanceGetState(EntityUid uid, HumanoidAppearanceComponent component, ref ComponentGetState args) + { + args.State = new HumanoidAppearanceComponentState(component.Appearance, component.Sex, component.Gender); + } + + private void OnAppearanceHandleState(EntityUid uid, HumanoidAppearanceComponent component, ref ComponentHandleState args) + { + if (args.Current is not HumanoidAppearanceComponentState state) + return; + + UpdateAppearance(uid, state.Appearance, state.Sex, state.Gender); + } + + // Scaffolding until Body is moved to ECS. + public void BodyPartAdded(EntityUid uid, BodyPartAddedEventArgs args) + { + RaiseLocalEvent(new HumanoidAppearanceBodyPartAddedEvent(uid, args)); + } + + public void BodyPartRemoved(EntityUid uid, BodyPartRemovedEventArgs args) + { + RaiseLocalEvent(new HumanoidAppearanceBodyPartRemovedEvent(uid, args)); + } + + // Scaffolding until Body is moved to ECS. + [Serializable, NetSerializable] + public class HumanoidAppearanceBodyPartAddedEvent : EntityEventArgs + { + public EntityUid Uid { get; } + public BodyPartAddedEventArgs Args { get; } + + public HumanoidAppearanceBodyPartAddedEvent(EntityUid uid, BodyPartAddedEventArgs args) + { + Uid = uid; + Args = args; + } + } + + [Serializable, NetSerializable] + public class HumanoidAppearanceBodyPartRemovedEvent : EntityEventArgs + { + public EntityUid Uid { get; } + public BodyPartRemovedEventArgs Args { get; } + + public HumanoidAppearanceBodyPartRemovedEvent(EntityUid uid, BodyPartRemovedEventArgs args) + { + Uid = uid; + Args = args; + } + + } + + [Serializable, NetSerializable] + public class ChangedHumanoidAppearanceEvent : EntityEventArgs + { + public HumanoidCharacterAppearance Appearance { get; } + public Sex Sex { get; } + public Gender Gender { get; } + + public ChangedHumanoidAppearanceEvent(HumanoidCharacterProfile profile) + { + Appearance = profile.Appearance; + Sex = profile.Sex; + Gender = profile.Gender; + } + + public ChangedHumanoidAppearanceEvent(HumanoidCharacterAppearance appearance, Sex sex, Gender gender) + { + Appearance = appearance; + Sex = sex; + Gender = gender; + } + } + } +} diff --git a/Content.Shared/Preferences/ICharacterProfile.cs b/Content.Shared/Preferences/ICharacterProfile.cs index 2efa088105..9f80350c0b 100644 --- a/Content.Shared/Preferences/ICharacterProfile.cs +++ b/Content.Shared/Preferences/ICharacterProfile.cs @@ -1,6 +1,5 @@ using Content.Shared.CharacterAppearance; - namespace Content.Shared.Preferences { public interface ICharacterProfile