{"id":18238600,"url":"https://github.com/eyellen/eyellen.unity.observablefields","last_synced_at":"2026-05-19T19:03:07.674Z","repository":{"id":257997750,"uuid":"872009653","full_name":"Eyellen/Eyellen.Unity.ObservableFields","owner":"Eyellen","description":"Simple implementation of observable fields for Unity","archived":false,"fork":false,"pushed_at":"2024-12-07T07:29:31.000Z","size":35,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-08T16:11:40.021Z","etag":null,"topics":["observer-pattern","unity"],"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/Eyellen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2024-10-13T14:55:38.000Z","updated_at":"2024-12-07T07:29:35.000Z","dependencies_parsed_at":"2024-12-05T05:19:23.952Z","dependency_job_id":"0a566c1c-60b2-4b06-9dd4-b99bb27996c3","html_url":"https://github.com/Eyellen/Eyellen.Unity.ObservableFields","commit_stats":null,"previous_names":["eyellen/eyellen.unity.observablefields"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Eyellen%2FEyellen.Unity.ObservableFields","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Eyellen%2FEyellen.Unity.ObservableFields/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Eyellen%2FEyellen.Unity.ObservableFields/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Eyellen%2FEyellen.Unity.ObservableFields/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Eyellen","download_url":"https://codeload.github.com/Eyellen/Eyellen.Unity.ObservableFields/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247878021,"owners_count":21011158,"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":["observer-pattern","unity"],"created_at":"2024-11-05T03:06:13.184Z","updated_at":"2026-05-19T19:03:02.638Z","avatar_url":"https://github.com/Eyellen.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Unity Observable Fields\n\nSimple observable fields implementation for Unity that works with an inspector.\n\n# Installation\n\n## Install via UPM (using Git URL)\nOpen Unity \u003e Window \u003e Package Manager \u003e + \u003e Add package from git URL:\n```\nhttps://github.com/Eyellen/Eyellen.Unity.ObservableFields.git\n```\nPaste and press \"Add\"\n\n# Summary\n\n`ObservableField` - Does not support inspector and uses only pure C# features.\u003c/br\u003e\n`UnityObservableField` - Supports inspector, uses C# and Unity events. You can assign Unity events in the inspector.\u003c/br\u003e\n`IReadOnlyObservableField` - Read only interface for observable fields. Allows to get read only value and subscribe to changes.\u003c/br\u003e\n`IObservableFieldEvents` - Interface that provides methods to subscribe or unsubscribe from changes.\u003c/br\u003e\n\n# Important Notes\n\n- You must call constructor for observable fields, otherwise it will give a `NullReferenceException`. The only exception is if you're going to use `SerializeFieldAttribute` on `UnityObservableField` and as a T parameter you pass a type that has `SerializableAttribute`, i.e. Unity is able to serialize that field.\n- If you want Unity events to be called in edit mode make sure to set `UnityEventCallState` to `EditorAndRuntime` in the inspector, it's next to each method reference in the unity event property. If you want C# events to be called in edit mode make sure to add `ExecuteAlwaysAttribute` to your class.\n- If you pass your custom type to `UnityObservableField` and want it to appear in the inspector make sure to add `SerializableAttribute` to your type.\n- Remember that reference types are reference types, `ObservableField` will not fire events when reference type's members will be changed, it will fire event only if the reference itself is changed. If you need to fire event when complex object is changed prefer using structs.\n\n# Usage\n\n## Declaring observable fields:\n```CSharp\nusing System;\nusing UnityEngine;\n\nnamespace Eyellen.Unity.ObservableFields.Examples\n{\n    public class ObservableFieldDeclaration : MonoBehaviour\n    {\n        // ObservableField does not support inspector. If you want it to show up in the inspector, use UnityObservableField.\n        // Does not appear in the inspector even though it has a SerializeField attribute.\n        // Uses CSharp events.\n        [SerializeField]\n        private ObservableField\u003cbool\u003e ObservableBool = new();\n\n        // Displayed in the inspector.\n        // Uses CSharp events and Unity events. Unity events can be assigned in the inspector.\n        [SerializeField]\n        private UnityObservableField\u003cbool\u003e UnityObservableBool = new();\n\n        // Displayed in the inspector since a passed type have Serializable attribute.\n        [SerializeField]\n        private UnityObservableField\u003cSerializedType\u003e SerializableType = new();\n\n        // Does not appear in the inspector because a type passed to a field is not serializable.\n        [SerializeField]\n        private UnityObservableField\u003cNonSerializedType\u003e NonSerializableType = new();\n    }\n\n    public class NonSerializedType\n    {\n        public string Name;\n        public string Description;\n    }\n\n    [Serializable]\n    public class SerializedType\n    {\n        public string Name;\n        public string Description;\n    }\n}\n```\n\nDeclared `UnityObservableField`s will look like this in the inspector:\u003c/br\u003e\n![Pasted image 20241016005148](https://github.com/user-attachments/assets/216b5910-afd9-4b60-9ca3-f877239cf100)\n\n## Subscribing to observable field changes:\n```CSharp\nusing UnityEngine;\n\nnamespace Eyellen.Unity.ObservableFields.Examples\n{\n    public class ObservableFieldSubscribing : MonoBehaviour\n    {\n        // You can subscribe to observable field changes in code and in inspector.\n        // NOTE: To subscribe on changes in the inspector use UnityObservableField.\n\n        private ObservableField\u003cint\u003e Number;\n\n        [SerializeField]\n        private UnityObservableField\u003cstring\u003e String;\n\n        private void Awake()\n        {\n            // ObservableField.\n            // Subscribing to C# events.\n            Number.SubscribeOnChange(OnValueChangedEventArgs);\n            Number.SubscribeOnChange(OnValueChangedTTArgs);\n            Number.SubscribeOnChange(OnValueChangedNoArgs);\n\n            // UnityObservableField.\n            // Subscribing to C# events.\n            String.SubscribeOnChange(OnValueChangedEventArgs);\n            String.SubscribeOnChange(OnValueChangedTTArgs);\n            String.SubscribeOnChange(OnValueChangedNoArgs);\n        }\n\n        // Method that takes ObservableField.EventArgs as a parameter.\n        // ObservableField.EventArgs contain previous and current values.\n        private void OnValueChangedEventArgs\u003cT\u003e(ObservableField\u003cT\u003e.EventArgs args)\n        {\n            Debug.Log(\n                $\"Call {nameof(OnValueChangedEventArgs)}: Previous value - {args.Previous}. Current value - {args.Current}\"\n            );\n        }\n\n        // Method that takes previous and current value as a parameters.\n        private void OnValueChangedTTArgs\u003cT\u003e(T previous, T current)\n        {\n            Debug.Log(\n                $\"Call {nameof(OnValueChangedTTArgs)}: Previous value - {previous}. Current value - {current}\"\n            );\n        }\n\n        // Method that takes no parameters.\n        private void OnValueChangedNoArgs()\n        {\n            Debug.Log($\"Call {nameof(OnValueChangedNoArgs)}\");\n        }\n    }\n}\n```\n\nInspector:\u003c/br\u003e\n`Use Unity Events` - indicates if Unity events will be called. If has false value Unity events will not be called even if they were assigned.\u003c/br\u003e\n![Pasted image 20241016005315](https://github.com/user-attachments/assets/5fd2922f-0cd5-42f9-a823-d96b1b5cccf2)\n\nIf you want to use Unity events, check `Use Unity Events` and `Events` foldout will pop up:\u003c/br\u003e\n![Pasted image 20241016005415](https://github.com/user-attachments/assets/c3a774ec-3257-46db-8ba8-154547130b1b)\n\nClick on `Events` foldout and there are 4 Unity events:\n1. Passes `ObservableField.EventArgs` as a parameter\n2. Passes `Previous` and `Current` values as a parameters\n3. Passes `Current` value as a parameter\n4. Passes no parameters\u003c/br\u003e\n![Pasted image 20241016005538](https://github.com/user-attachments/assets/064b78e7-9df6-44fb-8439-c9c672127f1f)\n\n## Using IReadOnlyObservableField\n```CSharp\nusing UnityEngine;\n\nnamespace Eyellen.Unity.ObservableFields.Examples\n{\n    public class UsingIReadOnlyObservableField : MonoBehaviour\n    {\n        // You can use IReadOnlyObservableField if you want to allow readonly value on you observable field\n        // but want to protect it from changes from outside the class.\n\n        // Private observable field.\n        // Can't be accessed outside the class.\n        [SerializeField]\n        private UnityObservableField\u003cfloat\u003e _float = new();\n\n        // Public IReadOnlyObservableField.\n        // Can be accessed outside the class.\n        // Provides only readonly Value getter and methods to subscribe to change event.\n        public IReadOnlyObservableField\u003cfloat\u003e Float =\u003e _float;\n    }\n}\n```\n\n## Implementing Getter/Setter's\n```CSharp\nusing UnityEngine;\n\nnamespace Eyellen.Unity.ObservableFields.Examples\n{\n    public class ObservableFieldGetterSetters : MonoBehaviour\n    {\n        // You can add Getter/Setter like behaviour to observable fields and specify Get/Set logic.\n        // Getter/Setter behaviour works fine with an inspector.\n        // Getter/Setter's are passed into a field constructor as a Func\u003cT, T\u003e\n        // where first value is input value and the second one is processed result.\n\n        // Here we implemented setter that clamps passed value between 0 and 10.\n        [SerializeField]\n        private UnityObservableField\u003cint\u003e ObservableInt =\n            new(default, value =\u003e Mathf.Clamp(value, 0, 10));\n\n        // Here we implemented getter that simply returns the passed float number as a negative while keeping original value as positive.\n        [SerializeField]\n        private UnityObservableField\u003cfloat\u003e ObservableFloat = new(default, null, value =\u003e -value);\n    }\n}\n```\n\n# License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feyellen%2Feyellen.unity.observablefields","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feyellen%2Feyellen.unity.observablefields","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feyellen%2Feyellen.unity.observablefields/lists"}