public void Test() { IThingFactory factory = Registry.Factory.Create <IThingFactory>(); IThing thing = factory.CreateItem(); Assert.AreEqual(typeof(Thing), thing.GetType()); Assert.IsInstanceOf(typeof(IThing), thing); thing = factory.CreateItem <object>(null); Assert.AreEqual(typeof(Thing), thing.GetType()); Assert.IsInstanceOf(typeof(IThing), thing); thing = factory.CreateItem <Empty>(new Empty()); Assert.AreEqual(typeof(Thing), thing.GetType()); Assert.IsInstanceOf(typeof(IThing), thing); thing = factory.CreateItem(new Empty()); Assert.AreEqual(typeof(Thing), thing.GetType()); Assert.IsInstanceOf(typeof(IThing), thing); thing = factory.CreateItem(""); Assert.IsInstanceOf(typeof(IThing <string>), thing); thing = factory.CreateItem <object>(""); Assert.IsInstanceOf(typeof(IThing <string>), thing); thing = factory.CreateItem(0); Assert.IsInstanceOf(typeof(INumberThing), thing); thing = factory.CreateItem <object>(0); Assert.IsInstanceOf(typeof(INumberThing), thing); thing = factory.CreateItem(0f); Assert.IsInstanceOf(typeof(INumberThing), thing); thing = factory.CreateItem <object>(0f); Assert.IsInstanceOf(typeof(INumberThing), thing); thing = factory.CreateItem(0d); Assert.IsInstanceOf(typeof(INumberThing), thing); thing = factory.CreateItem <object>(0d); Assert.IsInstanceOf(typeof(INumberThing), thing); thing = factory.CreateItem(DateTime.Now); Assert.IsInstanceOf(typeof(INumberThing), thing); thing = factory.CreateItem <object>(DateTime.Now); Assert.IsInstanceOf(typeof(INumberThing), thing); thing = factory.CreateItem(new Quad16(0, 0, 0, 0)); Assert.IsInstanceOf(typeof(INumberThing), thing); thing = factory.CreateItem <object>(new Quad16(0, 0, 0, 0)); Assert.IsInstanceOf(typeof(INumberThing), thing); using (var stream = new MemoryStream()) { thing = factory.CreateItem(stream); Assert.IsInstanceOf(typeof(IStreamThing), thing); thing = factory.CreateItem <object> (stream); Assert.IsInstanceOf(typeof(IStreamThing), thing); } thing = factory.CreateItem <Stream>(null); Assert.IsInstanceOf(typeof(IStreamThing), thing); }
/// <summary> /// Attempts to replace a <see cref="IThing"/> from this container with another. /// </summary> /// <param name="thingFactory">A reference to the factory of things to use.</param> /// <param name="fromThing">The <see cref="IThing"/> to remove from the container.</param> /// <param name="toThing">The <see cref="IThing"/> to add to the container.</param> /// <param name="index">Optional. The index from which to replace the <see cref="IThing"/>. Defaults to byte.MaxValue, which instructs to replace the <see cref="IThing"/> if found at any index.</param> /// <param name="amount">Optional. The amount of the <paramref name="fromThing"/> to replace.</param> /// <returns>A tuple with a value indicating whether the attempt was at least partially successful, and false otherwise. If the result was only partially successful, a remainder of the thing may be returned.</returns> public (bool result, IThing remainderToChange) ReplaceContent(IThingFactory thingFactory, IThing fromThing, IThing toThing, byte index = byte.MaxValue, byte amount = 1) { if (this.Inventory[index] is IContainerItem bodyContainer) { return(bodyContainer.ReplaceContent(thingFactory, fromThing, toThing, DefaultBodyContainerIndex, amount)); } return(false, fromThing); }
public void TestIThingFactory() { IThingFactory itf = ThingFactory.GiveMeAFactory(); IThing thing = itf .AddInteger(94) .AddString("hello, world") .Create(); Assert.AreEqual(94, thing.SomeIntegerFunction(8)); Assert.AreEqual("goodbye", thing.SaySomething("g'day")); }
/// <summary> /// Attempts to remove a thing from this container. /// </summary> /// <param name="thingFactory">A reference to the factory of things to use.</param> /// <param name="thing">The <see cref="IThing"/> to remove from the container.</param> /// <param name="index">Optional. The index from which to remove the <see cref="IThing"/>. Defaults to byte.MaxValue, which instructs to remove the <see cref="IThing"/> if found at any index.</param> /// <param name="amount">Optional. The amount of the <paramref name="thing"/> to remove.</param> /// <returns>A tuple with a value indicating whether the attempt was at least partially successful, and false otherwise. If the result was only partially successful, a remainder of the thing may be returned.</returns> public virtual (bool result, IThing remainder) RemoveContent(IThingFactory thingFactory, ref IThing thing, byte index = byte.MaxValue, byte amount = 1) { thingFactory.ThrowIfNull(nameof(thingFactory)); thing.ThrowIfNull(nameof(thing)); if (!(thingFactory is IItemFactory itemFactory)) { throw new ArgumentException($"The {nameof(thingFactory)} must be derived of type {nameof(IItemFactory)}."); } IItem existingItem = null; ushort thingId = thing.TypeId; if (index == byte.MaxValue) { existingItem = this.Content.FirstOrDefault(i => i.TypeId == thingId); } else { // Attempt to get the item at that index. existingItem = index >= this.Content.Count ? null : this.Content[index]; } if (existingItem == null || thing.TypeId != existingItem.TypeId || existingItem.Amount < amount) { return(false, null); } if (!existingItem.IsCumulative || existingItem.Amount == amount) { // Item has the exact amount we're looking for, just remove it. this.Content.RemoveAt(index); this.InvokeContentRemoved(index); return(true, null); } (bool success, IItem itemProduced) = existingItem.Split(itemFactory, amount); if (success) { if (itemProduced != null) { thing = itemProduced; } // We've changed an item at this index, so we notify observers. this.InvokeContentUpdated(index, existingItem); } return(success, existingItem); }
public static IThingFactory ThingFactory(this IGraph <IVisual, IVisualEdge> graph) { IThingFactory result = null; var sourceGraph = graph.Source <IVisual, IVisualEdge, IThing, ILink>(); if (sourceGraph != null) { var adapter = sourceGraph.Mapper.Transformer as VisualThingTransformer; result = adapter?.ThingFactory; } if (result == null) { result = Registry.Factory.Create <IThingFactory>(); } return(result); }
/// <summary> /// Attempts to replace a <see cref="IThing"/> from this container with another. /// </summary> /// <param name="thingFactory">A reference to the factory of things to use.</param> /// <param name="fromThing">The <see cref="IThing"/> to remove from the container.</param> /// <param name="toThing">The <see cref="IThing"/> to add to the container.</param> /// <param name="index">Optional. The index from which to replace the <see cref="IThing"/>. Defaults to byte.MaxValue, which instructs to replace the <see cref="IThing"/> if found at any index.</param> /// <param name="amount">Optional. The amount of the <paramref name="fromThing"/> to replace.</param> /// <returns>A tuple with a value indicating whether the attempt was at least partially successful, and false otherwise. If the result was only partially successful, a remainder of the thing may be returned.</returns> public (bool result, IThing remainderToChange) ReplaceContent(IThingFactory thingFactory, IThing fromThing, IThing toThing, byte index = byte.MaxValue, byte amount = 1) { (bool removeSuccessful, IThing removeRemainder) = this.RemoveContent(thingFactory, ref fromThing, index, amount); if (!removeSuccessful) { return(false, removeRemainder); } if (removeRemainder != null) { (bool addedRemainder, IThing remainderOfRemainder) = this.AddContent(thingFactory, removeRemainder, byte.MaxValue); if (!addedRemainder) { return(false, remainderOfRemainder); } } return(this.AddContent(thingFactory, toThing, index)); }
/// <summary> /// Attempts to replace a <see cref="IThing"/> from this container with another. /// </summary> /// <param name="thingFactory">A reference to the factory of things to use.</param> /// <param name="fromThing">The <see cref="IThing"/> to remove from the container.</param> /// <param name="toThing">The <see cref="IThing"/> to add to the container.</param> /// <param name="index">Optional. The index from which to replace the <see cref="IThing"/>. Defaults to byte.MaxValue, which instructs to replace the <see cref="IThing"/> if found at any index.</param> /// <param name="amount">Optional. The amount of the <paramref name="fromThing"/> to replace.</param> /// <returns>A tuple with a value indicating whether the attempt was at least partially successful, and false otherwise. If the result was only partially successful, a remainder of the thing may be returned.</returns> public (bool result, IThing remainderToChange) ReplaceContent(IThingFactory thingFactory, IThing fromThing, IThing toThing, byte index = byte.MaxValue, byte amount = 1) { thingFactory.ThrowIfNull(nameof(thingFactory)); fromThing.ThrowIfNull(nameof(fromThing)); toThing.ThrowIfNull(nameof(toThing)); if (!(thingFactory is IItemFactory itemFactory)) { throw new ArgumentException($"The {nameof(thingFactory)} must be derived of type {nameof(IItemFactory)}."); } IItem existingItem = null; if (index == byte.MaxValue) { existingItem = this.Content.FirstOrDefault(i => i.TypeId == fromThing.TypeId); } else { // Attempt to get the item at that index. existingItem = index >= this.Content.Count ? null : this.Content[index]; } if (existingItem == null || fromThing.TypeId != existingItem.TypeId || existingItem.Amount < amount) { return(false, null); } this.Content.RemoveAt(index); this.Content.Insert(index, toThing as IItem); toThing.ParentContainer = this; // We've changed an item at this index, so we notify observers. this.InvokeContentUpdated(index, toThing as IItem); return(true, null); }
/// <summary> /// Attempts to remove a thing from this container. /// </summary> /// <param name="thingFactory">A reference to the factory of things to use.</param> /// <param name="thing">The <see cref="IThing"/> to remove from the container.</param> /// <param name="index">Optional. The index from which to remove the <see cref="IThing"/>. Defaults to byte.MaxValue, which instructs to remove the <see cref="IThing"/> if found at any index.</param> /// <param name="amount">Optional. The amount of the <paramref name="thing"/> to remove.</param> /// <returns>A tuple with a value indicating whether the attempt was at least partially successful, and false otherwise. If the result was only partially successful, a remainder of the thing may be returned.</returns> public (bool result, IThing remainder) RemoveContent(IThingFactory thingFactory, ref IThing thing, byte index = byte.MaxValue, byte amount = 1) { // TODO: try to delete from that specific body container. throw new NotImplementedException(); }
/// <summary> /// Attempts to add a <see cref="IThing"/> to this container. /// </summary> /// <param name="thingFactory">A reference to the factory of things to use.</param> /// <param name="thing">The <see cref="IThing"/> to add to the container.</param> /// <param name="index">Optional. The index at which to add the <see cref="IThing"/>. Defaults to byte.MaxValue, which instructs to add the <see cref="IThing"/> at any free index.</param> /// <returns>A tuple with a value indicating whether the attempt was at least partially successful, and false otherwise. If the result was only partially successful, a remainder of the thing may be returned.</returns> public (bool result, IThing remainder) AddContent(IThingFactory thingFactory, IThing thing, byte index = byte.MaxValue) { // TODO: try to add at that specific body container. return(false, thing); }
public ThingContentFacade(IThingFactory factory) { _factory = factory; }
public ThingModelBinder(IThingFactory thingFactory) { this.IThingFactory = thingFactory; }
/// <summary> /// Initializes a new instance of the <see cref="WorldGenerator"/> class. /// </summary> /// <param name="seed">The seed to use.</param> /// <param name="thingFactory">The thing factory.</param> public WorldGenerator(int seed, IThingFactory thingFactory) { this.Seed = seed; this.Random = new Random(this.Seed); this.thingFactory = thingFactory; }
/// <summary> /// Initializes a new instance of the <see cref="WorldGenerator"/> class. /// </summary> /// <param name="thingFactory">The thing factory.</param> public WorldGenerator(IThingFactory thingFactory) { this.Seed = new Random().Next(); this.Random = new Random(this.Seed); this.thingFactory = thingFactory; }
/// <summary> /// Attempts to add a <see cref="IThing"/> to this container. /// </summary> /// <param name="thingFactory">A reference to the factory of things to use.</param> /// <param name="thing">The <see cref="IThing"/> to add to the container.</param> /// <param name="index">Optional. The index at which to add the <see cref="IThing"/>. Defaults to byte.MaxValue, which instructs to add the <see cref="IThing"/> at any free index.</param> /// <returns>A tuple with a value indicating whether the attempt was at least partially successful, and false otherwise. If the result was only partially successful, a remainder of the thing may be returned.</returns> public override (bool result, IThing remainder) AddContent(IThingFactory thingFactory, IThing thing, byte index = byte.MaxValue) { thingFactory.ThrowIfNull(nameof(thingFactory)); thing.ThrowIfNull(nameof(thing)); if (!(thingFactory is IItemFactory itemFactory)) { throw new ArgumentException($"The {nameof(thingFactory)} must be derived of type {nameof(IItemFactory)}."); } if (!(thing is IItem item)) { // Containers like this can only add items. return(false, null); } // Validate that the item being added is not a parent of this item. if (this.IsChildOf(item) || !this.CanDressItemHere(item)) { // TODO: error message 'This is impossible'. return(false, thing); } // Find an index which falls in within the actual content boundaries. var targetIndex = index < this.Content.Count ? index : -1; // Then get an item if there is one, at that index. var existingItemAtIndex = targetIndex == -1 ? this.Content.FirstOrDefault() : this.Content[targetIndex]; (bool success, IThing remainderItem) = (false, item); if (existingItemAtIndex != null) { // We matched with an item, let's attempt to add or join with it first. if (existingItemAtIndex.IsContainer && existingItemAtIndex is IContainerItem existingContainer) { return(existingContainer.AddContent(itemFactory, remainderItem)); } else { (success, remainderItem) = existingItemAtIndex.Merge(remainderItem as IItem); if (success) { // Regardless if we're done, we've changed an item at this index, so we notify observers. this.InvokeContentUpdated((byte)targetIndex, remainderItem as IItem); } } } if (success) { // If we have partially succeeded, we need to return now. return(true, remainderItem); } if (existingItemAtIndex == null) { remainderItem.ParentContainer = this; this.Content.Insert(0, remainderItem as IItem); this.InvokeContentAdded(remainderItem as IItem); remainderItem = null; } else { // Swap the items. this.Content.Clear(); remainderItem.ParentContainer = this; this.Content.Insert(0, remainderItem as IItem); this.InvokeContentUpdated(0, remainderItem as IItem); remainderItem = existingItemAtIndex; } return(true, remainderItem); }
/// <summary> /// Attempts to remove a specific thing from this container. /// </summary> /// <param name="thingFactory">A reference to the factory of things to use.</param> /// <param name="thing">The <see cref="IThing"/> to remove from the container.</param> /// <param name="index">Optional. The index from which to remove the <see cref="IThing"/>. Defaults to byte.MaxValue, which instructs to remove the <see cref="IThing"/> if found at any index.</param> /// <param name="amount">Optional. The amount of the <paramref name="thing"/> to remove.</param> /// <returns>A tuple with a value indicating whether the attempt was at least partially successful, and false otherwise. If the result was only partially successful, a remainder of the thing may be returned.</returns> public (bool result, IThing remainder) RemoveContent(IThingFactory thingFactory, ref IThing thing, byte index = byte.MaxValue, byte amount = 1) { thingFactory.ThrowIfNull(nameof(thingFactory)); if (!(thingFactory is IItemFactory itemFactory)) { throw new ArgumentException($"The {nameof(thingFactory)} must be derived of type {nameof(IItemFactory)}."); } if (amount == 0) { throw new ArgumentException($"Invalid {nameof(amount)} zero."); } IItem remainder = null; if (thing is ICreature creature) { return(this.InternalRemoveCreature(creature), null); } else if (thing is IItem item) { if (item.IsGround) { if (this.Ground != item) { return(false, item); } this.Ground = null; } else if (item.IsGroundFix) { if (amount > 1) { throw new ArgumentException($"Invalid {nameof(amount)} while removing a ground border item: {amount}."); } return(this.InternalRemoveGroundBorderItem(thing), null); } else if (item.IsLiquidPool) { if (this.LiquidPool != item) { return(false, item); } this.LiquidPool = null; } else if (item.StaysOnTop) { if (amount > 1) { throw new ArgumentException($"Invalid {nameof(amount)} while removing a stay-on-top item: {amount}."); } return(this.InternalRemoveStayOnTopItem(thing), null); } else if (item.StaysOnBottom) { if (amount > 1) { throw new ArgumentException($"Invalid {nameof(amount)} while removing a stay-on-bottom item: {amount}."); } return(this.InternalRemoveStayOnBottomItem(thing), null); } else { lock (this.tileLock) { if ((!item.IsCumulative && amount > 1) || (item.IsCumulative && item.Amount < amount)) { return(false, null); } if (!item.IsCumulative || item.Amount == amount) { // Since we have the exact amount, we can remove the item instance from the tile. this.itemsOnTile.Pop(); } else { // We're removing less than the entire amount, so we need to calculate the remainder to add back. var newExistingAmount = (byte)(item.Amount - amount); item.Amount = newExistingAmount; // item amount is left wrong. // Create a new item as the remainder. remainder = itemFactory.CreateItem(new ItemCreationArguments() { TypeId = item.Type.TypeId }); remainder.Amount = amount; thing = remainder; remainder = item; } } } } else { throw new InvalidCastException($"Thing did not cast to either a {nameof(ICreature)} or {nameof(IItem)}."); } // Update the tile's version so that it invalidates the cache. this.LastModified = DateTimeOffset.UtcNow; return(true, remainder); }
/// <summary> /// Attempts to add a <see cref="IThing"/> to this container. /// </summary> /// <param name="thingFactory">A reference to the factory of things to use.</param> /// <param name="thing">The <see cref="IThing"/> to add to the container.</param> /// <param name="index">Optional. The index at which to add the <see cref="IThing"/>. Defaults to byte.MaxValue, which instructs to add the <see cref="IThing"/> at any free index.</param> /// <returns>A tuple with a value indicating whether the attempt was at least partially successful, and false otherwise. If the result was only partially successful, a remainder of the thing may be returned.</returns> public (bool result, IThing remainder) AddContent(IThingFactory thingFactory, IThing thing, byte index = byte.MaxValue) { thingFactory.ThrowIfNull(nameof(thingFactory)); if (!(thingFactory is IItemFactory itemFactory)) { throw new ArgumentException($"The {nameof(thingFactory)} must be derived of type {nameof(IItemFactory)}."); } lock (this.tileLock) { if (thing is ICreature creature) { this.creaturesOnTile.Push(creature); } else if (thing is IItem item) { if (item.IsGround) { this.Ground = item; } else if (item.IsGroundFix) { this.groundBorders.Push(item); } else if (item.IsLiquidPool) { this.LiquidPool = item; } else if (item.StaysOnTop) { this.stayOnTopItems.Push(item); } else if (item.StaysOnBottom) { this.stayOnBottomItems.Push(item); } else { var remainingAmountToAdd = item.Amount; while (remainingAmountToAdd > 0) { if (!item.IsCumulative) { this.itemsOnTile.Push(item); break; } var existingItem = this.itemsOnTile.Count > 0 ? this.itemsOnTile.Peek() : null; // Check if there is an existing top item and if it is of the same type. if (existingItem == null || existingItem.Type != item.Type || existingItem.Amount >= ItemConstants.MaximumAmountOfCummulativeItems) { this.itemsOnTile.Push(item); break; } remainingAmountToAdd += existingItem.Amount; // Modify the existing item with the new amount, or the maximum permitted. var newExistingAmount = Math.Min(remainingAmountToAdd, ItemConstants.MaximumAmountOfCummulativeItems); existingItem.Amount = newExistingAmount; remainingAmountToAdd -= newExistingAmount; if (remainingAmountToAdd == 0) { break; } item = itemFactory.CreateItem(new ItemCreationArguments() { TypeId = item.Type.TypeId }); item.Amount = remainingAmountToAdd; item.ParentContainer = this; } } // Update the tile's version so that it invalidates the cache. // TOOD: if we start caching creatures, move to outer scope. this.LastModified = DateTimeOffset.UtcNow; } } if (thing != null && thing is IContainedThing containedThing) { containedThing.ParentContainer = this; } return(true, null); }
/// <summary> /// Attempts to add a <see cref="IThing"/> to this container. /// </summary> /// <param name="thingFactory">A reference to the factory of things to use.</param> /// <param name="thing">The <see cref="IThing"/> to add to the container.</param> /// <param name="index">Optional. The index at which to add the <see cref="IThing"/>. Defaults to byte.MaxValue, which instructs to add the <see cref="IThing"/> at any free index.</param> /// <returns>A tuple with a value indicating whether the attempt was at least partially successful, and false otherwise. If the result was only partially successful, a remainder of the thing may be returned.</returns> public virtual (bool result, IThing remainder) AddContent(IThingFactory thingFactory, IThing thing, byte index = byte.MaxValue) { thingFactory.ThrowIfNull(nameof(thingFactory)); thing.ThrowIfNull(nameof(thing)); if (!(thingFactory is IItemFactory itemFactory)) { throw new ArgumentException($"The {nameof(thingFactory)} must be derived of type {nameof(IItemFactory)}."); } if (!(thing is IItem item)) { // Containers like this can only add items. return(false, null); } // Validate that the item being added is not itself, or a parent of this item. if (thing == this || this.IsChildOf(item)) { // TODO: error message 'This is impossible'. return(false, thing); } // Find an index which falls in within the actual content boundaries. var targetIndex = index < this.Content.Count ? index : -1; var atCapacity = this.Capacity == this.Content.Count; // Then get an item if there is one, at that index. var existingItemAtIndex = targetIndex == -1 ? null : this.Content[targetIndex]; (bool success, IThing remainderToAdd) = (false, item); if (existingItemAtIndex != null) { // We matched with an item, let's attempt to add or join with it first. if (existingItemAtIndex.IsContainer && existingItemAtIndex is IContainerItem existingContainer) { (success, remainderToAdd) = existingContainer.AddContent(itemFactory, remainderToAdd); } else { (success, remainderToAdd) = existingItemAtIndex.Merge(remainderToAdd as IItem); if (success) { // Regardless if we're done, we've changed an item at this index, so we notify observers. if (remainderToAdd != null && !atCapacity) { targetIndex++; } this.InvokeContentUpdated((byte)targetIndex, existingItemAtIndex); } } } if (remainderToAdd == null) { // If there's nothing still waiting to be added, we're done. return(true, null); } // Now we need to add whatever is remaining to this container. if (atCapacity) { // This is full. return(success, remainderToAdd); } remainderToAdd.ParentContainer = this; this.Content.Insert(0, remainderToAdd as IItem); this.InvokeContentAdded(remainderToAdd as IItem); return(true, null); }