Skip to content

Commit

Permalink
Add pain
Browse files Browse the repository at this point in the history
  • Loading branch information
DebugOk committed Feb 12, 2024
1 parent 494aa78 commit 3e843a9
Show file tree
Hide file tree
Showing 4 changed files with 239 additions and 51 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using Content.Shared.Nyanotrasen.Item.PseudoItem;

namespace Content.Client.Nyanotrasen.Item.PseudoItem;

public sealed class PseudoItemSystem : SharedPseudoItemSystem
{
}
21 changes: 17 additions & 4 deletions Content.Server/Nyanotrasen/Item/PseudoItem/PseudoItemSystem.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
using Content.Shared.IdentityManagement;
using Content.Server.DoAfter;
using Content.Server.Item;
using Content.Server.Storage.EntitySystems;
using Content.Shared.DoAfter;
using Content.Shared.IdentityManagement;
using Content.Shared.Item;
using Content.Shared.Item.PseudoItem;
using Content.Shared.Nyanotrasen.Item.PseudoItem;
using Content.Shared.Storage;
using Content.Shared.Tag;
using Content.Shared.Verbs;

namespace Content.Server.Nyanotrasen.Item.PseudoItem;

public sealed class PseudoItemSystem : SharedPseudoItemSystem
{
[Dependency] private readonly StorageSystem _storage = default!;
[Dependency] private readonly ItemSystem _item = default!;
[Dependency] private readonly DoAfterSystem _doAfter = default!;


public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PseudoItemComponent, GetVerbsEvent<AlternativeVerb>>(AddInsertAltVerb);
}

