public bool SquashDuplicateSlotChanges() { Dictionary <int, List <SlotChangeAction> > slotChanges = new Dictionary <int, List <SlotChangeAction> >(); for (int i = 0; i < this.Actions.Count; ++i) { if (this.Actions[i] is SlotChangeAction) { SlotChangeAction action = (SlotChangeAction)this.Actions[i]; int hash = action.Inventory.GetHashCode() | action.InventorySlot; List <SlotChangeAction> list; if (slotChanges.ContainsKey(hash)) { list = slotChanges[hash]; } else { list = new List <SlotChangeAction>(); } list.Add(action); slotChanges[hash] = list; } } KeyValuePair <int, List <SlotChangeAction> >[] entries = slotChanges.ToArray(); for (int c = 0; c < entries.Length; ++c) { int hash = entries[c].Key; List <SlotChangeAction> list = entries[c].Value; if (list.Count == 1) { slotChanges.Remove(hash); continue; } List <SlotChangeAction> originalList = new List <SlotChangeAction>(list); SlotChangeAction originalAction = null; Item lastTargetItem = null; for (int i = 0; i < list.Count; ++i) { SlotChangeAction action = list[i]; if (action.IsValid(this.Player)) { originalAction = action; lastTargetItem = action.TargetItem; list.RemoveAt(i); break; } } if (originalAction == null) { return(false); } int sortedThisLoop; do { sortedThisLoop = 0; for (int i = 0; i < list.Count; ++i) { SlotChangeAction action = list[i]; Item actionSource = action.SourceItem; if (actionSource == lastTargetItem) { lastTargetItem = action.TargetItem; list.RemoveAt(i); sortedThisLoop++; } else if (actionSource.Equals(lastTargetItem, true, false, true, true)) { lastTargetItem.Count -= actionSource.Count; list.RemoveAt(i); if (lastTargetItem.Count == 0) { sortedThisLoop++; } } } } while (sortedThisLoop > 0); if (list.Count > 0) { return(false); } for (int i = 0; i < originalList.Count; ++i) { this.Actions.Remove(originalList[i]); } this.AddAction(new SlotChangeAction(originalAction.Inventory, originalAction.InventorySlot, originalAction.SourceItem, lastTargetItem)); } return(true); }
/// <inheritdoc /> protected override void HandleNormalTransaction(NormalTransaction normal) { ObservableCollection <InventoryAction> actions = new ObservableCollection <InventoryAction>(); actions.CollectionChanged += (sender, args) => { if (args.Action == NotifyCollectionChangedAction.Add) { foreach (InventoryAction add in args.NewItems) { add.OnAddToTransaction(); } } }; foreach (var transaction in normal.TransactionRecords) { var newItem = transaction.NewItem; var oldItem = transaction.OldItem; if (SlotChangeAction.EqualsExactly(newItem, oldItem)) { continue; } switch (transaction) { case WorldInteractionTransactionRecord wit: { if (wit.Slot != 0) { Log.Warn($"Got non item-drop in WorldInteractionTransactionRecord!"); InventoryMisMatch(); break; } actions.Add(new DropItemAction(newItem)); bool didMatch = false; foreach (var record in normal.RequestRecords) { foreach (var slot in record.Slots) { var item = GetContainerItem(record.ContainerId, slot); if (item.Id == wit.NewItem.Id && item.Metadata == wit.NewItem.Metadata && item.Count >= wit.NewItem.Count) { item.Count -= newItem.Count; if (DropItem(newItem, item)) { DropItem(wit.NewItem); didMatch = true; break; } else { item.Count += wit.NewItem.Count; } } } if (didMatch) { break; } } if (normal.RequestRecords.Count > 0 && !didMatch) { Log.Warn($"WorldInteractionTransactionRecord: No matching item found."); InventoryMisMatch(); return; } // Log.Info($"WorldInteractionTransactionRecord: (Flags={wit.Flags} Slot={wit.Slot} NewItem={wit.NewItem} OldItem={wit.OldItem} StackId={wit.StackNetworkId})"); } break; case ContainerTransactionRecord ctr: { // var item = GetInvItem(ctr.InventoryId, ctr.Slot); /* * if (item.Count != newItem.Count) * { * Log.Warn($"ContainerTransactionRecord invalid! Expected: {item.Count} Got: {newItem.Count} (OldItem={oldItem})"); * InventoryMisMatch(); * * return; * } */ actions.Add(new SlotChangeAction(this, ctr.InventoryId, ctr.Slot, oldItem, newItem)); //Log.Info($"ContainerTransactionRecord (InventoryId={ctr.InventoryId} Slot={ctr.Slot} StackId={ctr.StackNetworkId}) (NewItem={ctr.NewItem}) (OldItem={ctr.OldItem})"); } break; } } foreach (var action in actions) { if (!action.IsValid(this)) { Log.Info($"Invalid action: {action}"); break; } } foreach (var action in actions) { if (action.PreExecute(this)) { if (action.Execute(this)) { action.ExecutionSucceeded(this); } else { action.ExecutionFailed(this); } } } }