FunkFrog / ShareSuite

Risk of Rain 2 Item, Money, & Equipment sharing mod build upon BepInEx
https://thunderstore.io/package/FunkFrog-and-Sipondo/ShareSuite/
GNU General Public License v3.0
39 stars 27 forks source link

Add event for other mods to mark pickups as unshareable #202

Closed ThinkInvis closed 1 year ago

ThinkInvis commented 1 year ago

Purpose of change:

Allows any inventory drop mod, as well as any other similar case, to prevent a specific pickup object from being shared on pickup. External code can subscribe to the event, and return true if the pickup is OK to share or false otherwise. If any subscriber returns false, the pickup will be unshareable.

Necessary to address https://github.com/ThinkInvis/RoR2-Yeet/issues/15.

Example implementation:

In TILER2:

public static class Compat_ShareSuite {
    [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
    public static void AddPickupEventHandler(Func<GenericPickupController, CharacterBody, bool> f) {
        ShareSuite.ItemSharingHooks.AdditionalPickupValidityChecks += f;
    }

    [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
    public static void RemovePickupEventHandler(Func<GenericPickupController, CharacterBody, bool> f) {
        ShareSuite.ItemSharingHooks.AdditionalPickupValidityChecks -= f;
    }

    private static bool? _enabled;
    public static bool enabled {
        get {
            if(_enabled == null) _enabled = BepInEx.Bootstrap.Chainloader.PluginInfos.ContainsKey("com.funkfrog_sipondo.sharesuite");
            return (bool)_enabled;
        }
    }
}

In Yeet, during plugin Awake:

if(Compat_ShareSuite.enabled) {
    Compat_ShareSuite.AddPickupEventHandler((pickup, picker) => {
        return !pickup.TryGetComponent<YeetData>(out _); //component added to pickup objects created by dropping from player inventory
    });
}

Notes:

A custom EventArgs class was not used because it would be difficult to handle as a soft dependency. It would make easily unsubscribing from the event impossible, as any reference to the subscribed function might include a missing type (the EventArgs class). This is what necessitated the manual multicast handling (iterating event.GetInvocationList(), instead of the usual single call to event?.Invoke()).