Dewarns access (#16666)
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
This commit is contained in:
@@ -11,14 +11,16 @@ public sealed class AccessOverlay : Overlay
|
||||
{
|
||||
private readonly IEntityManager _entityManager;
|
||||
private readonly EntityLookupSystem _lookup;
|
||||
private readonly SharedTransformSystem _xform;
|
||||
private readonly Font _font;
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.ScreenSpace;
|
||||
|
||||
public AccessOverlay(IEntityManager entManager, IResourceCache cache, EntityLookupSystem lookup)
|
||||
public AccessOverlay(IEntityManager entManager, IResourceCache cache, EntityLookupSystem lookup, SharedTransformSystem xform)
|
||||
{
|
||||
_entityManager = entManager;
|
||||
_lookup = lookup;
|
||||
_xform = xform;
|
||||
|
||||
_font = cache.GetFont("/Fonts/NotoSans/NotoSans-Regular.ttf", 12);
|
||||
}
|
||||
@@ -71,7 +73,7 @@ public sealed class AccessOverlay : Overlay
|
||||
textStr = "";
|
||||
}
|
||||
|
||||
var screenPos = args.ViewportControl.WorldToScreen(xform.WorldPosition);
|
||||
var screenPos = args.ViewportControl.WorldToScreen(_xform.GetWorldPosition(xform));
|
||||
|
||||
args.ScreenHandle.DrawString(_font, screenPos, textStr, Color.Gold);
|
||||
}
|
||||
|
||||
@@ -2,4 +2,6 @@ using Content.Shared.Access.Systems;
|
||||
|
||||
namespace Content.Client.Access;
|
||||
|
||||
public sealed class AccessSystem : SharedAccessSystem {}
|
||||
public sealed class AccessSystem : SharedAccessSystem
|
||||
{
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ public sealed class ShowAccessReadersCommand : IConsoleCommand
|
||||
{
|
||||
var collection = IoCManager.Instance;
|
||||
|
||||
if (collection == null) return;
|
||||
if (collection == null)
|
||||
return;
|
||||
|
||||
var overlay = collection.Resolve<IOverlayManager>();
|
||||
|
||||
@@ -25,9 +26,10 @@ public sealed class ShowAccessReadersCommand : IConsoleCommand
|
||||
|
||||
var entManager = collection.Resolve<IEntityManager>();
|
||||
var cache = collection.Resolve<IResourceCache>();
|
||||
var system = entManager.EntitySysManager.GetEntitySystem<EntityLookupSystem>();
|
||||
var lookup = entManager.System<EntityLookupSystem>();
|
||||
var xform = entManager.System<SharedTransformSystem>();
|
||||
|
||||
overlay.AddOverlay(new AccessOverlay(entManager, cache, system));
|
||||
overlay.AddOverlay(new AccessOverlay(entManager, cache, lookup, xform));
|
||||
shell.WriteLine($"Set access reader debug overlay to true");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,9 +56,10 @@ namespace Content.Client.Access.UI
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (!disposing) return;
|
||||
if (!disposing)
|
||||
return;
|
||||
|
||||
_window?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -51,7 +51,9 @@ namespace Content.Client.Access.UI
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (!disposing) return;
|
||||
if (!disposing)
|
||||
return;
|
||||
|
||||
_window?.Dispose();
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ namespace Content.Client.Access.UI
|
||||
public sealed partial class IdCardConsoleWindow : DefaultWindow
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly ILogManager _logManager = default!;
|
||||
private readonly ISawmill _logMill = default!;
|
||||
|
||||
private readonly IdCardConsoleBoundUserInterface _owner;
|
||||
|
||||
@@ -30,6 +32,7 @@ namespace Content.Client.Access.UI
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
_logMill = _logManager.GetSawmill(SharedIdCardConsoleSystem.Sawmill);
|
||||
|
||||
_owner = owner;
|
||||
|
||||
@@ -67,7 +70,7 @@ namespace Content.Client.Access.UI
|
||||
{
|
||||
if (!prototypeManager.TryIndex<AccessLevelPrototype>(access, out var accessLevel))
|
||||
{
|
||||
Logger.ErrorS(SharedIdCardConsoleSystem.Sawmill, $"Unable to find accesslevel for {access}");
|
||||
_logMill.Error($"Unable to find accesslevel for {access}");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Shared.Access;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Access.Systems;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Serilog;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Access
|
||||
{
|
||||
@@ -9,6 +13,35 @@ namespace Content.IntegrationTests.Tests.Access
|
||||
[TestOf(typeof(AccessReaderComponent))]
|
||||
public sealed class AccessReaderTest
|
||||
{
|
||||
[Test]
|
||||
public async Task TestProtoTags()
|
||||
{
|
||||
await using var pair = await PoolManager.GetServerClient(new PoolSettings() { NoClient = true });
|
||||
var server = pair.Pair.Server;
|
||||
|
||||
var protoManager = server.ResolveDependency<IPrototypeManager>();
|
||||
var accessName = server.ResolveDependency<IComponentFactory>().GetComponentName(typeof(AccessReaderComponent));
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
foreach (var ent in protoManager.EnumeratePrototypes<EntityPrototype>())
|
||||
{
|
||||
if (!ent.Components.TryGetComponent(accessName, out var access))
|
||||
continue;
|
||||
|
||||
var reader = (AccessReaderComponent) access;
|
||||
var allTags = reader.AccessLists.SelectMany(c => c).Union(reader.DenyTags);
|
||||
|
||||
foreach (var level in allTags)
|
||||
{
|
||||
Assert.That(protoManager.HasIndex<AccessLevelPrototype>(level), $"Invalid access level: {level} found on {ent}");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await pair.CleanReturnAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TestTags()
|
||||
{
|
||||
|
||||
@@ -2,5 +2,6 @@ namespace Content.Server.Access.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed class AgentIDCardComponent : Component
|
||||
{}
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,5 +4,4 @@ namespace Content.Server.Access.Systems;
|
||||
|
||||
public sealed class AccessSystem : SharedAccessSystem
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace Content.Server.Access.Systems
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metaSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -112,7 +113,7 @@ namespace Content.Server.Access.Systems
|
||||
if (player != null)
|
||||
{
|
||||
_adminLogger.Add(LogType.Identity, LogImpact.Low,
|
||||
$"{ToPrettyString(player.Value):player} has changed the job title of {ToPrettyString(id.Owner):entity} to {jobTitle} ");
|
||||
$"{ToPrettyString(player.Value):player} has changed the job title of {ToPrettyString(uid):entity} to {jobTitle} ");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -149,7 +150,7 @@ namespace Content.Server.Access.Systems
|
||||
if (player != null)
|
||||
{
|
||||
_adminLogger.Add(LogType.Identity, LogImpact.Low,
|
||||
$"{ToPrettyString(player.Value):player} has changed the name of {ToPrettyString(id.Owner):entity} to {fullName} ");
|
||||
$"{ToPrettyString(player.Value):player} has changed the name of {ToPrettyString(uid):entity} to {fullName} ");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -174,7 +175,7 @@ namespace Content.Server.Access.Systems
|
||||
: Loc.GetString("access-id-card-component-owner-full-name-job-title-text",
|
||||
("fullName", id.FullName),
|
||||
("jobSuffix", jobSuffix));
|
||||
EntityManager.GetComponent<MetaDataComponent>(id.Owner).EntityName = val;
|
||||
_metaSystem.SetEntityName(uid, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,9 +21,8 @@ public sealed class IdExaminableSystem : EntitySystem
|
||||
|
||||
private void OnGetExamineVerbs(EntityUid uid, IdExaminableComponent component, GetVerbsEvent<ExamineVerb> args)
|
||||
{
|
||||
|
||||
var detailsRange = _examineSystem.IsInDetailsRange(args.User, uid);
|
||||
var info = GetInfo(component.Owner) ?? Loc.GetString("id-examinable-component-verb-no-id");
|
||||
var info = GetInfo(uid) ?? Loc.GetString("id-examinable-component-verb-no-id");
|
||||
|
||||
var verb = new ExamineVerb()
|
||||
{
|
||||
@@ -36,7 +35,7 @@ public sealed class IdExaminableSystem : EntitySystem
|
||||
Category = VerbCategory.Examine,
|
||||
Disabled = !detailsRange,
|
||||
Message = Loc.GetString("id-examinable-component-verb-disabled"),
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/character.svg.192dpi.png"))
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/character.svg.192dpi.png"))
|
||||
};
|
||||
|
||||
args.Verbs.Add(verb);
|
||||
@@ -47,12 +46,13 @@ public sealed class IdExaminableSystem : EntitySystem
|
||||
if (_inventorySystem.TryGetSlotEntity(uid, "id", out var idUid))
|
||||
{
|
||||
// PDA
|
||||
if (EntityManager.TryGetComponent(idUid, out PdaComponent? pda) && pda.ContainedId is not null)
|
||||
if (EntityManager.TryGetComponent(idUid, out PdaComponent? pda) &&
|
||||
TryComp<IdCardComponent>(pda.ContainedId, out var id))
|
||||
{
|
||||
return GetNameAndJob(pda.ContainedId);
|
||||
return GetNameAndJob(id);
|
||||
}
|
||||
// ID Card
|
||||
if (EntityManager.TryGetComponent(idUid, out IdCardComponent? id))
|
||||
if (EntityManager.TryGetComponent(idUid, out id))
|
||||
{
|
||||
return GetNameAndJob(id);
|
||||
}
|
||||
|
||||
@@ -26,15 +26,16 @@ namespace Content.Server.Access.Systems
|
||||
{
|
||||
// Go over all ID cards and make sure they're correctly configured for extended access.
|
||||
|
||||
foreach (var card in EntityQuery<PresetIdCardComponent>())
|
||||
var query = EntityQueryEnumerator<PresetIdCardComponent>();
|
||||
while (query.MoveNext(out var uid, out var card))
|
||||
{
|
||||
var station = _stationSystem.GetOwningStation(card.Owner);
|
||||
var station = _stationSystem.GetOwningStation(uid);
|
||||
|
||||
// If we're not on an extended access station, the ID is already configured correctly from MapInit.
|
||||
if (station == null || !Comp<StationJobsComponent>(station.Value).ExtendedAccess)
|
||||
return;
|
||||
|
||||
SetupIdAccess(card.Owner, card, true);
|
||||
SetupIdAccess(uid, card, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +46,7 @@ namespace Content.Server.Access.Systems
|
||||
// or may not yet know whether it is on extended access (players not spawned yet).
|
||||
// PlayerJobsAssigned makes sure extended access is configured correctly in that case.
|
||||
|
||||
var station = _stationSystem.GetOwningStation(id.Owner);
|
||||
var station = _stationSystem.GetOwningStation(uid);
|
||||
var extended = false;
|
||||
if (station != null)
|
||||
extended = Comp<StationJobsComponent>(station.Value).ExtendedAccess;
|
||||
|
||||
@@ -2,6 +2,7 @@ using Content.Server.Administration.UI;
|
||||
using Content.Server.EUI;
|
||||
using Content.Server.Hands.Systems;
|
||||
using Content.Server.Preferences.Managers;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Inventory;
|
||||
@@ -16,7 +17,7 @@ using Robust.Shared.Prototypes;
|
||||
namespace Content.Server.Administration.Commands
|
||||
{
|
||||
[AdminCommand(AdminFlags.Admin)]
|
||||
sealed class SetOutfitCommand : IConsoleCommand
|
||||
public sealed class SetOutfitCommand : IConsoleCommand
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entities = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypes = default!;
|
||||
@@ -25,7 +26,7 @@ namespace Content.Server.Administration.Commands
|
||||
|
||||
public string Description => Loc.GetString("set-outfit-command-description", ("requiredComponent", nameof(InventoryComponent)));
|
||||
|
||||
public string Help => Loc.GetString("set-outfit-command-help-text", ("command",Command));
|
||||
public string Help => Loc.GetString("set-outfit-command-help-text", ("command", Command));
|
||||
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
@@ -51,7 +52,7 @@ namespace Content.Server.Administration.Commands
|
||||
|
||||
if (!_entities.HasComponent<InventoryComponent?>(target))
|
||||
{
|
||||
shell.WriteLine(Loc.GetString("shell-target-entity-does-not-have-message",("missing", "inventory")));
|
||||
shell.WriteLine(Loc.GetString("shell-target-entity-does-not-have-message", ("missing", "inventory")));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -106,9 +107,9 @@ namespace Content.Server.Administration.Commands
|
||||
var equipmentEntity = entityManager.SpawnEntity(gearStr, entityManager.GetComponent<TransformComponent>(target).Coordinates);
|
||||
if (slot.Name == "id" &&
|
||||
entityManager.TryGetComponent<PdaComponent?>(equipmentEntity, out var pdaComponent) &&
|
||||
pdaComponent.ContainedId != null)
|
||||
entityManager.TryGetComponent<IdCardComponent>(pdaComponent.ContainedId, out var id))
|
||||
{
|
||||
pdaComponent.ContainedId.FullName = entityManager.GetComponent<MetaDataComponent>(target).EntityName;
|
||||
id.FullName = entityManager.GetComponent<MetaDataComponent>(target).EntityName;
|
||||
}
|
||||
|
||||
invSystem.TryEquip(target, equipmentEntity, slot.Name, silent: true, force: true, inventory: inventoryComponent);
|
||||
|
||||
@@ -10,6 +10,7 @@ using Content.Server.Damage.Components;
|
||||
using Content.Server.Doors.Systems;
|
||||
using Content.Server.Hands.Systems;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server.Power.EntitySystems;
|
||||
using Content.Server.Stack;
|
||||
using Content.Server.Station.Components;
|
||||
using Content.Server.Station.Systems;
|
||||
@@ -49,6 +50,9 @@ public sealed partial class AdminVerbSystem
|
||||
[Dependency] private readonly AdminTestArenaSystem _adminTestArenaSystem = default!;
|
||||
[Dependency] private readonly StationJobsSystem _stationJobsSystem = default!;
|
||||
[Dependency] private readonly JointSystem _jointSystem = default!;
|
||||
[Dependency] private readonly BatterySystem _batterySystem = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _xformSystem = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metaSystem = default!;
|
||||
|
||||
private void AddTricksVerbs(GetVerbsEvent<Verb> args)
|
||||
{
|
||||
@@ -80,7 +84,6 @@ public sealed partial class AdminVerbSystem
|
||||
? "admin-trick-unbolt-description"
|
||||
: "admin-trick-bolt-description"),
|
||||
Priority = (int) (bolts.BoltsDown ? TricksVerbPriorities.Unbolt : TricksVerbPriorities.Bolt),
|
||||
|
||||
};
|
||||
args.Verbs.Add(bolt);
|
||||
}
|
||||
@@ -91,7 +94,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = airlock.EmergencyAccess ? "Emergency Access Off" : "Emergency Access On",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/emergency_access.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/emergency_access.png")),
|
||||
Act = () =>
|
||||
{
|
||||
_airlockSystem.ToggleEmergencyAccess(args.Target, airlock);
|
||||
@@ -100,9 +103,7 @@ public sealed partial class AdminVerbSystem
|
||||
Message = Loc.GetString(airlock.EmergencyAccess
|
||||
? "admin-trick-emergency-access-off-description"
|
||||
: "admin-trick-emergency-access-on-description"),
|
||||
Priority = (int) (airlock.EmergencyAccess
|
||||
? TricksVerbPriorities.EmergencyAccessOff
|
||||
: TricksVerbPriorities.EmergencyAccessOn),
|
||||
Priority = (int) (airlock.EmergencyAccess ? TricksVerbPriorities.EmergencyAccessOff : TricksVerbPriorities.EmergencyAccessOn),
|
||||
};
|
||||
args.Verbs.Add(emergencyAccess);
|
||||
}
|
||||
@@ -113,7 +114,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Rejuvenate",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/rejuvenate.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/rejuvenate.png")),
|
||||
Act = () =>
|
||||
{
|
||||
RejuvenateCommand.PerformRejuvenate(args.Target);
|
||||
@@ -131,7 +132,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Make Indestructible",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/plus.svg.192dpi.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/plus.svg.192dpi.png")),
|
||||
Act = () =>
|
||||
{
|
||||
_godmodeSystem.EnableGodmode(args.Target);
|
||||
@@ -148,7 +149,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Make Vulnerable",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/plus.svg.192dpi.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/plus.svg.192dpi.png")),
|
||||
Act = () =>
|
||||
{
|
||||
_godmodeSystem.DisableGodmode(args.Target);
|
||||
@@ -166,11 +167,11 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Refill Battery",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/fill_battery.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/fill_battery.png")),
|
||||
Act = () =>
|
||||
{
|
||||
battery.CurrentCharge = battery.MaxCharge;
|
||||
Dirty(battery);
|
||||
_batterySystem.SetCharge(args.Target, battery.MaxCharge, battery);
|
||||
Dirty(args.Target, battery);
|
||||
},
|
||||
Impact = LogImpact.Medium,
|
||||
Message = Loc.GetString("admin-trick-refill-battery-description"),
|
||||
@@ -182,11 +183,11 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Drain Battery",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/drain_battery.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/drain_battery.png")),
|
||||
Act = () =>
|
||||
{
|
||||
battery.CurrentCharge = 0;
|
||||
Dirty(battery);
|
||||
_batterySystem.SetCharge(args.Target, 0, battery);
|
||||
Dirty(args.Target, battery);
|
||||
},
|
||||
Impact = LogImpact.Medium,
|
||||
Message = Loc.GetString("admin-trick-drain-battery-description"),
|
||||
@@ -198,7 +199,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Infinite Battery",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/infinite_battery.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/infinite_battery.png")),
|
||||
Act = () =>
|
||||
{
|
||||
var recharger = EnsureComp<BatterySelfRechargerComponent>(args.Target);
|
||||
@@ -218,7 +219,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Block Unanchoring",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/anchor.svg.192dpi.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/anchor.svg.192dpi.png")),
|
||||
Act = () =>
|
||||
{
|
||||
RemComp(args.Target, anchor);
|
||||
@@ -236,7 +237,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Refill Internals Oxygen",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Tanks/oxygen.rsi"), "icon"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/oxygen.rsi"), "icon"),
|
||||
Act = () =>
|
||||
{
|
||||
RefillGasTank(args.Target, Gas.Oxygen, tank);
|
||||
@@ -251,7 +252,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Refill Internals Nitrogen",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Tanks/red.rsi"), "icon"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/red.rsi"), "icon"),
|
||||
Act = () =>
|
||||
{
|
||||
RefillGasTank(args.Target, Gas.Nitrogen, tank);
|
||||
@@ -266,7 +267,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Refill Internals Plasma",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Tanks/plasma.rsi"), "icon"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/plasma.rsi"), "icon"),
|
||||
Act = () =>
|
||||
{
|
||||
RefillGasTank(args.Target, Gas.Plasma, tank);
|
||||
@@ -284,7 +285,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Refill Internals Oxygen",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Tanks/oxygen.rsi"), "icon"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/oxygen.rsi"), "icon"),
|
||||
Act = () =>
|
||||
{
|
||||
foreach (var slot in _inventorySystem.GetSlots(args.Target))
|
||||
@@ -316,7 +317,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Refill Internals Nitrogen",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Tanks/red.rsi"), "icon"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/red.rsi"), "icon"),
|
||||
Act = () =>
|
||||
{
|
||||
foreach (var slot in _inventorySystem.GetSlots(args.Target))
|
||||
@@ -348,7 +349,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Refill Internals Plasma",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Tanks/plasma.rsi"), "icon"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/plasma.rsi"), "icon"),
|
||||
Act = () =>
|
||||
{
|
||||
foreach (var slot in _inventorySystem.GetSlots(args.Target))
|
||||
@@ -381,12 +382,12 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Send to test arena",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/eject.svg.192dpi.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/eject.svg.192dpi.png")),
|
||||
|
||||
Act = () =>
|
||||
{
|
||||
var (mapUid, gridUid) = _adminTestArenaSystem.AssertArenaLoaded(player);
|
||||
Transform(args.Target).Coordinates = new EntityCoordinates(gridUid ?? mapUid, Vector2.One);
|
||||
_xformSystem.SetCoordinates(args.Target, new EntityCoordinates(gridUid ?? mapUid, Vector2.One));
|
||||
},
|
||||
Impact = LogImpact.Medium,
|
||||
Message = Loc.GetString("admin-trick-send-to-test-arena-description"),
|
||||
@@ -402,7 +403,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Grant All Access",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Misc/id_cards.rsi"), "centcom"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Misc/id_cards.rsi"), "centcom"),
|
||||
Act = () =>
|
||||
{
|
||||
GiveAllAccess(activeId.Value);
|
||||
@@ -417,7 +418,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Revoke All Access",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Misc/id_cards.rsi"), "default"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Misc/id_cards.rsi"), "default"),
|
||||
Act = () =>
|
||||
{
|
||||
RevokeAllAccess(activeId.Value);
|
||||
@@ -435,7 +436,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Grant All Access",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Misc/id_cards.rsi"), "centcom"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Misc/id_cards.rsi"), "centcom"),
|
||||
Act = () =>
|
||||
{
|
||||
GiveAllAccess(args.Target);
|
||||
@@ -450,7 +451,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Revoke All Access",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Misc/id_cards.rsi"), "default"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Misc/id_cards.rsi"), "default"),
|
||||
Act = () =>
|
||||
{
|
||||
RevokeAllAccess(args.Target);
|
||||
@@ -469,7 +470,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Adjust Stack",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/adjust-stack.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/adjust-stack.png")),
|
||||
Act = () =>
|
||||
{
|
||||
// Unbounded intentionally.
|
||||
@@ -488,7 +489,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Fill Stack",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/fill-stack.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/fill-stack.png")),
|
||||
Act = () =>
|
||||
{
|
||||
_stackSystem.SetCount(args.Target, _stackSystem.GetMaxCount(stack), stack);
|
||||
@@ -504,12 +505,12 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Rename",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/rename.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/rename.png")),
|
||||
Act = () =>
|
||||
{
|
||||
_quickDialog.OpenDialog(player, "Rename", "Name", (string newName) =>
|
||||
{
|
||||
MetaData(args.Target).EntityName = newName;
|
||||
_metaSystem.SetEntityName(args.Target, newName);
|
||||
});
|
||||
},
|
||||
Impact = LogImpact.Medium,
|
||||
@@ -522,12 +523,12 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Redescribe",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/redescribe.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/redescribe.png")),
|
||||
Act = () =>
|
||||
{
|
||||
_quickDialog.OpenDialog(player, "Redescribe", "Description", (LongString newDescription) =>
|
||||
{
|
||||
MetaData(args.Target).EntityDescription = newDescription.String;
|
||||
_metaSystem.SetEntityDescription(args.Target, newDescription.String);
|
||||
});
|
||||
},
|
||||
Impact = LogImpact.Medium,
|
||||
@@ -540,15 +541,15 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Redescribe",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/rename_and_redescribe.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/rename_and_redescribe.png")),
|
||||
Act = () =>
|
||||
{
|
||||
_quickDialog.OpenDialog(player, "Rename & Redescribe", "Name", "Description",
|
||||
(string newName, LongString newDescription) =>
|
||||
{
|
||||
var meta = MetaData(args.Target);
|
||||
meta.EntityName = newName;
|
||||
meta.EntityDescription = newDescription.String;
|
||||
_metaSystem.SetEntityName(args.Target, newName, meta);
|
||||
_metaSystem.SetEntityDescription(args.Target, newDescription.String, meta);
|
||||
});
|
||||
},
|
||||
Impact = LogImpact.Medium,
|
||||
@@ -565,7 +566,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Bar job slots",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/bar_jobslots.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/bar_jobslots.png")),
|
||||
Act = () =>
|
||||
{
|
||||
foreach (var (job, _) in _stationJobsSystem.GetJobs(args.Target))
|
||||
@@ -584,7 +585,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Locate Cargo Shuttle",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Clothing/Head/Soft/cargosoft.rsi"), "icon"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Clothing/Head/Soft/cargosoft.rsi"), "icon"),
|
||||
Act = () =>
|
||||
{
|
||||
var shuttle = Comp<StationCargoOrderDatabaseComponent>(args.Target).Shuttle;
|
||||
@@ -592,7 +593,7 @@ public sealed partial class AdminVerbSystem
|
||||
if (shuttle is null)
|
||||
return;
|
||||
|
||||
Transform(args.User).Coordinates = new EntityCoordinates(shuttle.Value, Vector2.Zero);
|
||||
_xformSystem.SetCoordinates(args.User, new EntityCoordinates(shuttle.Value, Vector2.Zero));
|
||||
},
|
||||
Impact = LogImpact.Low,
|
||||
Message = Loc.GetString("admin-trick-locate-cargo-shuttle-description"),
|
||||
@@ -607,7 +608,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Refill Battery",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/fill_battery.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/fill_battery.png")),
|
||||
Act = () =>
|
||||
{
|
||||
foreach (var ent in childEnum)
|
||||
@@ -615,8 +616,8 @@ public sealed partial class AdminVerbSystem
|
||||
if (!HasComp<StationInfiniteBatteryTargetComponent>(ent))
|
||||
continue;
|
||||
var battery = EnsureComp<BatteryComponent>(ent);
|
||||
battery.CurrentCharge = battery.MaxCharge;
|
||||
Dirty(battery);
|
||||
_batterySystem.SetCharge(ent, battery.MaxCharge, battery);
|
||||
Dirty(ent, battery);
|
||||
}
|
||||
},
|
||||
Impact = LogImpact.Extreme,
|
||||
@@ -629,7 +630,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Drain Battery",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/drain_battery.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/drain_battery.png")),
|
||||
Act = () =>
|
||||
{
|
||||
foreach (var ent in childEnum)
|
||||
@@ -637,8 +638,8 @@ public sealed partial class AdminVerbSystem
|
||||
if (!HasComp<StationInfiniteBatteryTargetComponent>(ent))
|
||||
continue;
|
||||
var battery = EnsureComp<BatteryComponent>(ent);
|
||||
battery.CurrentCharge = 0;
|
||||
Dirty(battery);
|
||||
_batterySystem.SetCharge(ent, 0, battery);
|
||||
Dirty(ent, battery);
|
||||
}
|
||||
},
|
||||
Impact = LogImpact.Extreme,
|
||||
@@ -651,7 +652,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Infinite Battery",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/infinite_battery.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/infinite_battery.png")),
|
||||
Act = () =>
|
||||
{
|
||||
// this kills the sloth
|
||||
@@ -680,7 +681,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Halt Movement",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/halt.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/halt.png")),
|
||||
Act = () =>
|
||||
{
|
||||
_physics.SetLinearVelocity(args.Target, Vector2.Zero, body: physics);
|
||||
@@ -703,7 +704,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Unpause Map",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/play.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/play.png")),
|
||||
Act = () =>
|
||||
{
|
||||
_mapManager.SetMapPaused(map.MapId, false);
|
||||
@@ -720,7 +721,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Pause Map",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/pause.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/pause.png")),
|
||||
Act = () =>
|
||||
{
|
||||
_mapManager.SetMapPaused(map.MapId, true);
|
||||
@@ -740,10 +741,10 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Snap Joints",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/snap_joints.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/snap_joints.png")),
|
||||
Act = () =>
|
||||
{
|
||||
_jointSystem.ClearJoints(joints);
|
||||
_jointSystem.ClearJoints(args.Target, joints);
|
||||
},
|
||||
Impact = LogImpact.Medium,
|
||||
Message = Loc.GetString("admin-trick-snap-joints-description"),
|
||||
@@ -758,7 +759,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Make Minigun",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Weapons/Guns/HMGs/minigun.rsi"), "icon"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Weapons/Guns/HMGs/minigun.rsi"), "icon"),
|
||||
Act = () =>
|
||||
{
|
||||
gun.FireRate = 15;
|
||||
@@ -776,7 +777,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Set Bullet Amount",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Fun/caps.rsi"), "mag-6"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Fun/caps.rsi"), "mag-6"),
|
||||
Act = () =>
|
||||
{
|
||||
_quickDialog.OpenDialog(player, "Set Bullet Amount", $"Amount (max {ballisticAmmo.Capacity}):", (int amount) =>
|
||||
@@ -858,12 +859,10 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
return slotEntity.Value;
|
||||
}
|
||||
else if (TryComp<PdaComponent>(slotEntity, out var pda))
|
||||
else if (TryComp<PdaComponent>(slotEntity, out var pda)
|
||||
&& HasComp<IdCardComponent>(pda.ContainedId))
|
||||
{
|
||||
if (pda.ContainedId != null)
|
||||
{
|
||||
return pda.ContainedId.Owner;
|
||||
}
|
||||
return pda.ContainedId;
|
||||
}
|
||||
}
|
||||
else if (TryComp<HandsComponent>(target, out var hands))
|
||||
@@ -891,40 +890,40 @@ public sealed partial class AdminVerbSystem
|
||||
|
||||
private void RevokeAllAccess(EntityUid entity)
|
||||
{
|
||||
_accessSystem.TrySetTags(entity, new string[]{});
|
||||
_accessSystem.TrySetTags(entity, Array.Empty<string>());
|
||||
}
|
||||
|
||||
public enum TricksVerbPriorities
|
||||
{
|
||||
Bolt = 0,
|
||||
Unbolt = 0,
|
||||
EmergencyAccessOn = -1, // These are separate intentionally for `invokeverb` shenanigans.
|
||||
EmergencyAccessOff = -1,
|
||||
MakeIndestructible = -2,
|
||||
MakeVulnerable = -2,
|
||||
BlockUnanchoring = -3,
|
||||
RefillBattery = -4,
|
||||
DrainBattery = -5,
|
||||
RefillOxygen = -6,
|
||||
RefillNitrogen = -7,
|
||||
RefillPlasma = -8,
|
||||
SendToTestArena = -9,
|
||||
GrantAllAccess = -10,
|
||||
RevokeAllAccess = -11,
|
||||
Rejuvenate = -12,
|
||||
AdjustStack = -13,
|
||||
FillStack = -14,
|
||||
Rename = -15,
|
||||
Redescribe = -16,
|
||||
RenameAndRedescribe = -17,
|
||||
BarJobSlots = -18,
|
||||
LocateCargoShuttle = -19,
|
||||
InfiniteBattery = -20,
|
||||
HaltMovement = -21,
|
||||
Unpause = -22,
|
||||
Pause = -23,
|
||||
SnapJoints = -24,
|
||||
MakeMinigun = -25,
|
||||
SetBulletAmount = -26,
|
||||
Unbolt = -1,
|
||||
EmergencyAccessOn = -2,
|
||||
EmergencyAccessOff = -3,
|
||||
MakeIndestructible = -4,
|
||||
MakeVulnerable = -5,
|
||||
BlockUnanchoring = -6,
|
||||
RefillBattery = -7,
|
||||
DrainBattery = -8,
|
||||
RefillOxygen = -9,
|
||||
RefillNitrogen = -10,
|
||||
RefillPlasma = -11,
|
||||
SendToTestArena = -12,
|
||||
GrantAllAccess = -13,
|
||||
RevokeAllAccess = -14,
|
||||
Rejuvenate = -15,
|
||||
AdjustStack = -16,
|
||||
FillStack = -17,
|
||||
Rename = -18,
|
||||
Redescribe = -19,
|
||||
RenameAndRedescribe = -20,
|
||||
BarJobSlots = -21,
|
||||
LocateCargoShuttle = -22,
|
||||
InfiniteBattery = -23,
|
||||
HaltMovement = -24,
|
||||
Unpause = -25,
|
||||
Pause = -26,
|
||||
SnapJoints = -27,
|
||||
MakeMinigun = -28,
|
||||
SetBulletAmount = -29,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ using Content.Server.PDA.Ringer;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Server.Store.Components;
|
||||
using Content.Server.Store.Systems;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.PDA;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Player;
|
||||
@@ -117,14 +118,15 @@ namespace Content.Server.PDA
|
||||
// TODO: Update the level and name of the station with each call to UpdatePdaUi is only needed for latejoin players.
|
||||
// TODO: If someone can implement changing the level and name of the station when changing the PDA grid, this can be removed.
|
||||
|
||||
var id = CompOrNull<IdCardComponent>(pda.ContainedId);
|
||||
var state = new PdaUpdateState(
|
||||
pda.FlashlightOn,
|
||||
pda.PenSlot.HasItem,
|
||||
new PdaIdInfoText
|
||||
{
|
||||
ActualOwnerName = pda.OwnerName,
|
||||
IdOwner = pda.ContainedId?.FullName,
|
||||
JobTitle = pda.ContainedId?.JobTitle,
|
||||
IdOwner = id?.FullName,
|
||||
JobTitle = id?.JobTitle,
|
||||
StationAlertLevel = pda.StationAlertLevel,
|
||||
StationAlertColor = pda.StationAlertColor
|
||||
},
|
||||
|
||||
@@ -93,7 +93,7 @@ namespace Content.Server.Sandbox
|
||||
if (e.NewStatus != SessionStatus.Connected || e.OldStatus != SessionStatus.Connecting)
|
||||
return;
|
||||
|
||||
RaiseNetworkEvent(new MsgSandboxStatus {SandboxAllowed = IsSandboxEnabled}, e.Session.ConnectedClient);
|
||||
RaiseNetworkEvent(new MsgSandboxStatus { SandboxAllowed = IsSandboxEnabled }, e.Session.ConnectedClient);
|
||||
}
|
||||
|
||||
private void SandboxRespawnReceived(MsgSandboxRespawn message, EntitySessionEventArgs args)
|
||||
@@ -113,7 +113,7 @@ namespace Content.Server.Sandbox
|
||||
return;
|
||||
|
||||
var player = _playerManager.GetSessionByChannel(args.SenderSession.ConnectedClient);
|
||||
if (player.AttachedEntity is not {} attached)
|
||||
if (player.AttachedEntity is not { } attached)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -130,17 +130,17 @@ namespace Content.Server.Sandbox
|
||||
}
|
||||
else if (TryComp<PdaComponent>(slotEntity, out var pda))
|
||||
{
|
||||
if (pda.ContainedId == null)
|
||||
if (pda.ContainedId is null)
|
||||
{
|
||||
var newID = CreateFreshId();
|
||||
if (TryComp<ItemSlotsComponent>(pda.Owner, out var itemSlots))
|
||||
if (TryComp<ItemSlotsComponent>(slotEntity, out var itemSlots))
|
||||
{
|
||||
_slots.TryInsert(slotEntity.Value, pda.IdSlot, newID, null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UpgradeId(pda.ContainedId.Owner);
|
||||
UpgradeId(pda.ContainedId!.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -189,7 +189,7 @@ namespace Content.Server.Sandbox
|
||||
|
||||
private void UpdateSandboxStatusForAll()
|
||||
{
|
||||
RaiseNetworkEvent(new MsgSandboxStatus {SandboxAllowed = IsSandboxEnabled});
|
||||
RaiseNetworkEvent(new MsgSandboxStatus { SandboxAllowed = IsSandboxEnabled });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ using Content.Server.Mind.Commands;
|
||||
using Content.Server.PDA;
|
||||
using Content.Server.Roles;
|
||||
using Content.Server.Station.Components;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Access.Systems;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Hands.Components;
|
||||
@@ -44,6 +45,7 @@ public sealed class StationSpawningSystem : EntitySystem
|
||||
[Dependency] private readonly PdaSystem _pdaSystem = default!;
|
||||
[Dependency] private readonly SharedAccessSystem _accessSystem = default!;
|
||||
[Dependency] private readonly IdentitySystem _identity = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metaSystem = default!;
|
||||
|
||||
private bool _randomizeCharacters;
|
||||
|
||||
@@ -73,7 +75,7 @@ public sealed class StationSpawningSystem : EntitySystem
|
||||
var ev = new PlayerSpawningEvent(job, profile, station);
|
||||
RaiseLocalEvent(ev);
|
||||
|
||||
DebugTools.Assert(ev.SpawnResult is {Valid: true} or null);
|
||||
DebugTools.Assert(ev.SpawnResult is { Valid: true } or null);
|
||||
|
||||
return ev.SpawnResult;
|
||||
}
|
||||
@@ -146,7 +148,7 @@ public sealed class StationSpawningSystem : EntitySystem
|
||||
if (profile != null)
|
||||
{
|
||||
_humanoidSystem.LoadProfile(entity.Value, profile);
|
||||
MetaData(entity.Value).EntityName = profile.Name;
|
||||
_metaSystem.SetEntityName(entity.Value, profile.Name);
|
||||
if (profile.FlavorText != "" && _configurationManager.GetCVar(CCVars.FlavorText))
|
||||
{
|
||||
AddComp<DetailExaminableComponent>(entity.Value).Content = profile.FlavorText;
|
||||
@@ -158,7 +160,7 @@ public sealed class StationSpawningSystem : EntitySystem
|
||||
return entity.Value;
|
||||
}
|
||||
|
||||
private void DoJobSpecials(Job? job, EntityUid entity)
|
||||
private static void DoJobSpecials(Job? job, EntityUid entity)
|
||||
{
|
||||
foreach (var jobSpecial in job?.Prototype.Special ?? Array.Empty<JobSpecial>())
|
||||
{
|
||||
@@ -211,11 +213,10 @@ public sealed class StationSpawningSystem : EntitySystem
|
||||
if (!_inventorySystem.TryGetSlotEntity(entity, "id", out var idUid))
|
||||
return;
|
||||
|
||||
if (!EntityManager.TryGetComponent(idUid, out PdaComponent? pdaComponent) || pdaComponent.ContainedId == null)
|
||||
if (!EntityManager.TryGetComponent(idUid, out PdaComponent? pdaComponent) || !TryComp<IdCardComponent>(pdaComponent.ContainedId, out var card))
|
||||
return;
|
||||
|
||||
var card = pdaComponent.ContainedId;
|
||||
var cardId = card.Owner;
|
||||
var cardId = pdaComponent.ContainedId.Value;
|
||||
_cardSystem.TryChangeFullName(cardId, characterName, card);
|
||||
_cardSystem.TryChangeJobTitle(cardId, jobPrototype.LocalizedName, card);
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ public sealed class StationRecordsSystem : EntitySystem
|
||||
string? jobId, StationRecordsComponent? records = null)
|
||||
{
|
||||
if (!Resolve(station, ref records)
|
||||
|| String.IsNullOrEmpty(jobId)
|
||||
|| string.IsNullOrEmpty(jobId)
|
||||
|| !_prototypeManager.HasIndex<JobPrototype>(jobId))
|
||||
{
|
||||
return;
|
||||
@@ -204,7 +204,7 @@ public sealed class StationRecordsSystem : EntitySystem
|
||||
{
|
||||
if (!Resolve(station, ref records))
|
||||
{
|
||||
return new (StationRecordKey, T)[]{};
|
||||
return Array.Empty<(StationRecordKey, T)>();
|
||||
}
|
||||
|
||||
return records.Records.GetRecordsOfType<T>();
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Content.Server.Verbs.Commands
|
||||
}
|
||||
|
||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
||||
var verbSystem = EntitySystem.Get<SharedVerbSystem>();
|
||||
var verbSystem = entityManager.System<SharedVerbSystem>();
|
||||
|
||||
// get the 'player' entity (defaulting to command user, otherwise uses a uid)
|
||||
EntityUid? playerEntity = null;
|
||||
|
||||
@@ -14,6 +14,6 @@ public sealed class AccessGroupPrototype : IPrototype
|
||||
[IdDataField]
|
||||
public string ID { get; } = default!;
|
||||
|
||||
[DataField("tags", required: true, customTypeSerializer:typeof(PrototypeIdHashSetSerializer<AccessLevelPrototype>))]
|
||||
[DataField("tags", required: true, customTypeSerializer: typeof(PrototypeIdHashSetSerializer<AccessLevelPrototype>))]
|
||||
public HashSet<string> Tags = default!;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using Content.Shared.Access.Systems;
|
||||
using Content.Shared.StationRecords;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
@@ -59,4 +58,3 @@ public sealed class AccessReaderComponentState : ComponentState
|
||||
AccessKeys = accessKeys;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Content.Shared.Access.Systems;
|
||||
using Content.Shared.PDA;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Access.Components
|
||||
{
|
||||
@@ -17,8 +16,7 @@ namespace Content.Shared.Access.Components
|
||||
|
||||
[DataField("jobTitle")]
|
||||
[AutoNetworkedField]
|
||||
[Access(typeof(SharedIdCardSystem), typeof(SharedPdaSystem), typeof(SharedAgentIdCardSystem),
|
||||
Other = AccessPermissions.ReadWrite)]
|
||||
[Access(typeof(SharedIdCardSystem), typeof(SharedPdaSystem), typeof(SharedAgentIdCardSystem), Other = AccessPermissions.ReadWrite)]
|
||||
public string? JobTitle;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ namespace Content.Shared.Access.Systems
|
||||
public sealed class AgentIDCardJobChangedMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public string Job { get; }
|
||||
|
||||
public AgentIDCardJobChangedMessage(string job)
|
||||
{
|
||||
Job = job;
|
||||
|
||||
@@ -11,286 +11,272 @@ using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.StationRecords;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Access.Systems
|
||||
namespace Content.Shared.Access.Systems;
|
||||
|
||||
public sealed class AccessReaderSystem : EntitySystem
|
||||
{
|
||||
public sealed class AccessReaderSystem : EntitySystem
|
||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
base.Initialize();
|
||||
|
||||
public override void Initialize()
|
||||
SubscribeLocalEvent<AccessReaderComponent, GotEmaggedEvent>(OnEmagged);
|
||||
SubscribeLocalEvent<AccessReaderComponent, LinkAttemptEvent>(OnLinkAttempt);
|
||||
|
||||
SubscribeLocalEvent<AccessReaderComponent, ComponentGetState>(OnGetState);
|
||||
SubscribeLocalEvent<AccessReaderComponent, ComponentHandleState>(OnHandleState);
|
||||
}
|
||||
|
||||
private void OnGetState(EntityUid uid, AccessReaderComponent component, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new AccessReaderComponentState(component.Enabled, component.DenyTags, component.AccessLists,
|
||||
component.AccessKeys);
|
||||
}
|
||||
|
||||
private void OnHandleState(EntityUid uid, AccessReaderComponent component, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not AccessReaderComponentState state)
|
||||
return;
|
||||
component.Enabled = state.Enabled;
|
||||
component.AccessKeys = new (state.AccessKeys);
|
||||
component.AccessLists = new (state.AccessLists);
|
||||
component.DenyTags = new (state.DenyTags);
|
||||
}
|
||||
|
||||
private void OnLinkAttempt(EntityUid uid, AccessReaderComponent component, LinkAttemptEvent args)
|
||||
{
|
||||
if (args.User == null) // AutoLink (and presumably future external linkers) have no user.
|
||||
return;
|
||||
if (!HasComp<EmaggedComponent>(uid) && !IsAllowed(args.User.Value, component))
|
||||
args.Cancel();
|
||||
}
|
||||
|
||||
private void OnEmagged(EntityUid uid, AccessReaderComponent reader, ref GotEmaggedEvent args)
|
||||
{
|
||||
args.Handled = true;
|
||||
reader.Enabled = false;
|
||||
Dirty(reader);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches the source for access tags
|
||||
/// then compares it with the targets readers access list to see if it is allowed.
|
||||
/// </summary>
|
||||
/// <param name="source">The entity that wants access.</param>
|
||||
/// <param name="target">The entity to search for an access reader</param>
|
||||
/// <param name="reader">Optional reader from the target entity</param>
|
||||
public bool IsAllowed(EntityUid source, EntityUid target, AccessReaderComponent? reader = null)
|
||||
{
|
||||
if (!Resolve(target, ref reader, false))
|
||||
return true;
|
||||
return IsAllowed(source, reader);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches the given entity for access tags
|
||||
/// then compares it with the readers access list to see if it is allowed.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity that wants access.</param>
|
||||
/// <param name="reader">A reader from a different entity</param>
|
||||
public bool IsAllowed(EntityUid entity, AccessReaderComponent reader)
|
||||
{
|
||||
var allEnts = FindPotentialAccessItems(entity);
|
||||
|
||||
// Access reader is totally disabled, so access is always allowed.
|
||||
if (!reader.Enabled)
|
||||
return true;
|
||||
|
||||
if (AreAccessTagsAllowed(FindAccessTags(entity, allEnts), reader))
|
||||
return true;
|
||||
|
||||
if (AreStationRecordKeysAllowed(FindStationRecordKeys(entity, allEnts), reader))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares the given tags with the readers access list to see if it is allowed.
|
||||
/// </summary>
|
||||
/// <param name="accessTags">A list of access tags</param>
|
||||
/// <param name="reader">An access reader to check against</param>
|
||||
public bool AreAccessTagsAllowed(ICollection<string> accessTags, AccessReaderComponent reader)
|
||||
{
|
||||
if (reader.DenyTags.Overlaps(accessTags))
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<AccessReaderComponent, ComponentInit>(OnInit);
|
||||
SubscribeLocalEvent<AccessReaderComponent, GotEmaggedEvent>(OnEmagged);
|
||||
SubscribeLocalEvent<AccessReaderComponent, LinkAttemptEvent>(OnLinkAttempt);
|
||||
|
||||
SubscribeLocalEvent<AccessReaderComponent, ComponentGetState>(OnGetState);
|
||||
SubscribeLocalEvent<AccessReaderComponent, ComponentHandleState>(OnHandleState);
|
||||
}
|
||||
|
||||
private void OnGetState(EntityUid uid, AccessReaderComponent component, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new AccessReaderComponentState(component.Enabled, component.DenyTags, component.AccessLists,
|
||||
component.AccessKeys);
|
||||
}
|
||||
|
||||
private void OnHandleState(EntityUid uid, AccessReaderComponent component, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not AccessReaderComponentState state)
|
||||
return;
|
||||
component.Enabled = state.Enabled;
|
||||
component.AccessKeys = new (state.AccessKeys);
|
||||
component.AccessLists = new (state.AccessLists);
|
||||
component.DenyTags = new (state.DenyTags);
|
||||
}
|
||||
|
||||
private void OnLinkAttempt(EntityUid uid, AccessReaderComponent component, LinkAttemptEvent args)
|
||||
{
|
||||
if (args.User == null) // AutoLink (and presumably future external linkers) have no user.
|
||||
return;
|
||||
if (!HasComp<EmaggedComponent>(uid) && !IsAllowed(args.User.Value, component))
|
||||
args.Cancel();
|
||||
}
|
||||
|
||||
private void OnInit(EntityUid uid, AccessReaderComponent reader, ComponentInit args)
|
||||
{
|
||||
var allTags = reader.AccessLists.SelectMany(c => c).Union(reader.DenyTags);
|
||||
foreach (var level in allTags)
|
||||
{
|
||||
if (!_prototypeManager.HasIndex<AccessLevelPrototype>(level))
|
||||
{
|
||||
Logger.ErrorS("access", $"Invalid access level: {level}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEmagged(EntityUid uid, AccessReaderComponent reader, ref GotEmaggedEvent args)
|
||||
{
|
||||
args.Handled = true;
|
||||
reader.Enabled = false;
|
||||
Dirty(reader);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches the source for access tags
|
||||
/// then compares it with the targets readers access list to see if it is allowed.
|
||||
/// </summary>
|
||||
/// <param name="source">The entity that wants access.</param>
|
||||
/// <param name="target">The entity to search for an access reader</param>
|
||||
/// <param name="reader">Optional reader from the target entity</param>
|
||||
public bool IsAllowed(EntityUid source, EntityUid target, AccessReaderComponent? reader = null)
|
||||
{
|
||||
if (!Resolve(target, ref reader, false))
|
||||
return true;
|
||||
return IsAllowed(source, reader);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches the given entity for access tags
|
||||
/// then compares it with the readers access list to see if it is allowed.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity that wants access.</param>
|
||||
/// <param name="reader">A reader from a different entity</param>
|
||||
public bool IsAllowed(EntityUid entity, AccessReaderComponent reader)
|
||||
{
|
||||
var allEnts = FindPotentialAccessItems(entity);
|
||||
|
||||
// Access reader is totally disabled, so access is always allowed.
|
||||
if (!reader.Enabled)
|
||||
return true;
|
||||
|
||||
if (AreAccessTagsAllowed(FindAccessTags(entity, allEnts), reader))
|
||||
return true;
|
||||
|
||||
if (AreStationRecordKeysAllowed(FindStationRecordKeys(entity, allEnts), reader))
|
||||
return true;
|
||||
// Sec owned by cargo.
|
||||
|
||||
// Note that in resolving the issue with only one specific item "counting" for access, this became a bit more strict.
|
||||
// As having an ID card in any slot that "counts" with a denied access group will cause denial of access.
|
||||
// DenyTags doesn't seem to be used right now anyway, though, so it'll be dependent on whoever uses it to figure out if this matters.
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares the given tags with the readers access list to see if it is allowed.
|
||||
/// </summary>
|
||||
/// <param name="accessTags">A list of access tags</param>
|
||||
/// <param name="reader">An access reader to check against</param>
|
||||
public bool AreAccessTagsAllowed(ICollection<string> accessTags, AccessReaderComponent reader)
|
||||
return reader.AccessLists.Count == 0 || reader.AccessLists.Any(a => a.IsSubsetOf(accessTags));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares the given stationrecordkeys with the accessreader to see if it is allowed.
|
||||
/// </summary>
|
||||
public bool AreStationRecordKeysAllowed(ICollection<StationRecordKey> keys, AccessReaderComponent reader)
|
||||
{
|
||||
return keys.Any() && reader.AccessKeys.Any(keys.Contains);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds all the items that could potentially give access to a given entity
|
||||
/// </summary>
|
||||
public HashSet<EntityUid> FindPotentialAccessItems(EntityUid uid)
|
||||
{
|
||||
FindAccessItemsInventory(uid, out var items);
|
||||
|
||||
var ev = new GetAdditionalAccessEvent
|
||||
{
|
||||
if (reader.DenyTags.Overlaps(accessTags))
|
||||
{
|
||||
// Sec owned by cargo.
|
||||
Entities = items
|
||||
};
|
||||
RaiseLocalEvent(uid, ref ev);
|
||||
items.Add(uid);
|
||||
return items;
|
||||
}
|
||||
|
||||
// Note that in resolving the issue with only one specific item "counting" for access, this became a bit more strict.
|
||||
// As having an ID card in any slot that "counts" with a denied access group will cause denial of access.
|
||||
// DenyTags doesn't seem to be used right now anyway, though, so it'll be dependent on whoever uses it to figure out if this matters.
|
||||
return false;
|
||||
}
|
||||
/// <summary>
|
||||
/// Finds the access tags on the given entity
|
||||
/// </summary>
|
||||
/// <param name="uid">The entity that is being searched.</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 ICollection<string> FindAccessTags(EntityUid uid, HashSet<EntityUid>? items = null)
|
||||
{
|
||||
HashSet<string>? tags = null;
|
||||
var owned = false;
|
||||
|
||||
return reader.AccessLists.Count == 0 || reader.AccessLists.Any(a => a.IsSubsetOf(accessTags));
|
||||
items ??= FindPotentialAccessItems(uid);
|
||||
|
||||
foreach (var ent in items)
|
||||
{
|
||||
FindAccessTagsItem(ent, ref tags, ref owned);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares the given stationrecordkeys with the accessreader to see if it is allowed.
|
||||
/// </summary>
|
||||
public bool AreStationRecordKeysAllowed(ICollection<StationRecordKey> keys, AccessReaderComponent reader)
|
||||
return (ICollection<string>?) tags ?? Array.Empty<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the access tags on the given entity
|
||||
/// </summary>
|
||||
/// <param name="uid">The entity that is being searched.</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 ICollection<StationRecordKey> FindStationRecordKeys(EntityUid uid, HashSet<EntityUid>? items = null)
|
||||
{
|
||||
HashSet<StationRecordKey> keys = new();
|
||||
|
||||
items ??= FindPotentialAccessItems(uid);
|
||||
|
||||
foreach (var ent in items)
|
||||
{
|
||||
return keys.Any() && reader.AccessKeys.Any(keys.Contains);
|
||||
if (FindStationRecordKeyItem(ent, out var key))
|
||||
keys.Add(key.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds all the items that could potentially give access to a given entity
|
||||
/// </summary>
|
||||
public HashSet<EntityUid> FindPotentialAccessItems(EntityUid uid)
|
||||
{
|
||||
FindAccessItemsInventory(uid, out var items);
|
||||
return keys;
|
||||
}
|
||||
|
||||
var ev = new GetAdditionalAccessEvent
|
||||
{
|
||||
Entities = items
|
||||
};
|
||||
RaiseLocalEvent(uid, ref ev);
|
||||
items.Add(uid);
|
||||
return items;
|
||||
/// <summary>
|
||||
/// Try to find <see cref="AccessComponent"/> on this item
|
||||
/// or inside this item (if it's pda)
|
||||
/// This version merges into a set or replaces the set.
|
||||
/// If owned is false, the existing tag-set "isn't ours" and can't be merged with (is read-only).
|
||||
/// </summary>
|
||||
private void FindAccessTagsItem(EntityUid uid, ref HashSet<string>? tags, ref bool owned)
|
||||
{
|
||||
if (!FindAccessTagsItem(uid, out var targetTags))
|
||||
{
|
||||
// no tags, no problem
|
||||
return;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the access tags on the given entity
|
||||
/// </summary>
|
||||
/// <param name="uid">The entity that is being searched.</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 ICollection<string> FindAccessTags(EntityUid uid, HashSet<EntityUid>? items = null)
|
||||
if (tags != null)
|
||||
{
|
||||
HashSet<string>? tags = null;
|
||||
var owned = false;
|
||||
|
||||
items ??= FindPotentialAccessItems(uid);
|
||||
|
||||
foreach (var ent in items)
|
||||
// existing tags, so copy to make sure we own them
|
||||
if (!owned)
|
||||
{
|
||||
FindAccessTagsItem(ent, ref tags, ref owned);
|
||||
tags = new(tags);
|
||||
owned = true;
|
||||
}
|
||||
|
||||
return (ICollection<string>?) tags ?? Array.Empty<string>();
|
||||
// then merge
|
||||
tags.UnionWith(targetTags);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the access tags on the given entity
|
||||
/// </summary>
|
||||
/// <param name="uid">The entity that is being searched.</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 ICollection<StationRecordKey> FindStationRecordKeys(EntityUid uid, HashSet<EntityUid>? items = null)
|
||||
else
|
||||
{
|
||||
HashSet<StationRecordKey> keys = new();
|
||||
|
||||
items ??= FindPotentialAccessItems(uid);
|
||||
|
||||
foreach (var ent in items)
|
||||
{
|
||||
if (FindStationRecordKeyItem(ent, out var key))
|
||||
keys.Add(key.Value);
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to find <see cref="AccessComponent"/> on this item
|
||||
/// or inside this item (if it's pda)
|
||||
/// This version merges into a set or replaces the set.
|
||||
/// If owned is false, the existing tag-set "isn't ours" and can't be merged with (is read-only).
|
||||
/// </summary>
|
||||
private void FindAccessTagsItem(EntityUid uid, ref HashSet<string>? tags, ref bool owned)
|
||||
{
|
||||
if (!FindAccessTagsItem(uid, out var targetTags))
|
||||
{
|
||||
// no tags, no problem
|
||||
return;
|
||||
}
|
||||
if (tags != null)
|
||||
{
|
||||
// existing tags, so copy to make sure we own them
|
||||
if (!owned)
|
||||
{
|
||||
tags = new(tags);
|
||||
owned = true;
|
||||
}
|
||||
// then merge
|
||||
tags.UnionWith(targetTags);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no existing tags, so now they're ours
|
||||
tags = targetTags;
|
||||
owned = false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool FindAccessItemsInventory(EntityUid uid, out HashSet<EntityUid> items)
|
||||
{
|
||||
items = new();
|
||||
|
||||
foreach (var item in _handsSystem.EnumerateHeld(uid))
|
||||
{
|
||||
items.Add(item);
|
||||
}
|
||||
|
||||
// maybe its inside an inventory slot?
|
||||
if (_inventorySystem.TryGetSlotEntity(uid, "id", out var idUid))
|
||||
{
|
||||
items.Add(idUid.Value);
|
||||
}
|
||||
|
||||
return items.Any();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to find <see cref="AccessComponent"/> on this item
|
||||
/// or inside this item (if it's pda)
|
||||
/// </summary>
|
||||
private bool FindAccessTagsItem(EntityUid uid, [NotNullWhen(true)] out HashSet<string>? tags)
|
||||
{
|
||||
if (TryComp(uid, out AccessComponent? access))
|
||||
{
|
||||
tags = access.Tags;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TryComp(uid, out PdaComponent? pda) &&
|
||||
pda.ContainedId?.Owner is {Valid: true} id)
|
||||
{
|
||||
tags = EntityManager.GetComponent<AccessComponent>(id).Tags;
|
||||
return true;
|
||||
}
|
||||
|
||||
tags = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to find <see cref="StationRecordKeyStorageComponent"/> on this item
|
||||
/// or inside this item (if it's pda)
|
||||
/// </summary>
|
||||
private bool FindStationRecordKeyItem(EntityUid uid, [NotNullWhen(true)] out StationRecordKey? key)
|
||||
{
|
||||
if (TryComp(uid, out StationRecordKeyStorageComponent? storage) && storage.Key != null)
|
||||
{
|
||||
key = storage.Key;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TryComp<PdaComponent>(uid, out var pda) &&
|
||||
pda.ContainedId?.Owner is {Valid: true} id)
|
||||
{
|
||||
if (TryComp<StationRecordKeyStorageComponent>(id, out var pdastorage) && pdastorage.Key != null)
|
||||
{
|
||||
key = pdastorage.Key;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
key = null;
|
||||
return false;
|
||||
// no existing tags, so now they're ours
|
||||
tags = targetTags;
|
||||
owned = false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool FindAccessItemsInventory(EntityUid uid, out HashSet<EntityUid> items)
|
||||
{
|
||||
items = new();
|
||||
|
||||
foreach (var item in _handsSystem.EnumerateHeld(uid))
|
||||
{
|
||||
items.Add(item);
|
||||
}
|
||||
|
||||
// maybe its inside an inventory slot?
|
||||
if (_inventorySystem.TryGetSlotEntity(uid, "id", out var idUid))
|
||||
{
|
||||
items.Add(idUid.Value);
|
||||
}
|
||||
|
||||
return items.Any();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to find <see cref="AccessComponent"/> on this item
|
||||
/// or inside this item (if it's pda)
|
||||
/// </summary>
|
||||
private bool FindAccessTagsItem(EntityUid uid, [NotNullWhen(true)] out HashSet<string>? tags)
|
||||
{
|
||||
if (TryComp(uid, out AccessComponent? access))
|
||||
{
|
||||
tags = access.Tags;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TryComp(uid, out PdaComponent? pda) &&
|
||||
pda.ContainedId is { Valid: true } id)
|
||||
{
|
||||
tags = EntityManager.GetComponent<AccessComponent>(id).Tags;
|
||||
return true;
|
||||
}
|
||||
|
||||
tags = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to find <see cref="StationRecordKeyStorageComponent"/> on this item
|
||||
/// or inside this item (if it's pda)
|
||||
/// </summary>
|
||||
private bool FindStationRecordKeyItem(EntityUid uid, [NotNullWhen(true)] out StationRecordKey? key)
|
||||
{
|
||||
if (TryComp(uid, out StationRecordKeyStorageComponent? storage) && storage.Key != null)
|
||||
{
|
||||
key = storage.Key;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TryComp<PdaComponent>(uid, out var pda) &&
|
||||
pda.ContainedId is { Valid: true } id)
|
||||
{
|
||||
if (TryComp<StationRecordKeyStorageComponent>(id, out var pdastorage) && pdastorage.Key != null)
|
||||
{
|
||||
key = pdastorage.Key;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
key = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ public abstract class SharedIdCardSystem : EntitySystem
|
||||
public bool TryFindIdCard(EntityUid uid, [NotNullWhen(true)] out IdCardComponent? idCard)
|
||||
{
|
||||
// check held item?
|
||||
if (EntityManager.TryGetComponent(uid, out HandsComponent? hands) &&
|
||||
if (TryComp(uid, out HandsComponent? hands) &&
|
||||
hands.ActiveHandEntity is EntityUid heldItem &&
|
||||
TryGetIdCard(heldItem, out idCard))
|
||||
{
|
||||
@@ -30,9 +30,7 @@ public abstract class SharedIdCardSystem : EntitySystem
|
||||
|
||||
// check inventory slot?
|
||||
if (_inventorySystem.TryGetSlotEntity(uid, "id", out var idUid) && TryGetIdCard(idUid.Value, out idCard))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -43,12 +41,12 @@ public abstract class SharedIdCardSystem : EntitySystem
|
||||
/// </summary>
|
||||
public bool TryGetIdCard(EntityUid uid, [NotNullWhen(true)] out IdCardComponent? idCard)
|
||||
{
|
||||
if (EntityManager.TryGetComponent(uid, out idCard))
|
||||
if (TryComp(uid, out idCard))
|
||||
return true;
|
||||
|
||||
if (EntityManager.TryGetComponent(uid, out PdaComponent? pda) && pda.ContainedId != null)
|
||||
if (TryComp(uid, out PdaComponent? pda)
|
||||
&& TryComp(pda.ContainedId, out idCard))
|
||||
{
|
||||
idCard = pda.ContainedId;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Content.Shared.PDA
|
||||
[DataField("id", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||
public string? IdCard;
|
||||
|
||||
[ViewVariables] public IdCardComponent? ContainedId;
|
||||
[ViewVariables] public EntityUid? ContainedId;
|
||||
[ViewVariables] public bool FlashlightOn;
|
||||
|
||||
[ViewVariables] public string? OwnerName;
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace Content.Shared.PDA
|
||||
protected virtual void OnItemInserted(EntityUid uid, PdaComponent pda, EntInsertedIntoContainerMessage args)
|
||||
{
|
||||
if (args.Container.ID == PdaComponent.PdaIdSlotId)
|
||||
pda.ContainedId = CompOrNull<IdCardComponent>(args.Entity);
|
||||
pda.ContainedId = args.Entity;
|
||||
|
||||
UpdatePdaAppearance(uid, pda);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user