Skip to content

Conversation

@ltwlf
Copy link

@ltwlf ltwlf commented Jan 29, 2025

This PR enables on-change callbacks for value-type SyncVar<> fields by allowing users to specify a callback method name via [SyncVarFlags("CallbackName")]. Whenever a SyncVar<> changes.

Additionally, custom sync fields (e.g., SyncString, SyncNetSerializable) now support a ValueChanged event, letting developers subscribe to any changes.

Unfortunately, SyncVar Value Types and SyncFields must be handled differently.

Example:

using LiteEntitySystem;
using LiteEntitySystem.Internal;
using UnityEngine;

[EntityFlags(EntityFlags.UpdateOnClient)]
public class TestEntity : EntityLogic
{
    // A simple SyncVar<int> with an on-change callback
    [SyncVarFlags("OnCounterChanged")]
    private SyncVar<int> _counter;

    // A SyncVar<bool> with another callback
    [SyncVarFlags("OnToggle")]
    private SyncVar<bool> _toggle;

    // A custom sync field (e.g., SyncString) that raises a ValueChanged event
    private readonly SyncString _greeting = new();

    // Normal constructor
    public TestEntity(EntityParams entityParams) : base(entityParams) {}

    // Called when `_counter` changes
    private void OnCounterChanged(int newValue)
    {
        if (IsClient)
            Debug.Log("Counter changed to: " + newValue);
    }

    // Called when `_toggle` changes
    private void OnToggle(bool state)
    {
        if (IsClient)
            Debug.Log("Toggle state changed: " + state);
    }

    // Example usage of SyncString's event
    private void OnGreetingValueChanged(string oldValue, string newValue)
    {
        if (IsClient)
            Debug.Log($"Greeting changed from '{oldValue}' to '{newValue}'");
    }

    protected override void OnConstructed()
    {
        base.OnConstructed();

        // Subscribe to the SyncString's ValueChanged event
        _greeting.ValueChanged += OnGreetingValueChanged;

        if (IsServer)
        {
            // You can initialize values on the server
            _counter.Value = 1;
            _greeting.Value = "Hello from the server!";
        }
    }

    private float _elapsedTime;

    protected override void Update()
    {
        if (IsServer)
        {
            // Increment `_counter` and flip `_toggle` every 2 seconds
            _elapsedTime += Time.deltaTime;
            if (_elapsedTime >= 2f)
            {
                _counter.Value += 1;
                _toggle.Value = !_toggle.Value;

                // Also update the greeting
                _greeting.Value = "Server greeting " + _counter.Value;

                _elapsedTime = 0f;
            }
        }
    }
}

@ltwlf ltwlf changed the title Event-driven SyncVar updates Event-driven SyncVar/Field updates Feb 2, 2025
@ltwlf ltwlf changed the title Event-driven SyncVar/Field updates SyncVar/Field Change Events Feb 2, 2025
@ltwlf
Copy link
Author

ltwlf commented Feb 2, 2025

@RevenantX would do you thinks about this? I know that you can subscribe with bind to value type changes, but I tried to make it easier for devs. For Sync Fields I coudn't find a way for change notifications in the current codebase.

- Implemented `ISyncFieldChanged<T>` interface for syncable fields to handle value changes.
- Added `ValueChanged` event in relevant classes to notify when values change.
- Updated methods to include field names in processing for better tracking.
- Introduced a callback registry to manage and invoke user-defined callbacks on type value changes.
@RevenantX
Copy link
Owner

RevenantX commented Feb 2, 2025

@ltwlf i use BindOnChange because it work for IL2CPP (and possibly for some AOT things in future) inside Unity.
IL2CPP need to know all generic types that will be used in resulting code. And methods that called by reflection without direct call can be stripped from resulting executable

https://docs.unity3d.com/6000.0/Documentation/Manual/scripting-backends-il2cpp.html

- Removed event handling for value changes in SyncableField.
- Cleaned up unused using directives across several files.
- Simplified the SyncVar struct by removing unnecessary event logic.
- Enhanced method to find methods in class hierarchy for better flexibility.
- Streamlined equality operator implementations for clarity.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants