discord / gamesdk-and-dispatch

Public issue tracker for the Discord Game SDK and Dispatch
22 stars 7 forks source link

I get CallbackOnCollectedDelegate exceptions when updating Activity because of Garbage Collector #102

Open BenjaminBjoernRommel opened 4 years ago

BenjaminBjoernRommel commented 4 years ago

I wanted to use the Discord API in my latest video game. However, I get crashes very often when updating the Activity. I use my own custom game engine written in C#, i.e. I use the C# code provided for non-Unity games.

I get the CallbackOnCollectedDelegate exception often after the Garbage Collector is used. I have declared all event handlers as class variables, i.e. the callbacks I declared should not be touched by the Garbage Collector! I also update the Activity from the main game loop, i.e. no other threads are involved.

I just need to call GC.Collect right after I called SetActivity and it will crash in Discord.RunCallbacks calling Methods.RunCallbacks.

It is not useable right now for me, if the Discord API cannot handle Garbage Collectors.

Declaring the callback in the constructor

            _updateActivityHandler = new UpdateActivityHandler((result) =>
            {
                if (result != Result.Ok)
                    _logger.WriteError("Discord acitivity could not be updated");
            });

Setting the activity that is later set (see below)

        public void SetActivity(string status)
        {
            if (_discord == null || _activityManager == null || !IsInitialized)
                return;

            lock (_activitiesLock)
            {
                _activities.Add(status);
            }
        }

Update function that is called in my game loop; it updates activities, if necessary

        public void Update()
        {
            if (_discord == null)
                return;

            lock (_activitiesLock)
            {
                if (_activities.Any())
                {
                    var activity = new Activity
                    {
                        State = _activities.First()
                    };

                    _activityManager.UpdateActivity(activity, _updateActivityHandler);

                    _activities.Clear();
                }
            }

            _discord.RunCallbacks();
        }
Fulgen301 commented 4 years ago

Can confirm this.

Referencing the internal callback fixed the crash with UpdateActivity for me as a quick developing hack, but still crashes when searching for lobbies. Also, as this "hack" requires editing the SDK sources, it is, to my knowledge, in violation of the ToS, so not an option.

        FFIMethods.UpdateActivityCallback updateActivityCallback;

        public void UpdateActivity(Activity activity, UpdateActivityHandler callback)
        {
            GCHandle wrapped = GCHandle.Alloc(callback);
            Methods.UpdateActivity(MethodsPtr, ref activity, GCHandle.ToIntPtr(wrapped), updateActivityCallback = UpdateActivityCallbackImpl);
        }

(Core.cs)

sylveon commented 4 years ago

From a quick read of the developer terms of service, it's not a violation.

Vercidium commented 3 years ago

Another user is facing this issue, there is a working hack to stop the delegate from being collected by GC here: https://github.com/discord/gamesdk-and-dispatch/issues/36#issuecomment-846799714