private void DeleteUndelete(bool redo) { bool wasDeleted = WasDeleted; // We are redoing instead of undoing, flip the behavior if (redo) { wasDeleted = !wasDeleted; } if (wasDeleted) { Debug.Assert(Receivers.All(entity => entity.GetReplacementOrThis().Removed), "Tried to redo a deletion but some items were not deleted"); List <MapEntity> clones = MapEntity.Clone(CloneList); int length = Math.Min(Receivers.Count, clones.Count); for (int i = 0; i < length; i++) { MapEntity clone = clones[i], receiver = Receivers[i]; if (receiver.GetReplacementOrThis() is Item item && clone is Item cloneItem) { foreach (ItemComponent ic in item.Components) { int index = item.GetComponentIndex(ic); ItemComponent component = cloneItem.Components.ElementAtOrDefault(index); switch (component) { case null: continue; case ItemContainer newContainer when newContainer.Inventory != null && ic is ItemContainer itemContainer && itemContainer.Inventory != null: itemContainer.Inventory.GetReplacementOrThiS().ReplacedBy = newContainer.Inventory; goto default; default: ic.GetReplacementOrThis().ReplacedBy = component; break; } } } receiver.GetReplacementOrThis().ReplacedBy = clone; } for (int i = 0; i < length; i++) { MapEntity clone = clones[i], receiver = Receivers[i]; if (clone is Item it) { foreach (var(slotRef, inventory) in PreviousInventories) { if (slotRef.Item == receiver) { inventory.GetReplacementOrThiS().TryPutItem(it, slotRef.Slot, false, false, null, createNetworkEvent: false); } } } } foreach (MapEntity clone in clones) { clone.Submarine = Submarine.MainSub; } } else { foreach (MapEntity t in Receivers) { MapEntity receiver = t.GetReplacementOrThis(); if (!receiver.Removed) { receiver.Remove(); } } } }
/// <summary> /// Creates a command where all entities share the same state. /// </summary> /// <param name="receivers">Entities that were deleted or added</param> /// <param name="wasDeleted">Whether or not all entities are or are going to be deleted</param> /// <param name="handleInventoryBehavior">Ignore item inventories when set to false, workaround for pasting</param> public AddOrDeleteCommand(List <MapEntity> receivers, bool wasDeleted, bool handleInventoryBehavior = true) { WasDeleted = wasDeleted; Receivers = receivers; try { foreach (MapEntity receiver in receivers) { if (receiver is Item it && it.ParentInventory != null) { PreviousInventories.Add(new InventorySlotItem(Array.IndexOf(it.ParentInventory.Items, it), it), it.ParentInventory); } } List <MapEntity> clonedTargets = MapEntity.Clone(receivers); List <MapEntity> itemsToDelete = new List <MapEntity>(); foreach (MapEntity receiver in Receivers) { if (receiver is Item it) { foreach (ItemContainer component in it.GetComponents <ItemContainer>()) { if (component.Inventory == null) { continue; } itemsToDelete.AddRange(component.Inventory.Items.Where(item => item != null && !item.Removed)); } } } if (itemsToDelete.Any() && handleInventoryBehavior) { ContainedItemsCommand.Add(new AddOrDeleteCommand(itemsToDelete, wasDeleted)); if (wasDeleted) { foreach (MapEntity item in itemsToDelete) { if (item != null && !item.Removed) { item.Remove(); } } } } foreach (MapEntity clone in clonedTargets) { clone.ShallowRemove(); if (clone is Item it) { foreach (ItemContainer container in it.GetComponents <ItemContainer>()) { container.Inventory?.DeleteAllItems(); } } } CloneList = clonedTargets; } // This should never happen except if we decide to make a new type of MapEntity that isn't finished yet catch (Exception e) { Receivers = new List <MapEntity>(); CloneList = new List <MapEntity>(); DebugConsole.ThrowError("Could not store object", e); } }