Example #1
0
        public Task Handle(OrderTransactionEvent evnt)
        {
            _state.HandledTransactions.TryPeek(out var handledTransaction);
            if (handledTransaction == evnt.EntityId)
            {
                // If we've already handled this event through the evaluator,
                // we don't want to mess with credits and inventory
                _state.HandledTransactions.Dequeue();
                return(Task.CompletedTask);
            }

            var fromOrder = _state.Orders[evnt.FromSellOrder];
            var toOrder   = _state.Orders[evnt.ToBuyOrder];

            fromOrder.QuantityFulfilled += evnt.Quantity;
            toOrder.QuantityFulfilled   += evnt.Quantity;

            fromOrder.Owner.Credits += evnt.Price;
            toOrder.Owner.Credits   -= evnt.Price;

            fromOrder.Owner.Inventory[evnt.ItemId].Quantity -= evnt.Quantity;

            if (toOrder.Owner.Inventory.TryGetValue(evnt.ItemId, out var inventory))
            {
                inventory.Quantity += evnt.Quantity;
            }
            else
            {
                toOrder.Owner.Inventory.Add(evnt.ItemId, new WarehouseInventory
                {
                    ItemId   = evnt.ItemId,
                    Quantity = evnt.Quantity,
                });
            }

            return(Task.CompletedTask);
        }
Example #2
0
        private IEnumerable <IEvent> EvaluateBuyOrder(
            BrokerOrder buyOrder,
            BrokerOrder sellOrder,
            long quantityToSell,
            State state)
        {
            // The quantity one order can buy will be the least of either:
            // 1. As much as the buyer can buy (credits)
            // 2. As much as the seller can sell (inventory/order size)
            // 3. As much as the buyer wants to buy (order size)
            if (sellOrder.Price == 0)
            {
                yield break;
            }
            var affordableQuantity = buyOrder.Owner.Credits / sellOrder.Price;
            var quantityToBuy      = Math.Min(affordableQuantity, quantityToSell); // Case 1 & 2

            if (buyOrder.Quantity != -1)                                           // Case 3
            {
                quantityToBuy = Math.Min(quantityToBuy, buyOrder.Quantity - buyOrder.QuantityFulfilled);
            }

            var evnt = new OrderTransactionEvent(Guid.NewGuid(), _initiator)
            {
                FromPlayer    = sellOrder.Owner.PlayerId,
                ToPlayer      = buyOrder.Owner.PlayerId,
                FromSellOrder = sellOrder.OrderId,
                ToBuyOrder    = buyOrder.OrderId,
                ItemId        = sellOrder.ItemId,
                Quantity      = quantityToBuy,
                Price         = quantityToBuy * sellOrder.Price,
            };

            buyOrder.Owner.Credits  -= evnt.Price;
            sellOrder.Owner.Credits += evnt.Price;

            buyOrder.QuantityFulfilled  += evnt.Quantity;
            sellOrder.QuantityFulfilled += evnt.Quantity;

            UpdatePlayerInventory(buyOrder.Owner, evnt.ItemId, evnt.Quantity);
            UpdatePlayerInventory(sellOrder.Owner, evnt.ItemId, -evnt.Quantity);

            state.HandledTransactions.Enqueue(evnt.EntityId);
            yield return(evnt);

            yield return(new OrderPartiallyFulfilledEvent(buyOrder.OrderId, _initiator)
            {
                TransactionId = evnt.EntityId,
                Price = evnt.Price,
                QuantityFulfilled = evnt.Quantity,
            });

            yield return(new OrderPartiallyFulfilledEvent(sellOrder.OrderId, _initiator)
            {
                TransactionId = evnt.EntityId,
                Price = evnt.Price,
                QuantityFulfilled = evnt.Quantity,
            });

            yield return(new PlayerBalanceChangedEvent(buyOrder.Owner.PlayerId, _initiator)
            {
                TransactionId = evnt.EntityId,
                BalanceChange = -evnt.Price,
            });

            yield return(new PlayerBalanceChangedEvent(sellOrder.Owner.PlayerId, _initiator)
            {
                TransactionId = evnt.EntityId,
                BalanceChange = evnt.Price,
            });

            yield return(new PlayerInventoryChangedEvent(buyOrder.Owner.PlayerId, _initiator)
            {
                TransactionId = evnt.EntityId,
                InventoryChange = new[]
                {
                    new LuaItemStack
                    {
                        Name = evnt.ItemId,
                        Count = evnt.Quantity,
                    },
                },
            });

            yield return(new PlayerInventoryChangedEvent(sellOrder.Owner.PlayerId, _initiator)
            {
                TransactionId = evnt.EntityId,
                InventoryChange = new[]
                {
                    new LuaItemStack
                    {
                        Name = evnt.ItemId,
                        Count = -evnt.Quantity,
                    },
                },
            });

            if (buyOrder.Quantity != -1 && buyOrder.QuantityFulfilled >= buyOrder.Quantity)
            {
                yield return(new OrderFulfilledEvent(buyOrder.OrderId, _initiator));

                buyOrder.State = OrderState.Fulfilled;
                _logger.Information($"Buy order ${buyOrder.OrderId} completely fulfilled!");
            }
        }