Inventory slot enumerator rejig (#21788)

This commit is contained in:
Leon Friedrich
2023-12-07 16:20:51 -05:00
committed by GitHub
parent 445c474c2c
commit 287d22cc49
18 changed files with 238 additions and 342 deletions

View File

@@ -92,9 +92,9 @@ namespace Content.Server.Administration.Commands
}
var invSystem = entityManager.System<InventorySystem>();
if (invSystem.TryGetSlots(target, out var slotDefinitions, inventoryComponent))
if (invSystem.TryGetSlots(target, out var slots))
{
foreach (var slot in slotDefinitions)
foreach (var slot in slots)
{
invSystem.TryUnequip(target, slot.Name, true, true, false, inventoryComponent);
var gearStr = startingGear.GetGear(slot.Name, profile);

View File

@@ -368,15 +368,12 @@ namespace Content.Server.Administration.Systems
}
}
if (TryComp(entity.Value, out InventoryComponent? inventory) &&
_inventory.TryGetSlots(entity.Value, out var slots, inventory))
if (_inventory.TryGetContainerSlotEnumerator(entity.Value, out var enumerator))
{
foreach (var slot in slots)
while (enumerator.NextItem(out var item, out var slot))
{
if (_inventory.TryUnequip(entity.Value, entity.Value, slot.Name, out var item, true, true))
{
_physics.ApplyAngularImpulse(item.Value, ThrowingSystem.ThrowAngularImpulse);
}
if (_inventory.TryUnequip(entity.Value, entity.Value, slot.Name, true, true))
_physics.ApplyAngularImpulse(item, ThrowingSystem.ThrowAngularImpulse);
}
}

View File

