More borg tweaks (#19143)

* borg tweaks but i'm gonna go code fun stuff first

* werkin' on it

* a ton of tweaks

* fuck everyone and then myself
This commit is contained in:
Nemanja
2023-08-14 19:34:23 -04:00
committed by GitHub
parent 8b0eb7e4de
commit 7ddee71379
40 changed files with 299 additions and 175 deletions

View File

@@ -10,17 +10,27 @@ namespace Content.Shared.Access.Components
/// </summary>
[RegisterComponent, NetworkedComponent]
[Access(typeof(SharedAccessSystem))]
public sealed class AccessComponent : Component
[AutoGenerateComponentState]
public sealed partial class AccessComponent : Component
{
/// <summary>
/// True if the access provider is enabled and can grant access.
/// </summary>
[DataField("enabled"), ViewVariables(VVAccess.ReadWrite)]
[AutoNetworkedField]
public bool Enabled = true;
[DataField("tags", customTypeSerializer: typeof(PrototypeIdHashSetSerializer<AccessLevelPrototype>))]
[Access(typeof(SharedAccessSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends
[AutoNetworkedField(true)]
public HashSet<string> Tags = new();
/// <summary>
/// Access Groups. These are added to the tags during map init. After map init this will have no effect.
/// </summary>
[DataField("groups", readOnly: true, customTypeSerializer: typeof(PrototypeIdHashSetSerializer<AccessGroupPrototype>))]
public readonly HashSet<string> Groups = new();
[AutoNetworkedField(true)]
public HashSet<string> Groups = new();
}
/// <summary>

View File

@@ -8,9 +8,9 @@ using Content.Shared.PDA;
using Content.Shared.StationRecords;
using Robust.Shared.Containers;
using Robust.Shared.GameStates;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Robust.Shared.Collections;
using Robust.Shared.Prototypes;
namespace Content.Shared.Access.Systems;
@@ -69,6 +69,8 @@ public sealed class AccessReaderSystem : EntitySystem
/// required entity.
/// </summary>
/// <param name="target">The entity to search for a container</param>
/// <param name="accessReader"></param>
/// <param name="result"></param>
private bool FindAccessReadersInContainer(EntityUid target, AccessReaderComponent accessReader, out List<AccessReaderComponent> result)
{
result = new();
@@ -171,6 +173,11 @@ public sealed class AccessReaderSystem : EntitySystem
{
FindAccessItemsInventory(uid, out var items);
foreach (var item in new ValueList<EntityUid>(items))
{
items.UnionWith(FindPotentialAccessItems(item));
}
var ev = new GetAdditionalAccessEvent
{
Entities = items
@@ -204,6 +211,7 @@ public sealed class AccessReaderSystem : EntitySystem
/// Finds the access tags on the given entity
/// </summary>
/// <param name="uid">The entity that is being searched.</param>
/// <param name="recordKeys"></param>
/// <param name="items">All of the items to search for access. If none are passed in, <see cref="FindPotentialAccessItems"/> will be used.</param>
public bool FindStationRecordKeys(EntityUid uid, out ICollection<StationRecordKey> recordKeys, HashSet<EntityUid>? items = null)
{
@@ -277,17 +285,6 @@ public sealed class AccessReaderSystem : EntitySystem
private bool FindAccessTagsItem(EntityUid uid, out HashSet<string> tags)
{
tags = new();
if (TryComp(uid, out AccessComponent? access))
{
tags.UnionWith(access.Tags);
}
if (TryComp(uid, out PdaComponent? pda) &&
pda.ContainedId is { Valid: true } id)
{
tags.UnionWith(EntityManager.GetComponent<AccessComponent>(id).Tags);
}
var ev = new GetAccessTagsEvent(tags, _prototype);
RaiseLocalEvent(uid, ref ev);

View File

@@ -15,28 +15,7 @@ namespace Content.Shared.Access.Systems
base.Initialize();
SubscribeLocalEvent<AccessComponent, MapInitEvent>(OnAccessInit);
SubscribeLocalEvent<AccessComponent, ComponentGetState>(OnAccessGetState);
SubscribeLocalEvent<AccessComponent, ComponentHandleState>(OnAccessHandleState);
}
private void OnAccessHandleState(EntityUid uid, AccessComponent component, ref ComponentHandleState args)
{
if (args.Current is not AccessComponentState state) return;
// Don't do = because prediction and refs
component.Tags.Clear();
component.Groups.Clear();
component.Tags.UnionWith(state.Tags);
component.Groups.UnionWith(state.Groups);
}
private void OnAccessGetState(EntityUid uid, AccessComponent component, ref ComponentGetState args)
{
args.State = new AccessComponentState()
{
Tags = component.Tags,
Groups = component.Groups,
};
SubscribeLocalEvent<AccessComponent, GetAccessTagsEvent>(OnGetAccessTags);
}
private void OnAccessInit(EntityUid uid, AccessComponent component, MapInitEvent args)
@@ -52,6 +31,22 @@ namespace Content.Shared.Access.Systems
}
}
private void OnGetAccessTags(EntityUid uid, AccessComponent component, ref GetAccessTagsEvent args)
{
if (!component.Enabled)
return;
args.Tags.UnionWith(component.Tags);
}
public void SetAccessEnabled(EntityUid uid, bool val, AccessComponent? component = null)
{
if (!Resolve(uid, ref component, false))
return;
component.Enabled = val;
Dirty(uid, component);
}
/// <summary>
/// Replaces the set of access tags we have with the provided set.
/// </summary>
@@ -122,12 +117,5 @@ namespace Content.Shared.Access.Systems
TryAddGroups(uid, prototype.ExtendedAccessGroups, access);
}
}
[Serializable, NetSerializable]
private sealed class AccessComponentState : ComponentState
{
public HashSet<string> Tags = new();
public HashSet<string> Groups = new();
}
}
}

View File

@@ -6,6 +6,10 @@ using Content.Shared.Movement.Events;
namespace Content.Shared.Interaction;
/// <summary>
/// Handles <see cref="BlockMovementComponent"/>, which prevents various
/// kinds of movement and interactions when attached to an entity.
/// </summary>
public partial class SharedInteractionSystem
{
public void InitializeBlocking()

View File

@@ -3,6 +3,9 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototy
namespace Content.Shared.NameIdentifier;
/// <summary>
/// Generates a unique numeric identifier for entities, with specifics controlled by a <see cref="NameIdentifierGroupPrototype"/>.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class NameIdentifierComponent : Component
{

View File

@@ -20,7 +20,7 @@ namespace Content.Shared.PAI
/// The last person who activated this PAI.
/// Used for assigning the name.
/// </summary>
[ViewVariables]
[DataField("lastUSer"), ViewVariables(VVAccess.ReadWrite)]
public EntityUid? LastUser;
[DataField("midiAction", required: true, serverOnly: true)] // server only, as it uses a server-BUI event !type

View File

@@ -18,8 +18,9 @@ namespace Content.Shared.PDA
SubscribeLocalEvent<PdaComponent, EntInsertedIntoContainerMessage>(OnItemInserted);
SubscribeLocalEvent<PdaComponent, EntRemovedFromContainerMessage>(OnItemRemoved);
}
SubscribeLocalEvent<PdaComponent, GetAdditionalAccessEvent>(OnGetAdditionalAccess);
}
protected virtual void OnComponentInit(EntityUid uid, PdaComponent pda, ComponentInit args)
{
if (pda.IdCard != null)
@@ -53,6 +54,12 @@ namespace Content.Shared.PDA
UpdatePdaAppearance(uid, pda);
}
private void OnGetAdditionalAccess(EntityUid uid, PdaComponent component, ref GetAdditionalAccessEvent args)
{
if (component.ContainedId is { } id)
args.Entities.Add(id);
}
private void UpdatePdaAppearance(EntityUid uid, PdaComponent pda)
{
Appearance.SetData(uid, PdaVisuals.IdCardInserted, pda.ContainedId != null);

View File

@@ -1,11 +1,7 @@
using Content.Shared.Roles;
using Content.Shared.Whitelist;
using Content.Shared.Whitelist;
using Robust.Shared.Containers;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
namespace Content.Shared.Silicons.Borgs.Components;
@@ -17,12 +13,6 @@ namespace Content.Shared.Silicons.Borgs.Components;
[RegisterComponent, NetworkedComponent, Access(typeof(SharedBorgSystem)), AutoGenerateComponentState]
public sealed partial class BorgChassisComponent : Component
{
/// <summary>
/// Whether or not the borg currently has a player occupying it
/// </summary>
[DataField("hasPlayer")]
public bool HasPlayer;
/// <summary>
/// Whether or not the borg is activated, meaning it has access to modules and a heightened movement speed
/// </summary>
@@ -43,15 +33,9 @@ public sealed partial class BorgChassisComponent : Component
public string BrainContainerId = "borg_brain";
[ViewVariables(VVAccess.ReadWrite)]
public ContainerSlot BrainContainer = default!;
public ContainerSlot BrainContainer = new();
public EntityUid? BrainEntity => BrainContainer.ContainedEntity;
/// <summary>
/// A brain entity that fills the <see cref="BrainContainer"/> on roundstart
/// </summary>
[DataField("startingBrain", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string? StartingBrain;
#endregion
#region Modules
@@ -77,33 +61,14 @@ public sealed partial class BorgChassisComponent : Component
public Container ModuleContainer = default!;
public int ModuleCount => ModuleContainer.ContainedEntities.Count;
/// <summary>
/// A list of modules that fill the borg on round start.
/// </summary>
[DataField("startingModules", customTypeSerializer: typeof(PrototypeIdListSerializer<EntityPrototype>))]
public List<string> StartingModules = new();
#endregion
/// <summary>
/// The job that corresponds to borgs
/// </summary>
[DataField("borgJobId", customTypeSerializer: typeof(PrototypeIdSerializer<JobPrototype>))]
public string BorgJobId = "Borg";
/// <summary>
/// The currently selected module
/// </summary>
[DataField("selectedModule")]
public EntityUid? SelectedModule;
/// <summary>
/// The access this cyborg has when a player is inhabiting it.
/// </summary>
[DataField("access"), ViewVariables(VVAccess.ReadWrite)]
[AutoNetworkedField]
public string AccessGroup = "AllAccess";
#region Visuals
[DataField("hasMindState")]
public string HasMindState = string.Empty;

View File

@@ -24,12 +24,21 @@ public sealed class MMIComponent : Component
[ViewVariables(VVAccess.ReadWrite)]
public ItemSlot BrainSlot = default!;
/// <summary>
/// The sprite state when the brain inserted has a mind.
/// </summary>
[DataField("hasMindState")]
public string HasMindState = "mmi_alive";
/// <summary>
/// The sprite state when the brain inserted doesn't have a mind.
/// </summary>
[DataField("noMindState")]
public string NoMindState = "mmi_dead";
/// <summary>
/// The sprite state when there is no brain inserted.
/// </summary>
[DataField("noBrainState")]
public string NoBrainState = "mmi_off";
}

View File

@@ -7,11 +7,12 @@ namespace Content.Shared.Silicons.Borgs.Components;
/// Mostly for receiving events.
/// </summary>
[RegisterComponent, NetworkedComponent, Access(typeof(SharedBorgSystem))]
public sealed class MMILinkedComponent : Component
[AutoGenerateComponentState]
public sealed partial class MMILinkedComponent : Component
{
/// <summary>
/// The MMI this entity is linked to.
/// </summary>
[DataField("linkedMMI")]
[DataField("linkedMMI"), AutoNetworkedField]
public EntityUid? LinkedMMI;
}

View File

@@ -30,7 +30,6 @@ public abstract partial class SharedBorgSystem : EntitySystem
SubscribeLocalEvent<BorgChassisComponent, EntInsertedIntoContainerMessage>(OnInserted);
SubscribeLocalEvent<BorgChassisComponent, EntRemovedFromContainerMessage>(OnRemoved);
SubscribeLocalEvent<BorgChassisComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovementSpeedModifiers);
SubscribeLocalEvent<BorgChassisComponent, GetAccessTagsEvent>(OnGetAccessTags);
InitializeRelay();
}
@@ -69,7 +68,8 @@ public abstract partial class SharedBorgSystem : EntitySystem
private void OnStartup(EntityUid uid, BorgChassisComponent component, ComponentStartup args)
{
var containerManager = EnsureComp<ContainerManagerComponent>(uid);
if (!TryComp<ContainerManagerComponent>(uid, out var containerManager))
return;
component.BrainContainer = Container.EnsureContainer<ContainerSlot>(uid, component.BrainContainerId, containerManager);
component.ModuleContainer = Container.EnsureContainer<Container>(uid, component.ModuleContainerId, containerManager);
@@ -96,12 +96,4 @@ public abstract partial class SharedBorgSystem : EntitySystem
var sprintDif = movement.BaseWalkSpeed / movement.BaseSprintSpeed;
args.ModifySpeed(1f, sprintDif);
}
private void OnGetAccessTags(EntityUid uid, BorgChassisComponent component, ref GetAccessTagsEvent args)
{
if (!component.HasPlayer)
return;
args.AddGroup(component.AccessGroup);
}
}

View File

@@ -1,14 +1,31 @@
namespace Content.Shared.Silicons.Laws.Components;
using Content.Shared.Roles;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Shared.Silicons.Laws.Components;
/// <summary>
/// This is used for an entity that grants a special "obey" law when emagge.d
/// </summary>
[RegisterComponent]
[RegisterComponent, NetworkedComponent, Access(typeof(SharedSiliconLawSystem))]
public sealed class EmagSiliconLawComponent : Component
{
/// <summary>
/// The name of the person who emagged this law provider.
/// </summary>
[DataField("ownerName")]
[DataField("ownerName"), ViewVariables(VVAccess.ReadWrite)]
public string? OwnerName;
/// <summary>
/// Does the panel need to be open to EMAG this law provider.
/// </summary>
[DataField("requireOpenPanel"), ViewVariables(VVAccess.ReadWrite)]
public bool RequireOpenPanel = true;
/// <summary>
/// A role given to entities with this component when they are emagged.
/// Mostly just for admin purposes.
/// </summary>
[DataField("antagonistRole", customTypeSerializer: typeof(PrototypeIdSerializer<AntagPrototype>))]
public string? AntagonistRole = "SubvertedSilicon";
}

View File

@@ -8,7 +8,7 @@ namespace Content.Shared.Silicons.Laws.Components;
/// <summary>
/// This is used for entities which are bound to silicon laws and can view them.
/// </summary>
[RegisterComponent]
[RegisterComponent, Access(typeof(SharedSiliconLawSystem))]
public sealed class SiliconLawBoundComponent : Component
{
/// <summary>
@@ -30,6 +30,14 @@ public sealed class SiliconLawBoundComponent : Component
public EntityUid? LastLawProvider;
}
/// <summary>
/// Event raised to get the laws that a law-bound entity has.
///
/// Is first raised on the entity itself, then on the
/// entity's station, then on the entity's grid,
/// before being broadcast.
/// </summary>
/// <param name="Entity"></param>
[ByRefEvent]
public record struct GetSiliconLawsEvent(EntityUid Entity)
{

View File

@@ -5,7 +5,7 @@ namespace Content.Shared.Silicons.Laws.Components;
/// <summary>
/// This is used for an entity which grants laws to a <see cref="SiliconLawBoundComponent"/>
/// </summary>
[RegisterComponent]
[RegisterComponent, Access(typeof(SharedSiliconLawSystem))]
public sealed class SiliconLawProviderComponent : Component
{
/// <summary>

View File

@@ -1,5 +1,7 @@
using Content.Shared.Emag.Systems;
using Content.Shared.Popups;
using Content.Shared.Silicons.Laws.Components;
using Content.Shared.Wires;
namespace Content.Shared.Silicons.Laws;
@@ -8,6 +10,8 @@ namespace Content.Shared.Silicons.Laws;
/// </summary>
public abstract class SharedSiliconLawSystem : EntitySystem
{
[Dependency] private readonly SharedPopupSystem _popup = default!;
/// <inheritdoc/>
public override void Initialize()
{
@@ -16,6 +20,14 @@ public abstract class SharedSiliconLawSystem : EntitySystem
protected virtual void OnGotEmagged(EntityUid uid, EmagSiliconLawComponent component, ref GotEmaggedEvent args)
{
if (component.RequireOpenPanel &&
TryComp<WiresPanelComponent>(uid, out var panel) &&
!panel.Open)
{
_popup.PopupClient(Loc.GetString("law-emag-require-panel"), uid, args.UserUid);
return;
}
component.OwnerName = Name(args.UserUid);
args.Handled = true;
}

View File

@@ -346,7 +346,7 @@ namespace Content.Shared.Stacks
private void OnStackGetState(EntityUid uid, StackComponent component, ref ComponentGetState args)
{
args.State = new StackComponentState(component.Count, GetMaxCount(component));
args.State = new StackComponentState(component.Count, component.MaxCountOverride, component.Lingering);
}
private void OnStackHandleState(EntityUid uid, StackComponent component, ref ComponentHandleState args)
@@ -355,6 +355,7 @@ namespace Content.Shared.Stacks
return;
component.MaxCountOverride = cast.MaxCount;
component.Lingering = cast.Lingering;
// This will change the count and call events.
SetCount(uid, cast.Count, component);
}

View File

@@ -41,7 +41,7 @@ namespace Content.Shared.Stacks
[DataField("lingering"), ViewVariables(VVAccess.ReadWrite)]
public bool Lingering;
[ViewVariables(VVAccess.ReadWrite)]
[DataField("throwIndividually"), ViewVariables(VVAccess.ReadWrite)]
public bool ThrowIndividually { get; set; } = false;
[ViewVariables]
@@ -84,12 +84,15 @@ namespace Content.Shared.Stacks
public sealed class StackComponentState : ComponentState
{
public int Count { get; }
public int MaxCount { get; }
public int? MaxCount { get; }
public StackComponentState(int count, int maxCount)
public bool Lingering;
public StackComponentState(int count, int? maxCount, bool lingering)
{
Count = count;
MaxCount = maxCount;
Lingering = lingering;
}
}
}