// For whatever reason, I have to put these in server or the verbs duplicate
private void AddInsertAltVerb(EntityUid uid, PseudoItemComponent component, GetVerbsEvent<AlternativeVerb> args)
{
if (!args.CanInteract || !args.CanAccess)
Expand All @@ -21,10 +33,11 @@ private void AddInsertAltVerb(EntityUid uid, PseudoItemComponent component, GetV
if (component.Active)
return;

if (!TryComp<StorageComponent>(args.Using, out _))
if (!TryComp<StorageComponent>(args.Using, out var targetStorage))
return;

// There *should* be a check here to see if we can fit, but I'm not aware of an easy way to do that, so eh, who cares
if (!CheckItemFits((uid, component), (args.Using.Value, targetStorage)))
return;

if (args.Hands?.ActiveHandEntity == null)
return;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
using Content.Shared.Item;
using Content.Shared.Storage;

namespace Content.Shared.Nyanotrasen.Item.PseudoItem;

/// <summary>
/// Almost all of this is code taken from other systems, but adapted to use PseudoItem.
/// I couldn't use the original functions because the resolve would fuck shit up, even if I passed a constructed itemcomp
///
/// This is horrible, and I hate it. But such is life
/// </summary>
public partial class SharedPseudoItemSystem
{
protected bool CheckItemFits(Entity<PseudoItemComponent?> itemEnt, Entity<StorageComponent?> storageEnt)
{
if (!Resolve(itemEnt, ref itemEnt.Comp) || !Resolve(storageEnt, ref storageEnt.Comp))
return false;

if (Transform(itemEnt).Anchored)
return false;

if (storageEnt.Comp.Whitelist?.IsValid(itemEnt, EntityManager) == false)
return false;

if (storageEnt.Comp.Blacklist?.IsValid(itemEnt, EntityManager) == true)
return false;

var maxSize = _storage.GetMaxItemSize(storageEnt);
if (_item.GetSizePrototype(itemEnt.Comp.Size) > maxSize)
return false;

// The following is shitfucked together straight from TryGetAvailableGridSpace, but eh, it works

var itemComp = new ItemComponent
{ Size = itemEnt.Comp.Size, Shape = itemEnt.Comp.Shape, StoredOffset = itemEnt.Comp.StoredOffset };

var storageBounding = storageEnt.Comp.Grid.GetBoundingBox();

Angle startAngle;
if (storageEnt.Comp.DefaultStorageOrientation == null)
startAngle = Angle.FromDegrees(-itemComp.StoredRotation); // PseudoItem doesn't support this
else
{
if (storageBounding.Width < storageBounding.Height)
{
startAngle = storageEnt.Comp.DefaultStorageOrientation == StorageDefaultOrientation.Horizontal
? Angle.Zero
: Angle.FromDegrees(90);
}
else
{
startAngle = storageEnt.Comp.DefaultStorageOrientation == StorageDefaultOrientation.Vertical
? Angle.Zero
: Angle.FromDegrees(90);
}
}

for (var y = storageBounding.Bottom; y <= storageBounding.Top; y++)
{
for (var x = storageBounding.Left; x <= storageBounding.Right; x++)
{
for (var angle = startAngle; angle <= Angle.FromDegrees(360 - startAngle); angle += Math.PI / 2f)
{
var location = new ItemStorageLocation(angle, (x, y));
if (ItemFitsInGridLocation(itemEnt, storageEnt, location.Position, location.Rotation))
return true;
}
}
}

return false;
}

private bool ItemFitsInGridLocation(
Entity<PseudoItemComponent?> itemEnt,
Entity<StorageComponent?> storageEnt,
Vector2i position,
Angle rotation)
{
if (!Resolve(itemEnt, ref itemEnt.Comp) || !Resolve(storageEnt, ref storageEnt.Comp))
return false;

var gridBounds = storageEnt.Comp.Grid.GetBoundingBox();
if (!gridBounds.Contains(position))
return false;

var itemShape = GetAdjustedItemShape(itemEnt, rotation, position);

foreach (var box in itemShape)
{
for (var offsetY = box.Bottom; offsetY <= box.Top; offsetY++)
{
for (var offsetX = box.Left; offsetX <= box.Right; offsetX++)
{
var pos = (offsetX, offsetY);

if (!IsGridSpaceEmpty(itemEnt, storageEnt, pos, itemShape))
return false;
}
}
}

return true;
}

private IReadOnlyList<Box2i> GetAdjustedItemShape(Entity<PseudoItemComponent?> entity, Angle rotation,
Vector2i position)
{
if (!Resolve(entity, ref entity.Comp))
return new Box2i[] { };

var shapes = entity.Comp.Shape ?? _item.GetSizePrototype(entity.Comp.Size).DefaultShape;
var boundingShape = shapes.GetBoundingBox();
var boundingCenter = ((Box2) boundingShape).Center;
var matty = Matrix3.CreateTransform(boundingCenter, rotation);
var drift = boundingShape.BottomLeft - matty.TransformBox(boundingShape).BottomLeft;

var adjustedShapes = new List<Box2i>();
foreach (var shape in shapes)
{
var transformed = matty.TransformBox(shape).Translated(drift);
var floored = new Box2i(transformed.BottomLeft.Floored(), transformed.TopRight.Floored());
var translated = floored.Translated(position);

adjustedShapes.Add(translated);
}

return adjustedShapes;
}

private bool IsGridSpaceEmpty(Entity<PseudoItemComponent?> itemEnt, Entity<StorageComponent?> storageEnt,
Vector2i location, IReadOnlyList<Box2i> shape)
{
if (!Resolve(storageEnt, ref storageEnt.Comp))
return false;

var validGrid = false;
foreach (var grid in storageEnt.Comp.Grid)
{
if (grid.Contains(location))
{
validGrid = true;
break;
}
}

if (!validGrid)
return false;

foreach (var (ent, storedItem) in storageEnt.Comp.StoredItems)
{
if (ent == itemEnt.Owner)
continue;

var adjustedShape = shape;
foreach (var box in adjustedShape)
{
if (box.Contains(location))
return false;
}
}

return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@

namespace Content.Shared.Nyanotrasen.Item.PseudoItem;

public class SharedPseudoItemSystem : EntitySystem
public abstract partial class SharedPseudoItemSystem : EntitySystem
{
[Dependency] private readonly SharedStorageSystem _storageSystem = default!;
[Dependency] private readonly SharedItemSystem _itemSystem = default!;
[Dependency] private readonly SharedStorageSystem _storage = default!;
[Dependency] private readonly SharedItemSystem _item = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
[Dependency] private readonly TagSystem _tagSystem = default!;
[Dependency] private readonly TagSystem _tag = default!;

[ValidatePrototypeId<TagPrototype>]
private const string PreventTag = "PreventLabel";
Expand All @@ -29,9 +29,9 @@ public override void Initialize()
SubscribeLocalEvent<PseudoItemComponent, EntGotRemovedFromContainerMessage>(OnEntRemoved);
SubscribeLocalEvent<PseudoItemComponent, GettingPickedUpAttemptEvent>(OnGettingPickedUpAttempt);
SubscribeLocalEvent<PseudoItemComponent, DropAttemptEvent>(OnDropAttempt);
SubscribeLocalEvent<PseudoItemComponent, PseudoItemInsertDoAfterEvent>(OnDoAfter);
SubscribeLocalEvent<PseudoItemComponent, ContainerGettingInsertedAttemptEvent>(OnInsertAttempt);
SubscribeLocalEvent<PseudoItemComponent, InteractionAttemptEvent>(OnInteractAttempt);
SubscribeLocalEvent<PseudoItemComponent, PseudoItemInsertDoAfterEvent>(OnDoAfter);
}

private void AddInsertVerb(EntityUid uid, PseudoItemComponent component, GetVerbsEvent<InnateVerb> args)
Expand All @@ -45,7 +45,8 @@ private void AddInsertVerb(EntityUid uid, PseudoItemComponent component, GetVerb
if (!TryComp<StorageComponent>(args.Target, out var targetStorage))
return;

// There *should* be a check here to see if we can fit, but I'm not aware of an easy way to do that, so eh, who cares
if (!CheckItemFits((uid, component), (args.Target, targetStorage)))
return;

if (Transform(args.Target).ParentUid == uid)
return;
Expand All @@ -62,6 +63,33 @@ private void AddInsertVerb(EntityUid uid, PseudoItemComponent component, GetVerb
args.Verbs.Add(verb);
}

private bool TryInsert(EntityUid storageUid, EntityUid toInsert, PseudoItemComponent component,
StorageComponent? storage = null)
{
if (!Resolve(storageUid, ref storage))
return false;

if (!CheckItemFits((toInsert, component), (storageUid, storage)))
return false;

var itemComp = new ItemComponent
{ Size = component.Size, Shape = component.Shape, StoredOffset = component.StoredOffset };
AddComp(toInsert, itemComp);
_item.VisualsChanged(toInsert);

_tag.TryAddTag(toInsert, PreventTag);

if (!_storage.Insert(storageUid, toInsert, out _, null, storage))
{
component.Active = false;
RemComp<ItemComponent>(toInsert);
return false;
}

component.Active = true;
return true;
}

private void OnEntRemoved(EntityUid uid, PseudoItemComponent component, EntGotRemovedFromContainerMessage args)
{
if (!component.Active)
Expand All @@ -87,40 +115,31 @@ private void OnDropAttempt(EntityUid uid, PseudoItemComponent component, DropAtt
args.Cancel();
}

private void OnDoAfter(EntityUid uid, PseudoItemComponent component, DoAfterEvent args)
private void OnInsertAttempt(EntityUid uid, PseudoItemComponent component,
ContainerGettingInsertedAttemptEvent args)
{
if (args.Handled || args.Cancelled || args.Args.Used == null)
if (!component.Active)
return;

args.Handled = TryInsert(args.Args.Used.Value, uid, component);
// This hopefully shouldn't trigger, but this is a failsafe just in case so we dont bluespace them cats
args.Cancel();
}

public bool TryInsert(EntityUid storageUid, EntityUid toInsert, PseudoItemComponent component,
StorageComponent? storage = null)
// Prevents moving within the bag :)
private void OnInteractAttempt(EntityUid uid, PseudoItemComponent component, InteractionAttemptEvent args)
{
if (!Resolve(storageUid, ref storage))
return false;

// Again, here we really should check if the item will fit, but at least insert takes care of it for us by failing if not /shrug

var itemComp = new ItemComponent { Size = component.Size, Shape = component.Shape, StoredOffset = component.StoredOffset };
AddComp(toInsert, itemComp);
_itemSystem.VisualsChanged(toInsert);

_tagSystem.TryAddTag(toInsert, PreventTag);
if (args.Uid == args.Target && component.Active)
args.Cancel();
}

if (!_storageSystem.Insert(storageUid, toInsert, out _, null, storage))
{
component.Active = false;
RemComp<ItemComponent>(toInsert);
return false;
}
private void OnDoAfter(EntityUid uid, PseudoItemComponent component, DoAfterEvent args)
{
if (args.Handled || args.Cancelled || args.Args.Used == null)
return;

component.Active = true;
return true;
args.Handled = TryInsert(args.Args.Used.Value, uid, component);
}

protected internal void StartInsertDoAfter(EntityUid inserter, EntityUid toInsert, EntityUid storageEntity,
protected void StartInsertDoAfter(EntityUid inserter, EntityUid toInsert, EntityUid storageEntity,
PseudoItemComponent? pseudoItem = null)
{
if (!Resolve(toInsert, ref pseudoItem))
Expand All @@ -136,20 +155,4 @@ protected internal void StartInsertDoAfter(EntityUid inserter, EntityUid toInser

_doAfter.TryStartDoAfter(args);
}

private void OnInsertAttempt(EntityUid uid, PseudoItemComponent component,
ContainerGettingInsertedAttemptEvent args)
{
if (!component.Active)
return;
// This hopefully shouldn't trigger, but this is a failsafe just in case so we dont bluespace them cats
args.Cancel();
}

// Prevents moving within the bag :)
private void OnInteractAttempt(EntityUid uid, PseudoItemComponent component, InteractionAttemptEvent args)
{
if (args.Uid == args.Target && component.Active)
args.Cancel();
}
}

0 comments on commit 3e843a9

Please sign in to comment.