BoltEngine / Bolt-Tracker

New issue tracker for Photon Bolt
10 stars 2 forks source link

Trigger delegate not being fired on proxies when set outside of/after Attached() #141

Closed cantorek closed 4 years ago

cantorek commented 5 years ago

How to reproduce issue

  1. Create state
  2. Create trigger property, set replicate to everyone
  3. Set the delegate in script attached to GO that is not EntityEventListener GetComponent<BoltBugTest>().state.OnGameOver += Log;

Expected Behavior

Delegate function (Log) should fire on all proxies

Actual behavior

Delegate function (Log) is called only on the owner

Configuration

When using state.AddCallback in the same place in code on different property it works fine. I wasn't able to use state.AddCallback with triggers successfully.

In example below, delegate function - Log - is being fired only on the owner. When changing the subscription place to within Attached() it works fine. This is however unexpected as delegate can be set anywhere in the code - hence it's a delegate. Also, using State.AddCallback works just fine. Trigger state is being replicated, I can see frame counter update within inspector. According to my debug log output, BoltBugTest2.Start() is being run after BoltBugTest.Attached().

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BoltBugTest : Bolt.EntityEventListener<IGameState>
{
    public override void Attached()
    {
        Debug.Log("Attached() " + this);
        base.Attached();
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BoltBugTest2 : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        Debug.Log("Start() " + this);
        GetComponent<BoltBugTest>().state.OnGameOver += Log;

        if (GetComponent<BoltBugTest>().entity.IsOwner)
            StartCoroutine(TrigerLog());
    }

    public IEnumerator TrigerLog()
    {
        while (true)
        {
            GetComponent<BoltBugTest>().state.GameOver();
            yield return new WaitForSeconds(1);
        }
    }

    public void Log()
    {
        Debug.Log("Is owner or controller? " + GetComponent<BoltBugTest>().entity.IsControllerOrOwner);
    }
}
ramonmelo commented 4 years ago

The initialization of a Bolt Entity is a frame-sensitive process, that is why we provide several callbacks to make sure it occurs at the right moment and you don't need to sync the flow yourself.

In your case, there is no way to properly know when the Start method of your other class will execute, as this is controlled by Unity itself.

There are two ways you can have your desired behavior working:

  1. Just extend the Bolt.EntityBehaviour<IState> with the right State and override the Attached() callback. The Bolt Prefabs can have multiple of those.
using System.Collections;
using Bolt.Samples.GettingStarted;
using UnityEngine;

public class BoltBugTets : Bolt.EntityBehaviour<IState>
{
    void Start()
    {
        if (entity.IsOwner)
        {
            StartCoroutine(TrigerLog());
        }
    }

    public override void Attached()
    {
        state.OnGameOver += Log;
    }

    public IEnumerator TrigerLog()
    {
        while (true)
        {
            state.GameOver();
            yield return new WaitForSeconds(1);
        }
    }

    public void Log()
    {
        BoltLog.Warn("Is owner or controller? {0}", entity.IsControllerOrOwner);
    }
}
  1. Use a Bolt.GlobalEventListener to include the callback on any Entity that was attached to the Bolt system:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[BoltGlobalBehaviour("GameScene")]
public class NetworkCallbacks : Bolt.GlobalEventListener
{
    public override void EntityAttached(BoltEntity entity)
    {
        if (entity.StateIs<IState>())
        {
            var state = entity.GetState<IState>();

            state.OnGameOver += () =>
            {
                BoltLog.Warn("Is owner or controller? {0}", entity.IsControllerOrOwner);
            };
        }
    }
}