OnCollectiblePickup // Preventing item from spawning

@Wulf

What is the appropriate way to disable or remove items from spawning when using OnCollectiblePickup(CollectibleEntity collectible, BasePlayer player)?

item.amount = 0; //works, but throws a warning in console:

Creating item with less than 1 amount! (Cloth)
Creating item with less than 1 amount! (Hemp Seed)

and I've read elsewhere that it is not the preferred method. I had tried converting the ItemAmount object to an Item object, so that I could use the item.Remove() function, but type errors prevented that route as well as it cannot convert between the two types. I looked at the assemblies for ItemDefinition and ItemAmount and didn't see anything in there that led me to believe it would remove the item / prevent collection / disable it. I've disassembled a few different plugins hoping to find clues as to how to accomplish this, but haven't found anything that was obvious.

It occured to me that I could check player inventory for a static item identifier after the item had already been given to the player, but that seems more resource intensive than necessary, and would still show the user that they recieved x of an item and then it was removed. 

Is there a cleaner way to perform this than I have written below?

        private void OnCollectiblePickup(CollectibleEntity collectible, BasePlayer player)
        {
            foreach (ItemAmount item in collectible.itemList)
            {
                var name = item.itemDef.name;
                Puts(name);

                if (name == "metal_ore.item")
                {
                    _metal(player);
                    _silver(player);
                }

                if (name == "cloth.item")
                {
                    item.amount = 0;
                }

                if (name == "hemp_seed.item")
                {
                    item.amount = 0;
                    _hemp(player);
                }
            }
        } 

try item.Remove();

or maybe

foreach (ItemAmount item in collectible.itemList.ToList())

collectible.itemList.Remove(item);

XfCLnLTBk2bE8vt.png Razor

try item.Remove();

or maybe

foreach (ItemAmount item in collectible.itemList.ToList())

collectible.itemList.Remove(item);

I attempted your suggestion, which resulted in the following:

error CS1061: Type `ItemAmount[]' does not contain a definition for `Remove' and no extension method `Remove' of type `ItemAmount[]' could be found. Are you missing `System.Collections.Generic' using directive?

After adding the directive referenced in the error message:

Error while compiling: GatherManagerOverwrite.cs(259,42): error CS1501: No overload for method `Remove' takes `2' arguments
There is no argument given that corresponds to the required formal parameter 'value' of 'CollectionExtensions.Remove<TKey, TValue>(IDictionary<TKey, TValue>, TKey, out TValue)'

As expressed in my post earlier, I did attempt to first convert the ItemAmount object to an Item object, so as to use item.Remove(); (this method does not exist within ItemAmount)

Any other ideas? Thanks for the feedback, either way!

I have looked at ItemAmount objects in the assemblies, and I see nothing that would indicate disabling or removing an item from the generated items:

https://gyazo.com/3dcd67c2cbcd174afe13f9dd91a33cc5

https://gyazo.com/7e080022eb77f8e9383e5710ebf583fc

I have looked at the source for many plugins that used this hook, but most of them have not been updated since it was changed to use CollectibleEntity instead of Item. Of those plugins, I have not seen any purpose built for disabling items obtained by picking them up off the ground. As I said, setting item.amount to zero does work, but throws console warnings.

private void OnCollectiblePickup(CollectibleEntity collectible, BasePlayer player)
		{

			for (int index = 0; index < collectible.itemList.Length; ++index)
			{
				if (collectible.itemList[index].itemDef.name == "metal_ore.item")
                {
					_metal(player);
					_silver(player);
				}
				else if (collectible.itemList[index].itemDef.name == "cloth.item")
				{
					NextTick(() => {
						Item item = player.inventory.FindItemID(collectible.itemList[index].itemDef.itemid);
						if (item.amount >= collectible.itemList[index].amount)
						{
							item.UseItem((int)collectible.itemList[index].amount);
						}
					});
				}
				else if (collectible.itemList[index].itemDef.name == "hemp_seed.item")
				{
					NextTick(() => {
						Item item = player.inventory.FindItemID(collectible.itemList[index].itemDef.itemid);
						if (item.amount >= collectible.itemList[index].amount)
						{
							item.UseItem((int)collectible.itemList[index].amount);
						}
					});
					_hemp(player);
				}

			}
		}
CqwdegQAd0ZMNPq.png Razor
private void OnCollectiblePickup(CollectibleEntity collectible, BasePlayer player)
		{

			for (int index = 0; index < collectible.itemList.Length; ++index)
			{
				if (collectible.itemList[index].itemDef.name == "metal_ore.item")
                {
					_metal(player);
					_silver(player);
				}
				else if (collectible.itemList[index].itemDef.name == "cloth.item")
				{
					NextTick(() => {
						Item item = player.inventory.FindItemID(collectible.itemList[index].itemDef.itemid);
						if (item.amount >= collectible.itemList[index].amount)
						{
							item.UseItem((int)collectible.itemList[index].amount);
						}
					});
				}
				else if (collectible.itemList[index].itemDef.name == "hemp_seed.item")
				{
					NextTick(() => {
						Item item = player.inventory.FindItemID(collectible.itemList[index].itemDef.itemid);
						if (item.amount >= collectible.itemList[index].amount)
						{
							item.UseItem((int)collectible.itemList[index].amount);
						}
					});
					_hemp(player);
				}

			}
		}

As predicted, this does show that the player recieved the item, but also removes the item as desired and does not spam the console with error messages. I've adapted your approach, and for now it will work for my purposes. Thank you so much for the assist!

oxidation

As predicted, this does show that the player recieved the item, but also removes the item as desired and does not spam the console with error messages. I've adapted your approach, and for now it will work for my purposes. Thank you so much for the assist!


Try this
object OnCollectiblePickup(CollectibleEntity collectible, BasePlayer reciever)
        {
            foreach (ItemAmount itemAmount in collectible.itemList)
            {
                if (itemAmount.itemDef.name == "metal_ore.item")
                {
                    _metal(reciever);
                    _silver(reciever);
                }
                else if (itemAmount.itemDef.name == "cloth.item")
                {
                    continue;
                }
                else if (itemAmount.itemDef.name == "hemp_seed.item")
                {
                    _hemp(reciever);
                    continue;
                }
                Item obj = ItemManager.Create(itemAmount.itemDef, (int)itemAmount.amount);
                if (obj != null)
                {
                    if ((bool)(UnityEngine.Object)reciever)
                        reciever.GiveItem(obj, BaseEntity.GiveItemReason.ResourceHarvested);
                    else
                        obj.Drop(collectible.transform.position + Vector3.up * 0.5f, Vector3.up);
                }
            }
            collectible.itemList = (ItemAmount[])null;
            if (collectible.pickupEffect.isValid)
                Effect.server.Run(collectible.pickupEffect.resourcePath, collectible.transform.position, collectible.transform.up);
            RandomItemDispenser randomItemDispenser = PrefabAttribute.server.Find<RandomItemDispenser>(collectible.prefabID);
            if ((PrefabAttribute)randomItemDispenser != (PrefabAttribute)null)
                randomItemDispenser.DistributeItems(reciever, collectible.transform.position);
            collectible.Kill();
            return true;
        }​