https://metaplay.io logo
Triggering an Offer
# questions-and-feedback
d
Hi How can I implement an Offer/Promotion to activate on a trigger on a specific user action in addition to other segment conditions and limitations?
n
Hi, if you already have some PlayerAction that you'd like to trigger it, you could do the following:
Copy code
MetaOfferGroupId offerGroupId = <desired offer group id>;
MetaOfferGroupInfoBase offerGroupInfo = player.GameConfig.OfferGroups.GetValueOrDefault(offerGroupId);
player.MetaOfferGroups.TryStartActivation(offerGroupInfo, player);
If you don't want it to check the segments and other conditions in this trigger, you can use
ForceStartActivation
instead of
TryStartActivation
. (edit: fixed the code snippet a bit)
d
that will just test if the offer conditions for activation are met - yes - or activate offer disregarding the conditions. so... I want the conditions to be checked - but. I do not want the offer to activate on session start
only on the trigger - if other conditions are met
so I want the specific offer or offer group to skip any activation unless I trigger it.
n
Alright, i see. The SDK doesn't readily have this functionality but it could be achievable in a custom way. At least for offer groups, one way i can think of is defining an extra check for activation in the
PlayerMetaOfferGroupsModelBase<...>
subclass,
CustomCanStartActivation
method, so that the specific offer cannot be normally activated, but can be activated via an explicit trigger. Along these lines:
Copy code
public class MyPlayerOfferGroupsModel : PlayerMetaOfferGroupsModelBase<MyOfferGroupInfo>
{
    ...

    MetaOfferGroupId _currentExplicitlyTriggeredId = null;

    public void TriggerActivationExplicitly(MyOfferGroupInfo info, IPlayerModelBase player)
    {
        _currentExplicitlyTriggeredId = info.GroupId;
        TryStartActivation(info, player);
        _currentExplicitlyTriggeredId = null;
    }

    protected override bool CustomCanStartActivation(MyOfferGroupInfo info, IPlayerModelBase player)
    {
        // In this example, RequireExplicitTrigger is a custom config property,
        // but it could be any other condition as desired.
        if (info.RequireExplicitTrigger)
        {
            if (_currentExplicitlyTriggeredId != info.GroupId)
                return false;
        }

        return base.CustomCanStartActivation(info, player);
    }
}
Having temporary state (_currentExplicitlyTriggeredId) like this is a bit unusual but in this case it's the easiest way to smuggle this info to the CustomCanStartActivation method (as the SDK doesn't currently have extra parameters for the activation call). This approach needs a custom subclass of PlayerMetaOfferGroupsModelBase as the CustomCanStartActivation exists there. Also, in this example there's a custom MyOfferGroupInfo config data type for the RequireExplicitTrigger property; that's assuming you want to have it controllable from the game configs. https://docs.metaplay.io/feature-cookbooks/in-game-offers/getting-started-with-in-game-offers.html#extending-the-config-data describes how to add a custom config data type. If there's a need to control also individual offers within offer groups, rather than just the whole offer groups, i'm not sure a similar approach will work as is without some SDK modifications, because currently there's no equivalent of CustomCanStartActivation for individual offers.
Alternatively, there's an
AdditionalConditions
list configurable for both offers and groups, that might be possible to arrange in a way that the conditions are fulfilled only on specific triggers. This isn't documented but it's possible to populate that list from config data when defining custom config data types for offers and offer groups.
d
Yeah I got to doing just that but am making it on the level of a GroupModel rather then GroupsModel - so it is per group. and then based on a custom flag from config an offer can be created with Manual activation enabled or not. - will share my code when I get it workign
thank you for your help 🙂
n
One regrettable gotcha there is that a GroupModel is not created until the group becomes active for the player for the first time (unless you create it explicitly with EnsureHasState(...) in the GroupsModel). So using the individual group's CustomCanStartActivation won't apply for the very first activation... This is why i used the GroupsModel in the above example
d
so will this:
Copy code
var state = player.MetaOfferGroups.TryGetState(OfferGroupId);
return null for an offer that was never activated for a given player?
n
Yes
d
that is indeed an unfortunate gotcha
I do not like this state member in GroupsModel I wander if it can be passed in the info instead...
sth like
Copy code
[MetaMember(1)] public bool IsManual;
        
        [IgnoreDataMember] public bool ManualActivation = false;
then action after retrieving group info can set it before calling to TryActivate and set it back after... and in CanActivate we check the two values of the info... no state in the groups model...
still dont like this bit much:
Copy code
csharp
                try
                {
                    groupInfo.ManualActivation = true;
                    player.MetaOfferGroups.TryStartActivation(groupInfo, player);
                }
                finally
                {
                    groupInfo.ManualActivation = false;
                }
n
Generally, config data (like groupInfo here) should not be mutated, because on the server, multiple player actors can share the same game config instance. (This sharing is done to reduce memory usage compared to each actor loading its own copy of the game config.) So if one player actor mutates game config data, the mutation can affect other players as well and cause strange bugs.
d
ah so it should be thread safe pretymuch... so... keeping state in the groups model or creating copy of the info passed to the startActivation...