# Creating New Item Class

{% hint style="warning" %}
All Item classes must be placed under namespace **Plugin.Items**
{% endhint %}

### Class Functions

* Init() - <mark style="color:green;">\[OPTIONAL]</mark> class initialization(called when item spawned, both on Player and ItemPickup).
* Update() - <mark style="color:green;">\[OPTIONAL]</mark> called every frame on clients.
* ServerUpdate() - <mark style="color:green;">\[OPTIONAL]</mark> called every frame on server.
* OnPickup() - <mark style="color:green;">\[OPTIONAL]</mark> called when item pickuped(on Player).
* OnDrop() - <mark style="color:green;">\[OPTIONAL]</mark> called when item dropped(on Player).
* OnUse() - <mark style="color:green;">\[OPTIONAL]</mark> called when Player use this item.
* OnHolster() - <mark style="color:green;">\[OPTIONAL]</mark> called when Player holster this item.
* OnDestroy() - <mark style="color:green;">\[OPTIONAL]</mark> called on class destroy.
* GetName() - <mark style="color:yellow;">\[REQUIRED]</mark> return displayed item name, return string \[DEFAULT: "item"].
* GetImage() - <mark style="color:yellow;">\[REQUIRED]</mark> return image ID that displayed in inventory, return string \[DEFAULT: "item"].
* OnRefine(int type) - <mark style="color:green;">\[OPTIONAL]</mark> return item ID(empty to destroy item) when item used in SCP-914(type: 0 - rough, 1 - coarse, 2 - 1:1, 3 - fine, 4 - very fine), return string \[DEFAULT: ""].
* GetKeyData() - <mark style="color:green;">\[OPTIONAL]</mark> return information about key card, return KeyData class \[DEFAULT: null].

### Local Properties

* player - return current Player class, if player contains it in inventory.&#x20;
* itemPickup- return current ItemPickup class, if item dropped.

### Local Functions

* SendToEveryone(string FunctionName, params object\[] arguments) - send command to every player to call function with arguments.
* SendToClient(string FunctionName, NetworkConnection connection, params object\[] arguments) - send command to player with connection to call function with arguments.
* SendToServer(string FunctionName, params object\[] arguments) - send command to server to call function with arguments.
* Invoke(Function, float seconds) - same logic as UnityEngine.Object.Invoke, call function after time.

### Example

```csharp
using System.Collections.Generic;
using UnityEngine;

namespace Plugin.Items
{
    public class NewCard : Akequ.Base.Item
    {
        private GameObject model;

        private KeyData keyData = new KeyData()
        {
            containment = 1
        };

        public override void Init()
        {
            model = ResourcesManager.SpawnObject("item_w_key");
            if (player == null)
            {
                model.transform.parent = itemPickup.transform;
                model.transform.localPosition = Vector3.zero;
                model.transform.localRotation = Quaternion.identity;
            }
            else
            {
                model.transform.parent = player.GetBoneTransform("mixamorig:RightHand");
                model.transform.localPosition = new Vector3(-0.002f, 0.165f, 0.032f);
                model.transform.localRotation = Quaternion.Euler(182.021f, -272.248f, -287.107f);
                model.transform.localScale = new Vector3(0.05174018f, 0.06509144f, -0.04974974f);
            }

            model.layer = 6;
            model.GetComponent<MeshRenderer>().sharedMaterial = ResourcesManager.GetObject("mat_key_janitor") as Material;
        }

        public override void OnDrop()
        {
            if (model != null)
            {
                GameObject.Destroy(model);
            }
        }

        public override void OnPickup()
        {
            if (model != null)
            {
                GameObject.Destroy(model);
            }

            if (player.isLocalPlayer)
            {
                model = ResourcesManager.SpawnObject("item_v_key");
                model.transform.parent = player.transform.Find("Recoil/MainCamera");
                model.transform.localPosition = Vector3.zero;
                model.transform.localRotation = Quaternion.identity;
                model.transform.localScale = new Vector3(-0.05f, 0.05f, 0.05f);
                model.GetComponentInChildren<SkinnedMeshRenderer>().sharedMaterial = (Material)ResourcesManager
                    .GetObject(
                        player.playerClass.GetHand());
            }
            else
            {
                model = ResourcesManager.SpawnObject("item_w_key");
                model.transform.parent = player.GetBoneTransform("mixamorig:RightHand");
                model.transform.localPosition = new Vector3(-0.002f, 0.165f, 0.032f);
                model.transform.localRotation = Quaternion.Euler(182.021f, -272.248f, -287.107f);
                model.transform.localScale = new Vector3(0.05174018f, 0.06509144f, -0.04974974f);
            }
            model.GetComponentInChildren<MeshRenderer>().sharedMaterial = ResourcesManager.GetObject("mat_key_janitor") as Material;
            model.SetActive(false);
        }

        public override void OnUse()
        {
            model.SetActive(true);
            player.SetHandAnim(4);
            if (player.isLocalPlayer)
            {
                UIManager.SetMobileButtons(new List<string>(){ "Move", "Rotate", "Pause", "PlayerList", "Interact", "Jump", "Run",
                    "Inventory", "Voice" });
            }
        }
        
        public override void OnHolster()
        {
            model.SetActive(false);
            player.SetHandAnim(0);
            if (player.isLocalPlayer)
            {
                UIManager.SetMobileButtons(new List<string>(){ "Move", "Rotate", "Pause", "PlayerList", "Interact", "Jump", "Run",
                    "Inventory", "Voice" });
            }
        }

        public override string GetName()
        {
            return "NewCard";
        }
        
        public override string GetImage()
        {
            return "inv_key_janitor";
        }
        
        public override KeyData GetKeyData()
        {
            return keyData;
        }

        public override string OnRefine(int mode)
        {
            int rand = Random.Range(0, 100);
            if (mode == 2 && rand < 25)
                return "RecruitCard";
            else if (mode == 2 && rand < 50)
                return "AssistantCard";
            else if (mode == 2 && rand < 75)
                return "JanitorCard";
            else if (mode == 2 && rand <= 100)
                return "FoundationAgentCard";
            else if (mode == 3)
                return "EngineerCard";
            else if (mode == 4 && rand < 75)
                return "ContainmentSpecialistCard";
            return "";
        }
    }
}
```

Example Solution can be downloaded here:\
[Link to archive](https://drive.google.com/file/d/1iT4OPJpX_YNxtVkDZWyRiip8tEZHM128/view?usp=sharing)

### Testing

Now we can compile this plugin and move library to server plugins folder according to [Folder Structure](/scp-classified-site-plugin-api/docs/folder-structure.md)\
\
Now we can spawn our item:

<figure><img src="/files/TcSlEpY2CD5k60n5zsTi" alt=""><figcaption></figcaption></figure>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://akequ.gitbook.io/scp-classified-site-plugin-api/docs/creating-new-item-class.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