@@ -285,27 +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"),
Act = () =>
{
foreach (var slot in _inventorySystem.GetSlots(args.Target))
{
if (!_inventorySystem.TryGetSlotEntity(args.Target, slot.Name, out var entity))
continue;
if (!TryComp(entity, out tank))
continue;
RefillGasTank(entity.Value, Gas.Oxygen, tank);
}
foreach (var held in _handsSystem.EnumerateHeld(args.Target))
{
if (!TryComp(held, out tank))
continue;
RefillGasTank(held, Gas.Oxygen, tank);
}
},
Act = () => RefillEquippedTanks(args.User, Gas.Oxygen),
Impact = LogImpact.Extreme,
Message = Loc.GetString("admin-trick-internals-refill-oxygen-description"),
Priority = (int) TricksVerbPriorities.RefillOxygen,
@@ -317,27 +297,7 @@ public sealed partial class AdminVerbSystem
Text = "Refill Internals Nitrogen",
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/red.rsi"), "icon"),
Act = () =>
{
foreach (var slot in _inventorySystem.GetSlots(args.Target))
{
if (!_inventorySystem.TryGetSlotEntity(args.Target, slot.Name, out var entity))
continue;
if (!TryComp(entity, out tank))
continue;
RefillGasTank(entity.Value, Gas.Nitrogen, tank);
}
foreach (var held in _handsSystem.EnumerateHeld(args.Target))
{
if (!TryComp(held, out tank))
continue;
RefillGasTank(held, Gas.Nitrogen, tank);
}
},
Act = () =>RefillEquippedTanks(args.User, Gas.Nitrogen),
Impact = LogImpact.Extreme,
Message = Loc.GetString("admin-trick-internals-refill-nitrogen-description"),
Priority = (int) TricksVerbPriorities.RefillNitrogen,
@@ -349,27 +309,7 @@ public sealed partial class AdminVerbSystem
Text = "Refill Internals Plasma",
Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/plasma.rsi"), "icon"),
Act = () =>
{
foreach (var slot in _inventorySystem.GetSlots(args.Target))
{
if (!_inventorySystem.TryGetSlotEntity(args.Target, slot.Name, out var entity))
continue;
if (!TryComp(entity, out tank))
continue;
RefillGasTank(entity.Value, Gas.Plasma, tank);
}
foreach (var held in _handsSystem.EnumerateHeld(args.Target))
{
if (!TryComp(held, out tank))
continue;
RefillGasTank(held, Gas.Plasma, tank);
}
},
Act = () => RefillEquippedTanks(args.User, Gas.Plasma),
Impact = LogImpact.Extreme,
Message = Loc.GetString("admin-trick-internals-refill-plasma-description"),
Priority = (int) TricksVerbPriorities.RefillPlasma,
@@ -792,9 +732,17 @@ public sealed partial class AdminVerbSystem
}
}
private void RefillGasTank(EntityUid tank, Gas gasType, GasTankComponent? tankComponent)
private void RefillEquippedTanks(EntityUid target, Gas plasma)
{
if (!Resolve(tank, ref tankComponent))
foreach (var held in _inventorySystem.GetHandOrInventoryEntities(target))
{
RefillGasTank(held, Gas.Plasma);
}
}
private void RefillGasTank(EntityUid tank, Gas gasType, GasTankComponent? tankComponent = null)
{
if (!Resolve(tank, ref tankComponent, false))
return;
var mixSize = tankComponent.Air.Volume;

View File

@@ -6,6 +6,7 @@ using Content.Server.Popups;
using Content.Shared.Alert;
using Content.Shared.Atmos;
using Content.Shared.DoAfter;
using Content.Shared.Hands.Components;
using Content.Shared.Internals;
using Content.Shared.Inventory;
using Content.Shared.Verbs;
@@ -26,6 +27,8 @@ public sealed class InternalsSystem : EntitySystem
[Dependency] private readonly InventorySystem _inventory = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
public const SlotFlags InventorySlots = SlotFlags.POCKET | SlotFlags.BELT;
public override void Initialize()
{
base.Initialize();
@@ -81,7 +84,7 @@ public sealed class InternalsSystem : EntitySystem
return;
}
var tank = FindBestGasTank(uid, internals);
var tank = FindBestGasTank(uid);
if (tank == null)
{
@@ -224,59 +227,35 @@ public sealed class InternalsSystem : EntitySystem
return 1;
}
public Entity<GasTankComponent>? FindBestGasTank(EntityUid internalsOwner, InternalsComponent component)
public Entity<GasTankComponent>? FindBestGasTank(Entity<HandsComponent?, InventoryComponent?, ContainerManagerComponent?> user)
{
// Prioritise
// 1. back equipped tanks
// 2. exo-slot tanks
// 3. in-hand tanks
// 4. pocket/belt tanks
InventoryComponent? inventory = null;
ContainerManagerComponent? containerManager = null;
if (_inventory.TryGetSlotEntity(internalsOwner, "back", out var backEntity, inventory, containerManager) &&
if (!Resolve(user.Owner, ref user.Comp1, ref user.Comp2, ref user.Comp3))
return null;
if (_inventory.TryGetSlotEntity(user.Owner, "back", out var backEntity, user.Comp2, user.Comp3) &&
TryComp<GasTankComponent>(backEntity, out var backGasTank) &&
_gasTank.CanConnectToInternals(backGasTank))
{
return (backEntity.Value, backGasTank);
}
if (_inventory.TryGetSlotEntity(internalsOwner, "suitstorage", out var entity, inventory, containerManager) &&
if (_inventory.TryGetSlotEntity(user.Owner, "suitstorage", out var entity, user.Comp2, user.Comp3) &&
TryComp<GasTankComponent>(entity, out var gasTank) &&
_gasTank.CanConnectToInternals(gasTank))
{
return (entity.Value, gasTank);
}
var tanks = new List<Entity<GasTankComponent>>();
foreach (var hand in _hands.EnumerateHands(internalsOwner))
foreach (var item in _inventory.GetHandOrInventoryEntities((user.Owner, user.Comp1, user.Comp2)))
{
if (TryComp(hand.HeldEntity, out gasTank) && _gasTank.CanConnectToInternals(gasTank))
tanks.Add((hand.HeldEntity.Value, gasTank));
}
if (tanks.Count > 0)
{
tanks.Sort((x, y) => y.Comp.Air.TotalMoles.CompareTo(x.Comp.Air.TotalMoles));
return tanks[0];
}
if (Resolve(internalsOwner, ref inventory, false))
{
var enumerator = new InventorySystem.ContainerSlotEnumerator(internalsOwner, inventory.TemplateId, _protoManager, _inventory, SlotFlags.POCKET | SlotFlags.BELT);
while (enumerator.MoveNext(out var container))
{
if (TryComp(container.ContainedEntity, out gasTank) && _gasTank.CanConnectToInternals(gasTank))
tanks.Add((container.ContainedEntity.Value, gasTank));
}
if (tanks.Count > 0)
{
tanks.Sort((x, y) => y.Comp.Air.TotalMoles.CompareTo(x.Comp.Air.TotalMoles));
return tanks[0];
}
if (TryComp(item, out gasTank) && _gasTank.CanConnectToInternals(gasTank))
return (item, gasTank);
}
return null;

View File

@@ -35,15 +35,13 @@ namespace Content.Server.Chemistry.EntitySystems
return;
}
if (component.BlockSlots != 0x0 && TryComp<InventoryComponent>(target, out var inventory))
if (component.BlockSlots != 0x0)
{
var containerEnumerator = new InventorySystem.ContainerSlotEnumerator(target, inventory.TemplateId, _protoManager, _inventorySystem, component.BlockSlots);
var containerEnumerator = _inventorySystem.GetSlotEnumerator(target, component.BlockSlots);
while (containerEnumerator.MoveNext(out var container))
{
if (!container.ContainedEntity.HasValue) continue;
// TODO add a helper method for this?
if (containerEnumerator.MoveNext(out _))
return;
}
}
var solRemoved = solution.SplitSolution(component.TransferAmount);

View File

@@ -25,10 +25,8 @@ namespace Content.Server.Inventory
private void OnExploded(Entity<InventoryComponent> ent, ref BeforeExplodeEvent args)
{
if (!TryGetContainerSlotEnumerator(ent, out var slots, ent.Comp))
return;
// explode each item in their inventory too
var slots = new InventorySlotEnumerator(ent);
while (slots.MoveNext(out var slot))
{
if (slot.ContainedEntity != null)
@@ -55,33 +53,16 @@ namespace Content.Server.Inventory
}
}
public void TransferEntityInventories(EntityUid uid, EntityUid target)
public void TransferEntityInventories(Entity<InventoryComponent?> source, Entity<InventoryComponent?> target)
{
if (!TryGetContainerSlotEnumerator(uid, out var enumerator))
if (!Resolve(source.Owner, ref source.Comp) || !Resolve(target.Owner, ref target.Comp))
return;
Dictionary<string, EntityUid> inventoryEntities = new();
var slots = GetSlots(uid);
while (enumerator.MoveNext(out var containerSlot))
var enumerator = new InventorySlotEnumerator(source.Comp);
while (enumerator.NextItem(out var item, out var slot))
{
//records all the entities stored in each of the target's slots
foreach (var slot in slots)
{
if (TryGetSlotContainer(target, slot.Name, out var conslot, out _) &&
conslot.ID == containerSlot.ID &&
containerSlot.ContainedEntity is { } containedEntity)
{
inventoryEntities.Add(slot.Name, containedEntity);
}
}
//drops everything in the target's inventory on the ground
TryUnequip(uid, containerSlot.ID, true, true);
}
// This takes the objects we removed and stored earlier
// and actually equips all of it to the new entity
foreach (var (slot, item) in inventoryEntities)
{
TryEquip(target, item, slot , true, true);
if (TryUnequip(source, slot.Name, true, true, inventory: source.Comp))
TryEquip(target, item, slot.Name , true, true, inventory: target.Comp);
}
}
}

View File

@@ -26,6 +26,9 @@ public sealed class StressTestMovementSystem : EntitySystem
while (query.MoveNext(out var uid, out var stressTest, out var transform))
{
if (!transform.ParentUid.IsValid())
continue;
stressTest.Progress += frameTime;
if (stressTest.Progress > 1)

View File

@@ -40,6 +40,16 @@ namespace Content.Server.Zombies
[Dependency] private readonly MobStateSystem _mobState = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
public const SlotFlags ProtectiveSlots =
SlotFlags.FEET |
SlotFlags.HEAD |
SlotFlags.EYES |
SlotFlags.GLOVES |
SlotFlags.MASK |
SlotFlags.NECK |
SlotFlags.INNERCLOTHING |
SlotFlags.OUTERCLOTHING;
public override void Initialize()
{
base.Initialize();
@@ -164,33 +174,27 @@ namespace Content.Server.Zombies
private float GetZombieInfectionChance(EntityUid uid, ZombieComponent component)
{
var baseChance = component.MaxZombieInfectionChance;
var max = component.MaxZombieInfectionChance;
if (!TryComp<InventoryComponent>(uid, out var inventoryComponent))
return baseChance;
var enumerator =
new InventorySystem.ContainerSlotEnumerator(uid, inventoryComponent.TemplateId, _protoManager, _inv,
SlotFlags.FEET |
SlotFlags.HEAD |
SlotFlags.EYES |
SlotFlags.GLOVES |
SlotFlags.MASK |
SlotFlags.NECK |
SlotFlags.INNERCLOTHING |
SlotFlags.OUTERCLOTHING);
if (!_inventory.TryGetContainerSlotEnumerator(uid, out var enumerator, ProtectiveSlots))
return max;
var items = 0f;
var total = 0f;
while (enumerator.MoveNext(out var con))
{
total++;
if (con.ContainedEntity != null)
items++;
}
var max = component.MaxZombieInfectionChance;
if (total == 0)
return max;
// Everyone knows that when it comes to zombies, socks & sandals provide just as much protection as an
// armored vest. Maybe these should be weighted per-item. I.e. some kind of coverage/protection component.
// Or at the very least different weights per slot.
var min = component.MinZombieInfectionChance;
//gets a value between the max and min based on how many items the entity is wearing
var chance = (max-min) * ((total - items)/total) + min;