Skip to content

Latest commit

 

History

History
285 lines (193 loc) · 10.2 KB

File metadata and controls

285 lines (193 loc) · 10.2 KB

Component Connector V2 ✨

Stop dragging things into the Inspector. Component Connector wires up your serialized references automatically, by name, the moment you build the hierarchy.

🇰🇷 한국어 README는 README.ko.md 에서 볼 수 있습니다.

cc_img_1

public class HUD : MonoBehaviour {
    [ComponentConnect] public Text   scoreText;   // ← finds GameObject "scoreText"
    [ComponentConnect] public Slider hpBar;       // ← finds GameObject "hpBar"
    [GetComponent]     public Canvas canvas;      // ← grabs Canvas on this GameObject
}

That's it. No Find(), no manual drag, no setup component, no runtime cost.


What's new in V2 ✨

V2 is a complete rewrite. Same attributes, dramatically better behavior:

V1 V2
Helper component on GameObject Required (ComponentConnector MonoBehaviour) Not needed
Trigger Update() poll every 0.1s Event-driven (hierarchyChanged, prefabStageOpened, prefabSaving)
Prefab Mode ❌ Scene only ✅ Fully supported (isolated stage + on-save)
Dirty marking ❌ Changes silently lost on reload EditorUtility.SetDirty
Undo support Undo.RecordObject
Field visibility public only public / private / protected / [SerializeField]
Method visibility ([OnClick]) public only All visibilities
Reflection Re-scanned every tick Cached per Type
[OnClick] re-binding Removed & re-added every tick → constant scene dirty No-op when already correct
[GetComponent] overrides Always overwritten User assignments preserved
Distribution Single file copy Single file copy or UPM

V2 is drop-in compatible with V1 — the legacy ComponentConnector MonoBehaviour ships as a no-op stub so existing scenes and prefabs keep loading without errors. See CHANGELOG.md for the full list.


Installation 📦

Option A — Single file (recommended for most projects)

Copy one file. That's the whole installation.

Download ComponentConnector.cs and drop it anywhere under your Assets/ folder.

  • No setup component to attach
  • No initialization step
  • No package manifest to edit
  • The editor-only logic is wrapped in #if UNITY_EDITOR and stripped from player builds

Option B — Unity Package Manager (UPM)

If you prefer dependency-managed installs:

In Unity: Window → Package Manager → + → Install package from git URL...

https://github.com/synchrok/ComponentConnector.git

Or add to Packages/manifest.json:

{
  "dependencies": {
    "com.synchrok.componentconnector": "https://github.com/synchrok/ComponentConnector.git"
  }
}

To pin a version, append #v2.0.0:

https://github.com/synchrok/ComponentConnector.git#v2.0.0

Usage ⚡️

[ComponentConnect] — wire by GameObject name

Add the attribute to any field that's visible in the inspector. The matched GameObject (or its component) gets assigned automatically.

using UnityEngine;
using UnityEngine.UI;

public class ShopPanel : MonoBehaviour {

    // 1. Match by field name → looks for a GameObject called "title"
    [ComponentConnect] public Text title;

    // 2. Match by an explicit name → looks for "BuyButton"
    [ComponentConnect("BuyButton")] public Button buyButton;

    // 3. Private / protected / [SerializeField] all work
    [ComponentConnect, SerializeField] private Image icon;
    [ComponentConnect]                 protected Text description;

    // 4. GameObject reference (instead of a component)
    [ComponentConnect("Backdrop")] public GameObject backdrop;
}

Search order

  1. this.gameObject and its descendants
  2. transform.root and all its descendants (skipped when inChildren = true, which is the default for the parameterless overload)
  3. Every other root GameObject in the active scene (or in the open prefab stage)

[ComponentConnect("Name~")] — collect arrays by prefix

Suffix the lookup name with ~ to gather every GameObject whose name starts with the keyword:

public class Inventory : MonoBehaviour {
    // Matches "Slot0", "Slot_A", "SlotEpic", ... in document order
    [ComponentConnect("Slot~")] public GameObject[] slots;

    // Component arrays work too — each match's component is grabbed
    [ComponentConnect("Enemy~")] public Enemy[] enemies;
}

[ComponentConnect("Parent...Child")] — disambiguate by parent

Use ... between a parent name and a child name when several siblings share the same name (think: every list row has its own Icon child):

public class HeaderBar : MonoBehaviour {
    // Finds a child named "Icon" under a parent named "Header"
    [ComponentConnect("Header...Icon")] public Image headerIcon;

