{"id":14960628,"url":"https://github.com/darkrewar/basetool","last_synced_at":"2025-05-02T12:31:07.603Z","repository":{"id":42482028,"uuid":"332817475","full_name":"DarkRewar/BaseTool","owner":"DarkRewar","description":"A big library of basic tools that you might need in your Unity projects.","archived":false,"fork":false,"pushed_at":"2025-04-09T18:49:43.000Z","size":717,"stargazers_count":47,"open_issues_count":24,"forks_count":6,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-09T19:43:27.176Z","etag":null,"topics":["csharp","game-development","gamedev","tool","unity","unity-editor","unity-plugin","unity3d","unity3d-plugin"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DarkRewar.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"DarkRewar","patreon":null,"open_collective":null,"ko_fi":"rewar","tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":null,"custom":null}},"created_at":"2021-01-25T16:53:49.000Z","updated_at":"2025-04-06T16:33:22.000Z","dependencies_parsed_at":"2024-03-04T17:47:34.626Z","dependency_job_id":"9ff94abb-6b5e-44ce-a3b7-93236253ec1d","html_url":"https://github.com/DarkRewar/BaseTool","commit_stats":{"total_commits":60,"total_committers":4,"mean_commits":15.0,"dds":"0.15000000000000002","last_synced_commit":"ccafad0eac1279a6e0f99e7bb3350510e29a1bc7"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DarkRewar%2FBaseTool","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DarkRewar%2FBaseTool/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DarkRewar%2FBaseTool/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DarkRewar%2FBaseTool/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DarkRewar","download_url":"https://codeload.github.com/DarkRewar/BaseTool/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252038114,"owners_count":21684626,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp","game-development","gamedev","tool","unity","unity-editor","unity-plugin","unity3d","unity3d-plugin"],"created_at":"2024-09-24T13:22:38.310Z","updated_at":"2025-05-02T12:31:06.367Z","avatar_url":"https://github.com/DarkRewar.png","language":"C#","readme":"![BaseTool_logo_full_baseline](https://github.com/DarkRewar/BaseTool/assets/7771426/ab5fdd5a-cddf-4418-9973-820091c797f0)\n\n\u003ca href=\"https://github.com/DarkRewar/BaseTool\"\u003e\u003cimg src=\"https://img.shields.io/github/package-json/v/darkrewar/basetool\" /\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/DarkRewar/BaseTool/tree/develop\"\u003e\u003cimg src=\"https://img.shields.io/github/package-json/v/darkrewar/basetool/develop\" /\u003e\u003c/a\u003e\n\u003ca href=\"unityhub://2021.3.37f1/3b6005ad5ad6\"\u003e\u003cimg src=\"https://img.shields.io/badge/Unity-2021%20LTS-blue\" /\u003e\u003c/a\u003e\n![commit activity](https://img.shields.io/github/commit-activity/m/darkrewar/basetool)\n![last commit](https://img.shields.io/github/last-commit/darkrewar/basetool)\n\u003ca href=\"https://twitter.com/intent/follow?screen_name=darkrewar\"\u003e\u003cimg src=\"https://img.shields.io/twitter/follow/darkrewar\" /\u003e\u003c/a\u003e\n\n# Description\n\nBaseTool contains many features that improve your daily game development.\nEvery feature is grouped by modules, and you can enable features you want to use.\n\nIt could be used for any kind of project, at any time, by *pretty* anyone. It contains those key features:\n\n- a Todo List window to check you project state ;\n- a singleton pattern to put on your MonoBehaviour ;\n- the cooldown class to avoid wasting time reimplement it everywhere ;\n- dictionaries that can be serialized in the inspector ;\n- game event flow using ScriptableObject ;\n- GetComponent attributes to retrieve components when you want ;\n- movement and shooter features ;\n- many editor attributes ;\n- many class extensions (for Vector3, arrays, camera...) ;\n- and many small but great features...\n\n# Installation\n\nThis tool is made for the Unity package manager and is available for Unity 2021 LTS and further.\n\nHow to install:\n\n- Go to `Window \u003e Package Manager` ;\n- Click the plus button-dropdown on the top-left of the window ;\n- Select `Add package from git URL` ;\n- Paste this URL : `https://github.com/DarkRewar/BaseTool.git`\n- Or if you want to test the preview : `https://github.com/DarkRewar/BaseTool.git#develop`\n\n# Documentation\n\n1. [Core](#core)\n    - [Setup Wizard](#setup-wizard)\n    - [Dev Console](#dev-console)\n    - [Injector](#injector)\n    - [Cooldown](#cooldown)\n    - [MonoSingleton](#monosingleton)\n    - [ValueListener](#valuelistener)\n    - [SerializableDictionary](#serializabledictionary)\n    - [GameEvent](#game-events)\n    - [Class Extensions](#class-extensions)\n    - [Math Utils](#math-utils)\n    - [TickManager](#tickmanager)\n    - [Tree](#tree)\n    - [Interfaces](#core-interfaces)\n2. [Movement](#movement)\n    - [Components](#movement-components)\n    - [Interfaces](#movement-interfaces)\n3. [Shooter](#shooter)\n    - [Sample](#shooter-sample)\n    - [Components](#shooter-components)\n    - [Interfaces](#shooter-interfaces)\n    - [Weapon](#weapon)\n4. [RPG](#rpg) [WIP]\n5. [RNG](#rng)\n    - [PonderateRandom](#ponderaterandom)\n    - [Deck](#deck)\n    - [Sample](#random-sample)\n6. [UI](#ui)\n    - [Workflow](#ui-workflow)\n    - [View](#view)\n    - [Navigation](#navigation)\n    - [Sample](#ui-sample)\n7. [Editor](#editor)\n    - [Todo List](#todo-list)\n    - [MinMaxAttribute](#minmaxattribute)\n    - [IfAttribute](#ifattribute)\n    - [IfNotAttribute](#ifnotattribute)\n    - [EnableIfAttribute](#enableifattribute)\n    - [DisableIfAttribute](#disableifattribute)\n    - [ReadOnlyAttribute](#readonlyattribute)\n    - [SuffixAttribute](#suffixattribute)\n    - [PrefixAttribute](#prefixattribute)\n    - [MessageAttribute](#messageattribute)\n    - [ButtonAttribute](#buttonattribute)\n\n## Core\n\n### Setup Wizard\n\nBy default, BaseTool include every module in the project. Each module is an Assembly which can be enabled or disabled\nusing the setup wizard.\n\nTo open the setup wizard, go to the topbar and open `Window \u003e BaseTool \u003e Setup`.\n\n`Core` is the main module which is mandatory to let BaseTool work. Other modules are all optional. If you only want\nessential features, untick every module.\n\n![setup_wizard](./Documentation~/Wizard/setup_wizard.png)\n\n### Dev Console\n\nYou can add/remove you own command to the `Console` by using :\n\n```csharp\nBaseTool.Console.AddCommand(\"\u003ccommand\u003e\", \"\u003cdescription\u003e\", MethodCallback);\n\nBaseTool.Console.RemoveCommand(\"\u003ccommand\u003e\");\n```\n\nHere is an implementation inside a `MonoBehaviour`:\n\n```csharp\nusing BaseTool;\n\npublic class AddCustomCommand : MonoBehaviour\n{\n    public void OnEnable()\n    {\n        Console.AddCommand(\"\u003cmy-command\u003e\", \"\u003cdescription\u003e\", Callback);\n    }\n    \n    public void OnDisable()\n    {\n        Console.RemoveCommand(\"\u003cmy-command\u003e\");\n    }\n\n    private void Callback(ConsoleArguments args)\n    {\n        Console.Write($\"Callback command with {args}\");\n    }\n}\n```\n\nThe command callback passes a `ConsoleArguments` as parameter.\nThis is a handler to parse arguments from the command.\n\nFor example, the command `mycommand test 99 -h -number 123` will\nparse arguments like :\n\n```csharp\nargs[0]; // test\nargs[1]; // 99\nargs[\"h\"]; // null\nargs[\"number\"]; // 123\n\n// You can check if an argument exists\nargs.Exists(\"h\"); // true\n```\n\nSince 0.4.0, dev console requires a `ConsoleSettings` file to\nwork. This asset contains definitions to change the toggle key\ncode, the timescale when opened and its inclusion in build.\n\nCurrently, this file **must** be in the `Resources` folder and\nbe named `ConsoleSettings`.\n\n![image](./Documentation~/Core/Console/console_settings.png)\n\nBy default, to toggle the dev console, press F4 key.\n\n![image](https://github.com/DarkRewar/BaseTool/assets/7771426/98bfceaa-62d0-45e9-8cc4-f087e2f19a5c)\n\n### Injector\n\nYou can \"automatically\" retrieve your components by using the `Injector.Process()` method.\n\nTo get your `Awake()`, `OnEnable()`, `Start()` or anything else clean, you can add attributes upon fields and properties\nyou want to retrieve. You can use one of those five attributes following their exact method:\n\n- `GetComponent`\n- `GetComponents`\n- `GetComponentInChildren`\n- `GetComponentsInChildren`\n- `GetComponentInParent`\n\n```csharp\nusing BaseTool;\nusing UnityEngine;\n\n[RequireComponent(typeof(Rigidbody))]\npublic class MyComponent : MonoBehaviour\n{\n    [GetComponent, SerializeField]\n    private Rigidbody _rigidbody;\n\n    [GetComponent]\n    public Rigidbody Rigidbody { get; private set; }\n\n    [GetComponentInChildren]\n    public Collider ChildCollider;\n\n    [GetComponentsInChildren]\n    public Collider[] ChildrenColliders;\n\n    [GetComponentInParent]\n    public Transform ParentTransform;\n\n    void Awake() =\u003e Injector.Process(this);\n}\n```\n\n### Cooldown\n\n`Cooldown` is a class that can be used to delay a call, action or whatever you want to do. You can directly check the\n`Cooldown.IsReady` boolean or subscribe to the `Cooldown.OnReady` event.\n\nEvery `Cooldown` is updated by an internal `CooldownManager`, you don't have to call the `Cooldown.Update()` method\nyourself.\nIf you want to manage the cooldown, you can set the `Cooldown.SubscribeToManager` to false.\n\nYou can pause and resume the cooldown by using `Cooldown.Pause()` and `Cooldown.Resume()` methods.\nIf you want to totally stop the cooldown (and remove it from the `CooldownManager`)\nyou can use the `Cooldown.Stop()` method.\n\n```csharp\nusing BaseTool;\nusing UnityEngine;\n\npublic class MyComponent : MonoBehaviour\n{\n    [SerializeField]\n    private Cooldown _cooldown = 2;\n\n    void Start()\n    {\n        // Event method\n        _cooldown.OnReady += OnCooldownIsReady;\n    }\n\n    void Update()\n    {\n        // Check if the cooldown is ready and reset it\n        if(_cooldown.Restart())\n        {\n            // Do something when cooldown is ready\n        }\n\n        // OR\n\n        // Check if the cooldown is ready...\n        if (_cooldown.IsReady)\n        {\n            _cooldown.Reset(); // ...and reset it\n            // Do something when cooldown is ready\n        }\n\n        if(Input.GetKeyDown(KeyCode.P))\n            _cooldown.Pause();\n        else if(Input.GetKeyDown(KeyCode.R))\n            _cooldown.Resume();\n        else if(Input.GetKeyDown(KeyCode.S))\n            _cooldown.Stop();\n    }\n\n    private void OnCooldownIsReady()\n    {\n        // Do something when cooldown is ready\n    }\n}\n```\n\n### MonoSingleton\n\nYou can create a singleton `MonoBehaviour` directly by inheriting from the `MonoSingleton`.\n\n```csharp\nusing BaseTool;\n\npublic class MyUniquePlayer : MonoSingleton\u003cMyUniquePlayer\u003e\n{\n    public int Life = 1;\n}\n\npublic class GameManager : MonoBehaviour\n{\n    public void UpdatePlayerLife(int damages)\n    {\n        MyUniquePlayer.Instance.Life -= damages;\n    }\n}\n```\n\n### ValueListener\n\nIf you want to use an Observer Pattern for a value, and you don't want\nto implement the entire change event handler, the `ValueListener\u003cT\u003e` lets\nyou do that for you.\n\nYou need to declare a `ValueListener\u003cT\u003e` of your type as a field or a property.\nI recommend to declare it as readonly to avoid losing the `OnChanged` event references.\n\nValue is implicitly cast to or from the value type you want. That means you can initialize\nyour object using the value directly (see following example).\n\n```csharp\nusing BaseTool;\nusing UnityEngine;\nusing UnityEngine.UI;\n\npublic class MyComponent : MonoBehaviour\n{\n    public readonly ValueListener\u003cint\u003e Lifepoints = 100;\n    public readonly ValueListener\u003cstring\u003e Nickname = new();\n\n    public Text NameLabel;\n    public Text LifeLabel;\n\n    public void Start()\n    {\n        Lifepoints.OnChanged += (oldLife, newLife) =\u003e \n            LifeLabel.text = $\"{oldLife} -\u003e {newLife}/100\";\n        Nickname.OnChanged += (_, newName) =\u003e \n            NameLabel.text = newName;\n\n        Nickname.Value = \"MyName\";\n        string name = Nickname;\n        Debug.Log(name);\n    }\n} \n```\n\n### SerializableDictionary\n\nYou can get dictionaries in inspector by using the `SerializableDictionary` class. It will serialize the dictionary\nbut also draw it like an extended list.\n\n```csharp\nusing BaseTool;\nusing UnityEngine;\n\npublic class MyComponent : MonoBehaviour\n{\n    public SerializableDictionary\u003cstring, GameObject\u003e ObjectPool;\n}\n```\n\nThe code above will display this dictionary in the inspector.\nIt also tells you when two keys already exists in the dictionary.\n\n![serializable_dictionary_drawer](./Documentation~/Editor/serializable_dictionary_drawer.png)\n\nYou can cast `Dictionary` to `SerializableDictionary` using\n`.ToSerializableDictionary()` method and you also can cast `SerializableDictionary` to `Dictionary` using implicit cast.\n\n```csharp\nusing BaseTool;\nusing System.Collections.Generic;\nusing UnityEngine;\n\npublic class Test : MonoBehaviour\n{\n    public SerializableDictionary\u003cint, string\u003e SerializedDictionary;\n\n    public Dictionary\u003cint, string\u003e Dictionary;\n    \n    void Start()\n    {\n        // Dictionary -\u003e SerializableDictionary\n        SerializedDictionary = Dictionary.ToSerializableDictionary();\n        //or\n        SerializedDictionary = new(Dictionary);\n\n        // SerializableDictionary -\u003e Dictionary\n        Dictionary = SerializedDictionary;\n    }\n}\n```\n\n### Game Events\n\nThis feature allows you to create custom events using ScriptableObjects.\n\nIt is based upon three elements:\n\n- `GameEvent` which is the ScriptableObject that handle the event channel ;\n- `GameEventTrigger` which triggers the event on the channel ;\n- `GameEventReceiver` which processes actions when the event is triggered in the channel.\n\nWhat is the purpose of this architecture? Well, it allows you to trigger multiple actions from only one trigger.\nFor example: the player enters a zone of battle, it will close the door, spawn enemies and play the battle music.\n\nAlso, this is really useful for multi-scene game events. It is impossible to reference a gameobject from a scene to\nanother.\nThat's why subscribing to a SO GameEvent speed up development and let you interoperate events between runtime loaded\nscenes.\nFor example: you have two loaded scenes in your level, the player passes a point that enables platforms in another\nscene.\n\nYou can totally inherit from those classes if you want to make custom game event, more specific or with alternate\ntriggers.\n\n#### `GameEvent`\n\nIn the Project window, right click in the folder you want to place the game event\nand then follow `Create \u003e BaseTool \u003e Events \u003e Game Event`.\n\n#### `GameEventTrigger`\n\nThis is the component you should use to trigger game events.\nIt is recommended to use a `Collider` with this component because\nit depends on `OnTriggerEnter()` and/or `OnCollisionEnter()` Unity calls to work properly.\n\n| Property       | Type                   | Description                                                       |\n|----------------|------------------------|-------------------------------------------------------------------|\n| Trigger Once   | `bool`                 | If checked, this component will trigger the event only once.      |\n| Trigger Type   | `GameEventTriggerType` | How the game event will be processed: Trigger, Collision or both. |\n| Trigger Tags   | `List\u003cstring\u003e`         | List of authorized tags that will trigger the event.              |\n| Game Event     | `GameEvent`            | The game event SO to trigger (optional).                          |\n| Generic Events | `UnityEvent`           | Additional callbacks that you can use (optional).                 |\n\n![game_event_trigger.png](./Documentation~/Core/Events/game_event_trigger.png)\n\n#### `GameEventReceiver`\n\nThis is the component you should use to process callbacks from a game event.\nYou can add it on any elements you want, as long as the objects is active\n(to allow event subscription in the `OnEnable()` method).\n\n| Property    | Type         | Description                                       |\n|-------------|--------------|---------------------------------------------------|\n| Game Event  | `GameEvent`  | The game event SO to listen to.                   |\n| OnTriggered | `UnityEvent` | Additional callbacks that you can use (optional). |\n\n![game_event_receiver.png](./Documentation~/Core/Events/game_event_receiver.png)\n\n### Class Extensions\n\nThis package contains many class extensions for mainly Unity primary classes. Here are the current extensions:\n\n- [Array Extensions](./Documentation~/Extensions.md#array-extensions)\n- [Camera Extensions](./Documentation~/Extensions.md#camera-extensions)\n- [Color Extensions](./Documentation~/Extensions.md#color-extensions)\n- [List Extensions](./Documentation~/Extensions.md#list-extensions)\n- [Number Extensions](./Documentation~/Extensions.md#number-extensions)\n- [Random Extensions](./Documentation~/Extensions.md#random-extensions)\n- [Range Extensions](./Documentation~/Extensions.md#range-extensions)\n- [String Extensions](./Documentation~/Extensions.md#string-extensions)\n- [Transform Extensions](./Documentation~/Extensions.md#transform-extensions)\n- [Vector Extensions](./Documentation~/Extensions.md#vector-extensions)\n\nGo to the full documentation : [Class Extensions](./Documentation~/Extensions.md)\n\n### Math Utils\n\nMethods available from the `MathUtils` static class:\n\n#### `Modulo(int index, int count)`\n\nBecause `%` is broken on C# when you want to get a negative modulo (e.g. you want the index -1 of an array), this method\nis a replacement of the symbol.\n\n```csharp\nusing BaseTool; \n\nMathUtils.Modulo(1, 5); // = 1\nMathUtils.Modulo(6, 5); // = 1\nMathUtils.Modulo(-1, 5); // = 4\nMathUtils.Modulo(-3, 5); // = 2\n```\n\n#### `Approximately(float a, float b, float tolerance = 0.001f)`\n\nThe [`UnityEngine.Mathf.Approximately`](https://docs.unity3d.com/ScriptReference/Mathf.Approximately.html)\nmethod is useful but not enough tolerant if you want to check values that are too different.\n\nFor example: if you want to make a deadzone on your Vector3 magnitude when it goes lower than 0.01f,\nthe `Mathf.Approximately(vector.magnitude, 0)` could return false if your magnitude is too high.\n\n```csharp\nusing BaseTool; \n\nMathUtils.Approximately(0.1f, 0.001f); // true\nMathUtils.Approximately(1, 0.001f); // false\n\nMathUtils.Approximately(1.1f, 1.2f, 0.2f); // true\nMathUtils.Approximately(1.1f, 1.2f, 0.05f); // false\n```\n\n#### `IsPointInsidePolygon(Vector2 point, Vector2[] polygon)`\n\nCheck if a point is inside a polygon (determined by a list of `Vector2`).\nAlso exists for `Vector2Int` by using\n`IsPointInsidePolygon(Vector2Int point, Vector2Int[] polygon)`.\n\n```csharp\nusing BaseTool;\n\nList\u003cVector2\u003e square = new()\n{\n   new(0, 0),\n   new(0, 1),\n   new(1, 1),\n   new(1, 0)\n};\n\nMathUtils.IsPointInsidePolygon(new Vector2(0.5f, 0.5f), points)); // true\nMathUtils.IsPointInsidePolygon(new Vector2(-1, -1), points)); // false\n```\n\n*Note: currently, there are no `Vector3` equivalent.*\n\n### TickManager\n\nThe `TickManager` component allows you to create a system that sends a tick every *x* seconds.\nYou can define the delay between two ticks by modifying the `Tick Duration` field.\nYou can also make the `TickManager` a singleton by checking `Make Singleton`\n(it will convert it to a singleton at Awake, don't do that at runtime!).\n\nTo add the component, you can go to `Add Component \u003e BaseTool \u003e Core \u003e Tick Manager`.\nYou can have more than one `TickManager` on a singleton GameObject, but it is highly recommended\nto use only one `TickManager` (as singleton) or seperate them between multiple GameObjects.\n\n![tick_manager_component](./Documentation~/Core/TickManager/tick_manager_component.PNG)\n\nYou can subscribe to the tick event from the inspector (using `UnityEvent`)\nor the `OnTick` event action.\n\n```csharp\nusing BaseTool;\nusing UnityEngine;\n\npublic class TickerTest : MonoBehaviour\n{\n    [SerializeField] private TickManager _tickManager;\n\n    void Start()\n    {\n        _tickManager.OnTick += OnTick;\n    }\n\n    private void OnTick() =\u003e Debug.Log(\"OnTick()\");\n}\n```\n\nIf you want to add more custom tick, you can create a struct that implements the `ICustomTick`\ninterface, and create you own tick logic. The interface implements the `ShouldTick(ulong tick)`\nmethod where `tick` is the current number of ticks elapsed since the beginning of the game.\n\nThe following example shows how to create a custom tick that process every two ticks only:\n\n```csharp\nusing BaseTool;\nusing UnityEngine;\n\npublic struct EveryTwoTicks : ICustomTick\n{\n    public bool ShouldTick(ulong tick) =\u003e tick % 2 == 0;\n}\n\npublic class TickerTest : MonoBehaviour\n{\n    [SerializeField] private TickManager _tickManager;\n\n    private void OnEnable()\n    {\n        _tickManager.RegisterCustomTick\u003cEveryTwoTicks\u003e(OnEveryTwoTicks);\n    }\n\n    private void OnDisable()\n    {\n        _tickManager.UnregisterCustomTick\u003cEveryTwoTicks\u003e(OnEveryTwoTicks);\n    }\n\n    private void EveryTwoTicks() =\u003e Debug.Log(\"EveryTwoTicks()\");\n}\n```\n\n### Tree\n\nA generic tree system following a parent/child link. Here is a following example based on a GameObject hierarchy (but\nwould work for a file, UI or node hierarchy too).\n\n```csharp\nusing BaseTool;\nusing UnityEngine;\n\n// Create a tree from a GameObject\nTree\u003cGameObject\u003e cameraTree = new(GameObject.Find(\"Camera\"));\n// Add a child to the camera tree\ncameraTree.AddChild(GameObject.Find(\"WeaponRender\"));\n\n// Create a tree from a GameObject\nTree\u003cGameObject\u003e tree = new(GameObject.Find(\"Root\"));\n// Add a child from a GameObject\ntree.AddChild(GameObject.Find(\"PlayerRender\"));\n// Add a tree to anothe tree\ntree.AddChild(cameraTree);\n\ntree.Parent; // = null\ntree.Current; // = Root (GameObject)\ncameraTree.Parent; // = tree (Tree\u003cGameObject\u003e)\n\nforeach(Tree\u003cGameObject\u003e child in tree)\n{\n    child.Parent;\n    child.Current;\n    child.Children;\n}\n```\n\n### \u003cspan id=\"core-interfaces\"\u003eInterfaces\u003c/span\u003e\n\n#### `IDamageable`\n\nInterface used to expose a component that can take damages (from a hit, an attack or a fall).\n\n```csharp\npublic interface IDamageable\n{\n    public void TakeDamages(double damages);\n}\n```\n\n## Movement\n\nThe `Movement` module contains most of the components used for movement, jump, camera rotation.\nYou can enable it, if you want to create one of the following game archetype:\n\n- FPS\n- ~~TPS~~\n- Platformer\n- Arcade\n- ~~Top-down~~\n- ~~Twin-stick~~\n\nBy default, the `Movement` module is enabled but can be disabled in the [Setup Wizard](#setup-wizard).\nThis module is located under the `BaseTool.Movement` namespace.\n\n### \u003cspan id=\"movement-components\"\u003eComponents\u003c/span\u003e\n\n#### `OldMovementInput`\n\nIf you are not using the new input system, you can add this component on your player to quickly\nset up a player movement based on the old input system.\n\nThis component manages a `IMovable` and/or a `IJumpable` component ; if they are found, the inputs are processed and\nsent to the component.\n\n#### `FirstPersonController`\n\nThis component manages a first-person view based on a GameObject/Camera hierarchy.\nIn this kind an architecture, the component is placed at the root of the player object hierarchy.\nThen, the `Camera` is under, as a child. The `FirstPersonController` references the camera,\nusing `GetComponentInChildren` or referencing it from the inspector.\n\n![first_person_structure](./Documentation~/Movement/first_person_structure.png)\n\n**Caution** : this component requires a `Rigidbody` to work properly and is **not** using the Unity\n`CharacterController`.\n\n#### `SideViewController`\n\nA light side-view controller. It only manages the movement of the object. The architecture is quite simple, you need to\nadd this component on the element that can move, on its root (recommended).\n\n#### `TopDownController`\n\nThis component is used to get a 2.5D-like movement (action-rpgs like Diablo, Torchlight, Minecraft Dungeons...). You\nmust add the component on the player's root from\n`Add Component \u003e BaseTool \u003e Movement \u003e Top Down Controller`.\n\n![top_down_controller](./Documentation~/Movement/top_down_controller.PNG)\n\nThe camera **must** not be a child of the player ; you can use the `SimpleCameraController`\nor [Cinemachine](https://docs.unity3d.com/Manual/com.unity.cinemachine.html)\nto follow the player.\n\n#### `JumpController`\n\nThis component allows any object to jump, with a quick setup.\n\n![jump_controller](./Documentation~/Movement/jump_controller.png)\n\n| Property            | Description                                                                                                       |\n|---------------------|-------------------------------------------------------------------------------------------------------------------|\n| Rigidbody           | The `Rigidbody` of the jumpable element.                                                                          |\n| Jump Force          | The velocity to apply when the element needs to jump.                                                             |\n| Fall Multiplier     | The velocity multiplier when the element is falling.                                                              |\n| Jump Count          | The number of allowed jumps.                                                                                      |\n| Ground Mask         | The `LayerMask` to check when the element touches the ground.                                                     |\n| Ground Check Offset | The `Vector3` offset if your collision check is not on the ground.                                                |\n| Ground Check Size   | The radius of the collision check.                                                                                |\n| Coyote Effect Delay | The delay of the coyote effect ; the time allowed to the element to jump even if it is not on the ground anymore. |\n\n### \u003cspan id=\"movement-interfaces\"\u003eInterfaces\u003c/span\u003e\n\n#### `IMovable`\n\nThis interface can be used to expose a component as a moving object. It is used to send movement inputs. See [\n`OldMovementInput`](#oldmovementinput) and [`FirstPersonController`](#firstpersoncontroller) for more information.\n\n```csharp\npublic interface IMovable\n{\n    void Move(Vector2 move);\n\n    void Rotate(Vector2 rotation);\n}\n```\n\n#### `IJumpable`\n\nThis interface can be used to expose a component as a jumping object. It is used to send jump inputs. See [\n`OldMovementInput`](#oldmovementinput) and [`FirstPersonController`](#firstpersoncontroller) for more information.\n\n```csharp\npublic interface IJumpable\n{\n    public bool CanJump { get; }\n\n    public void Jump();\n}\n```\n\n## Shooter\n\nThe `Shooter` module contains most of the components used for weapons related games.\nYou can enable it, if you want to create one of the following game archetype:\n\n- FPS\n- TPS\n- Arcade shooter\n- Looter shooter\n- RTS\n\nBy default, the `Shooter` module is enabled but can be disabled in the [Setup Wizard](#setup-wizard).\nThis module is located under the `BaseTool.Shooter` namespace.\n\n### \u003cspan id=\"shooter-sample\"\u003eSample\u003c/span\u003e\n\nThe package include a shooter sample project using most of the primary components to begin creating an FPS game.\n\n### \u003cspan id=\"shooter-components\"\u003eComponents\u003c/span\u003e\n\n#### `OldShootInput`\n\nSimple component that handles input (from the old input system) and calls `IShootable` shoot and reload\nmethods. It could be used with the [`ShootController`](#shootcontroller) component as well.\n\n#### `ShootController`\n\nThis component can be added from the **AddComponent** menu by following `BaseTool \u003e Shooter \u003e Shoot Controller`. It\nimplements `IShootable` and `IShootController` interfaces.\n\nIt authorizes a GameObject to use a shoot logic and send shoot and reload information to other components.\n\n#### `WeaponController`\n\nThis component can be added from the **AddComponent** menu by following `BaseTool \u003e Shooter \u003e Weapon Controller`.\n\nIt is used to update, instantiate and swap weapons.\n\n#### `WeaponSwitcher`\n\nThis component can be added from the **AddComponent** menu by following `BaseTool \u003e Shooter \u003e Weapon Switcher`.\n\n#### `WeaponProjectile`\n\nThis component can be added from the **AddComponent** menu by following `BaseTool \u003e Shooter \u003e Weapon Projectile`.\n\nIt is used to add the projectile behaviour on a GameObject. This is for weapon purpose ; if a weapon must shoot\nprojectiles instead of a raycast, the GameObject must have this component.\n\n### \u003cspan id=\"shooter-interfaces\"\u003eInterfaces\u003c/span\u003e\n\n#### `IShootable`\n\nThis interface must be used on a component that can shoot. E.g. the player or enemies.\nIt forces the implementation of shooting and reloading method.\n\n```csharp\npublic interface IShootable\n{\n    public bool CanShoot { get; }\n    public void ShootPressed();\n    public void ShootReleased();\n    public void Reload();\n}\n```\n\n#### `IShootController`\n\nThis interface must be used by a component that declares and exposes its shooting callbacks.\nIt is not mandatory but allows other components to understand that some logics could be executed\nin the shoot process. For example, when you want a component that triggers animations when it shoots.\n\n```csharp\npublic interface IShootController\n{\n    public event Action OnStartShoot;\n    public event Action OnStopShoot;\n    public event Action OnReload;\n}\n```\n\n### Weapon\n\n#### `Weapon`\n\nThis is the main object used for every weapon. You can create any type of weapon using this base.\nTo create a new one, right click in your project window, then `Create \u003e BaseTool \u003e Shooter \u003e Weapon`.\n\n#### `WeaponCategory`\n\nThis object refers to a category that could be assigned to a weapon. It is used to sort weapons or identify ammos. To\ncreate a new one, right click in your project window, then `Create \u003e BaseTool \u003e Shooter \u003e Weapon Category`.\n\n## RPG\n\n[still in development]\n\n## RNG\n\n### PonderateRandom\n\nMany games uses randomizer tweaked to let some elements happens more times than others.\nIt is called \"ponderate randomisation\". You can create your own by using `PonderateRandom`\nclass and add weight on each element ; allowing some to happen more or less than others.\n\n```csharp\nusing BaseTool;\nusing UnityEngine;\n\nvar cheatedDice = new PonderateRandom\u003cstring\u003e {\n    { \"One\", 1 },\n    { \"Two\", 1 },\n    { \"Three\", 0.5f }, // the three happens twice less than others\n    { \"Four\", 1 },\n    { \"Five\", 1 },\n    { \"Six\", 2 }, // the six happens twice more than others\n};\n\n// use UnityEngine.Random\nDebug.Log(cheatedDice.Get());\n\n// use System.Random\nvar random = new System.Random(1);\nDebug.Log(cheatedDice.Get(random)); // always be \"Two\"\nDebug.Log(cheatedDice.Get(random)); // always be \"One\"\n```\n\n### Deck\n\nIf you want to make a card game, you need to store those cards\ninto a deck. That's the purpose of `Deck\u003cT\u003e`. It inherits from\nthe `PonderateRandom\u003cT\u003e` class.\n\nYou can define your deck directly from the inspector, with\ncard quantity. Thus, you can `Fill()` the deck at start and \n`Draw()` cards whenever you want.\n\n```csharp\n[SerializeField]\nprivate Deck\u003cGameObject\u003e _deck;\n\n_deck.Fill();\nGameObject element = _deck.Draw();\n```\n\n### Sample[](#rng-sample)\n\n![poker_sample](./Documentation~/RNG/poker_sample.png)\n\nIf you want to understand how the RNG module and `Deck\u003cT\u003e` work,\nyou can use the Poker Sample from the BaseTool package manager\npage's.\n\n## UI\n\nThe `UI` module contains most of the components used to manage user interfaces.\nYou can enable it, if you want to use a simple UI navigation workflow based on\nparenthood views architecture.\n\nThis module uses the `UnityEngine.UI` system and does not support\n`UnityEngine.UIElements` (UI Toolkit) yet.\n\nBy default, the `UI` module is enabled but can be disabled in the [Setup Wizard](#setup-wizard).\nThis module is located under the `BaseTool.UI` namespace.\n\n### \u003cspan id=\"ui-workflow\"\u003eWorkflow\u003c/span\u003e\n\nThe `UI` module follows [the official Unity UI recommendations](https://unity.com/fr/how-to/unity-ui-optimization-tips)\nabout optimization and organization.\nMeaning that you must set up a specific UI workflow to use the module:\n\n1. Any view must inherit from the [`View`](#view) class ;\n2. Each view must have a `Canvas` component ;\n3. Views must be opened and closed using the `Navigation` class only ;\n4. Sub-views must be children of a parent view in the Unity GameObject hierarchy ; and\n5. Every view must be in the scene at start with its canvas disabled.\n\nSee the [sample](#ui-sample) for more examples.\n\n### `View`\n\nWhat is called a view is a page of an element that can be displayed or opened\nby the user (like the inventory, settings, pause menu...). Any view created\nmust inherit from the `View` class that automatically registers the component\nto the `Navigation`.\n\nCaution: using UI GameObject that could be a view without inheriting from `View`\ncould brake the navigation workflow.\n\nYou can create a view from the template by right click in your assets project :\n`Create \u003e BaseTool \u003e UI \u003e View Class`.\n\n```csharp\nusing BaseTool.UI;\n\npublic class MyView : View\n{\n    // Called when the view is opened\n    public override void OnNavigateFrom(View fromView, NavigationArgs args)\n    {\n        base.OnNavigateFrom(toView, args);\n    }\n\n    // Called when the view is closed\n    public override void OnNavigateTo(View toView, NavigationArgs args)\n    {\n        base.OnNavigateTo(toView, args);\n    }\n}\n```\n\n| Methods and properties                 | Description                                                                                                                 |\n|----------------------------------------|-----------------------------------------------------------------------------------------------------------------------------|\n| **Properties**                         |\n| Tree                                   | Get the full tree of the view, knowing its parent and its children.                                                         |\n| Parent                                 | Get the parent view (if it exists).                                                                                         |\n| IsVisible                              | Returns true if the view is displayed (child or not).                                                                       |\n| **Methods**                            |\n| `Display(boolean)`                     | Display (or hide) the view and its parent.                                                                                  |\n| `OnNavigateFrom(View, NavigationArgs)` | Method called by the `Navigation` when the view is displayed (navigated from another view passed by parameter).             |\n| `OnNavigateTo(View, NavigationArgs)`   | Method called by the `Navigation` when the view is closed (when navigation wants to open another view passed by parameter). |\n\n### `Navigation`\n\nThe `Navigation` class **must be** the only way to display or hide views. This is\nbecause it uses a navigation history to go backward. You can add the `BackBehaviour`\ncomponent anywhere in your scene to add this behaviour (or handle the back yourself).\n\n| Methods         | Description                                        |\n|-----------------|----------------------------------------------------|\n| `Open\u003cView\u003e()`  | Open the view following the type in parameter.     |\n| `Close\u003cView\u003e()` | Close the view following the type in parameter.    |\n| `Back()`        | Close the current view and open the previous one.  |\n| `Clear()`       | Hide every views and clear the navigation history. |\n\nThe basic workflow, if you properly set up your views, is :\n\n```csharp\nusing BaseTool.UI;\n\n// View on the root UI\npublic class HomeView : View {}\n\n// View on the root UI\npublic class SettingsView : View {}\n\n// View inside the SettingsView\npublic class AudioSettingsView : View {}\n\nNavigation.Open\u003cHomeView\u003e(); // will open the HomeView\nNavigation.Open\u003cSettingsView\u003e(); // will open SettingsView\n\nNavigation.Back(); // will close the SettingsView and open the HomeView\n\nNavigation.Open\u003cAudioSettingsView\u003e(); // will open the AudioSettingsView\n\n//will open the AudioSettingsView that is inside the SettingsView\nNavigation.Open\u003cSettingsView, AudioSettingsView\u003e(); \n```\n\nThe `Open()` method can be used to open differents views. If you made a view\n\"unique\", that only exists once, you can use the `Navigation.Open\u003cT\u003e()` method.\nBut, if the view you want to open exists multiple times, and could be different\ndepending on the context, you can open the view by a path search using two generics:\n`Navigation.Open\u003cT1, T2\u003e()` ; like the example in the code upper.\n\nYou can also pass arguments when you want to open the view. Arguments will be sent\nto the `OnNavigateTo()` on the closing view and `OnNavigateFrom()` on the opening view.\n\n```csharp\nusing BaseTool.UI;\n\npublic class UserArgs : NavigationArgs\n{\n    public string Email;\n    public string Password;\n}\n\npublic class UserView : View \n{\n    public override void OnNavigateFrom(View fromView, NavigationArgs args)\n    {\n        if(args is UserArgs userArgs)\n        {\n            ConnectToServer(userArgs.Email, userArgs.Password);\n        }\n    }\n\n    private void ConnectToServer(string user, string pass)\n    {\n        // do something with data\n    }\n}\n```\n\n### \u003cspan id=\"ui-sample\"\u003eSample\u003c/span\u003e\n\nThe package include a UI sample project that contains scripts to understand the\nnavigation workflow.\n\nYou can download it from the package manager, in the BaseTool sample tab.\n\n## Editor\n\n### Misc Buttons\n\nThe package contains useful buttons/links directly accesible from the `Window` menu.\nHere are their functions:\n\n- `Window \u003e BaseTool \u003e Documentation` will open the documentation ;\n- `Window \u003e BaseTool \u003e Report a bug...` will redirect you to the [issue](https://github.com/DarkRewar/BaseTool/issues)\n  page ;\n- `Window \u003e BaseTool \u003e Open Data Folder` will open the `Application.dataPath` in the Explorer/Finder ;\n- `Window \u003e BaseTool \u003e Open Persistent Data Folder` will open the `Application.persistentDataPath` in the\n  Explorer/Finder.\n\n### Todo List\n\nIf you go to `Window \u003e BaseTool \u003e Todo List`, you can get an editor window that opens.\nIt will list you every TODO and FIXME entries found in your project.\n\n![todo_list.png](./Documentation~/Editor/todo_list.png)\n\nEntries are grouped by assemblies and can be filtered by tags. You can also bind developers to entries.\nHow does it work? In your C# script, inside your project, you can add todo and fixme comments. The tool\nwill detect them and add them to the list. To add some, you must follow those rules:\n\n- start by a comment and a todo, fix or fixme : `//Todo`, `//Fix` or `//Fixme` ;\n- (optionnal) you can add metadata between parenthesis:\n    - if it begins by `@`, it will be detected as a dev name ;\n    - if it begins by `#`, it will be detected as a tag to filter entries ;\n- (optionnal) you can add `:` to split the beginning of comment and content ;\n- end with the message of the todo/fix you want to display.\n\nYou can see some following examples:\n\n```csharp\n//TODO a normal todo\n//todo can be case insensitive\n//Todo(@MyDeveloperName) : you can add names and punctation\n//Todo(@MyName #core #engine #gameplay) : you can also add tags to filter entries\n//Fixme : will be displayed\n//Fix works like fixme\n```\n\n### `MinMaxAttribute`\n\nThis attribute allows you to put a slider range for a value in the inspector. It is used to create a range using\n`Vector2`.\n\n![min_max_attribute](./Documentation~/Editor/min_max_attribute.png)\n\n```csharp\nusing BaseTool;\nusing UnityEngine;\n\npublic class MyClass : MonoBehaviour\n{\n    [MinMax(0, 20)]\n    public Vector2 MinMaxTest = new(5, 15);\n\n    public bool IsValueInRange(float value) =\u003e \n        value.IsBetween(MinMaxTest.x, MinMaxTest.y);\n}\n```\n\n### `IfAttribute`\n\nThis attribute can display its property from inspector only if condition is checked.\n\n```csharp\nusing BaseTool;\nusing UnityEngine;\n\npublic class MyClass : MonoBehaviour\n{\n    public bool UseProjectile = true;\n\n    [If(nameof(UseProjectile))]\n    public GameObject ProjectilePrefab;\n\n    public float ProjectileSpeed = 1f;\n    \n    [If(\"ProjectileSpeed \u003e 1\")]\n    public GameObject ProjectileFX;\n}\n```\n\n### `IfNotAttribute`\n\nThis attribute can hide its property from inspector only if condition is checked.\n\n```csharp\nusing BaseTool;\nusing UnityEngine;\n\npublic class MyClass : MonoBehaviour\n{\n    public bool UseRaycast = true;\n\n    [IfNot(nameof(UseRaycast))]\n    public GameObject ProjectilePrefab;\n\n    public float ProjectileSpeed = 1f;\n    \n    [If(\"ProjectileSpeed \u003e 1\")]\n    public GameObject ProjectileFX;\n}\n```\n\n### `EnableIfAttribute`\n\nThis attribute can mark its field as readonly in the inspector if\nthe condition is false.\n\n```csharp\nusing BaseTool;\nusing UnityEngine;\n\npublic class MyClass : MonoBehaviour\n{\n    public bool IsStrong = true;\n\n    [EnableIf(nameof(IsStrong))]\n    public float Strength = 10f;\n\n    [EnableIf(\"!IsStrong\")]\n    public float NonStrength = 10f;\n}\n```\n\n### `DisableIfAttribute`\n\nThis attribute can mark its field as readonly in the inspector if\nthe condition is true.\n\n```csharp\nusing BaseTool;\nusing UnityEngine;\n\npublic class MyClass : MonoBehaviour\n{\n    public bool IsStrong = true;\n\n    [DisableIf(\"!IsStrong\")]\n    public float Strength = 10f;\n\n    [DisableIf(nameof(IsStrong))]\n    public float NonStrength = 10f;\n}\n```\n\n### `ReadOnlyAttribute`\n\nThis attribute can mark the field or property as disabled in inspector (unchangeable).\n\n```csharp\nusing BaseTool;\nusing UnityEngine;\n\npublic class MyClass : MonoBehaviour\n{\n    [ReadOnly]\n    public int Lifepoints = 10;\n}\n```\n\n### `SuffixAttribute`\n\nThis attribute can place a text as suffix in the input field in inspector.\n\n![suffix_attribute](./Documentation~/Editor/suffix_attribute.PNG)\n\n```csharp\nusing BaseTool;\nusing UnityEngine;\n\npublic class MyClass : MonoBehaviour\n{\n    [Suffix(\"m/s\")]\n    public float Velocity = 10f;\n}\n```\n\n### `PrefixAttribute`\n\nThis attribute can place a text as prefix before the input field in inspector.\n\n![prefix_attribute](./Documentation~/Editor/prefix_attribute.PNG)\n\n```csharp\nusing BaseTool;\nusing UnityEngine;\n\npublic class MyClass : MonoBehaviour\n{\n    [Prefix(\"m/s\")]\n    public float Velocity = 10f;\n}\n```\n\n### `MessageAttribute`\n\nYou can add a `[Message]` attribute before a field to display a message in the inspector.\nYou need to pass the message as the first parameter, and you can precise which type of message\nyou want (None, Info, Warning or Error).\n\n```csharp\n[MessageAttribute(string message, MessageAttribute.MessageType type = MessageAttribute.MessageType.Info)]\n```\n\nThere also is three shortcut to write those messages:\n`InfoMessage`, `WarningMessage` and `ErrorMessage`.\n\n```csharp\nusing BaseTool;\nusing UnityEngine;\n\npublic class MyClass : MonoBehaviour\n{\n    [Message(\"This is a normal message\")]\n    public float _hello;\n\n    [WarningMessage(\"This is a warning message\")]\n    public float _helloWarning;\n\n    [Message(\"This is an error message\", MessageAttribute.MessageType.Error)]\n    public float _helloError;\n}\n```\n\n![message_attribute](./Documentation~/Editor/message_attribute.PNG)\n\n### `ButtonAttribute`\n\nYou can add a `[Button]` attribute before a method to display a button in the inspector.\nWhen clicked, it will execute the method linked to the button attribute.\n\n```csharp\nusing BaseTool;\nusing UnityEngine;\n\npublic class ButtonTest : MonoBehaviour\n{\n    [Button]\n    public void DoSomething()\n    {\n        Debug.Log(\"Method called from inspector\");\n    }\n}\n```\n\n![button_attribute](./Documentation~/Editor/button_attribute.png)","funding_links":["https://github.com/sponsors/DarkRewar","https://ko-fi.com/rewar"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdarkrewar%2Fbasetool","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdarkrewar%2Fbasetool","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdarkrewar%2Fbasetool/lists"}