    // Finds "Label" under "Footer"
    [ComponentConnect("Footer...Label")] public Text footerLabel;
}

[GetComponent] — pull a component on the same GameObject

public class Player : MonoBehaviour {
    [GetComponent] public Rigidbody2D    body;
    [GetComponent] public SpriteRenderer sprite;
    [GetComponent] public Animator       animator;
}

If the field already has a value you assigned manually, v2 leaves it alone.

[OnClick] — auto-bind UI Button click handlers

Mark the class with IComponentConnector, then put [OnClick("ButtonName")] on the handler method. The matching Button.onClick persistent listener is wired up at edit time — fully serialized, zero runtime cost.

using UnityEngine;

public class MainMenu : MonoBehaviour, IComponentConnector {

    [OnClick("StartButton")]
    private void OnStart() {
        Debug.Log("Start!");
    }

    [OnClick("QuitButton")]
    private void OnQuit() {
        Application.Quit();
    }

    // The same method can be bound to multiple buttons
    [OnClick("HelpButton")]
    [OnClick("InfoButton")]
    private void ShowHelp() { /* ... */ }
}

Full example — putting it all together

using UnityEngine;
using UnityEngine.UI;

public class CharacterCard : MonoBehaviour, IComponentConnector {

    [GetComponent]                       public CanvasGroup     canvasGroup;
    [GetComponent]                       public RectTransform   rectTransform;

    [ComponentConnect]                   public Image           portrait;
    [ComponentConnect("Name")]           public Text            nameLabel;
    [ComponentConnect("HP...Fill")]      public Image           hpFill;
    [ComponentConnect("Buff~")]          public GameObject[]    buffIcons;

    [ComponentConnect, SerializeField] private Button equipButton;
    [ComponentConnect, SerializeField] private Button dismissButton;

    [OnClick("EquipButton")]
    private void OnEquip()   { /* ... */ }

    [OnClick("DismissButton")]
    private void OnDismiss() { /* ... */ }
}

cc_img_3 cc_img_4


When does it run? ⏱

V2 is event-driven. Wiring runs automatically when:

  • The hierarchy changes (add / move / rename a GameObject)
  • A prefab is opened in Prefab Mode
  • A prefab is saved
  • You right-click any component header → Component Connect (manual trigger)

It does not poll. It is dormant during play mode, compilation, and asset import.


Performance 🚀

V1's full-scene scan every 100 ms is gone. V2:

  • Caches reflection per Type (one-time cost per script type)
  • Skips fields that already hold a live Object
  • Coalesces multiple hierarchyChanged events in one frame via EditorApplication.delayCall
  • Marks dirty only when something actually changed
  • Skips [OnClick] re-binding when the listener already points at (target, method)

You should see effectively zero overhead in normal editor use.


Migrating from V1 🔁

  1. Replace your old ComponentConnector.cs with the V2 file (same name and location works perfectly), or install via UPM.
  2. Optional cleanup: remove the ComponentConnector MonoBehaviour from scene roots — it's no longer needed. (V2 keeps a no-op stub class so existing scenes still load.)

No attribute signatures changed. Your existing [ComponentConnect] / [GetComponent] / [OnClick] code keeps working as-is.


FAQ

Does this run in builds? No. The processor is wrapped in #if UNITY_EDITOR and stripped from player builds. References get baked into the serialized scene/prefab — at runtime there is zero overhead.

Will it overwrite a reference I assigned manually? No. V2 only fills fields whose current value is null (or an empty array).

What about [OnClick] — will it nuke my existing button bindings? It only touches buttons matched by name, and only if the existing persistent listener doesn't already point to (this, method). If it's already correct, it's a no-op.

Does it work with nested prefabs / prefab variants? Yes — PrefabStage events fire for both, and the on-save hook catches anything the live editor missed.

Why isn't my newly-added [ComponentConnect] field getting populated? The processor reacts to hierarchy changes, not to script edits. After adding the attribute, either change the hierarchy (rename / re-parent any object), save the prefab, or right-click the component header and pick Component Connect.

Minimum Unity version? 2021.3 LTS or newer (uses the UnityEditor.SceneManagement.PrefabStage API).


Projects using Component Connector 👀

Disclaimer ⚠

I take no responsibility for issues you may encounter using this code. But it has saved me a lot of time on the projects above.

License

Component Connector is released under the MIT license. See LICENSE for details.