Skip to content
UCIK Docs
Esc
↑↓navigate↵open⌘Jpreview
On this page

Handle reports and sanctions

Submit player reports and respond to moderation outcomes.

Keep the reported player’s full handle. Reports and sanctions go to the provider that owns that handle; support is not shared across every platform.

Report a player

Report a player
Preparing your graph…

Loading the interactive viewer.

Game module dependencies: UCIKCore, BetideCore.

#include "Engine/GameInstance.h"
#include "Platform/UCIKPlatformSubsystem.h"
#include "UCIKCore.h"

void ReportPlayer(UGameInstance &GameInstance, const FUCIK_PlayerHandle &Player,
                  const FString &Reason, const FString &MatchId)
{
    auto *Service = GameInstance.GetSubsystem<UUCIKPlatformSubsystem>();
    if (!Service)
        return;

    FUCIK_PlayerReport Report;
    Report.Player = Player;
    Report.Category = EUCIK_ReportCategory::Cheating;
    Report.Message = Reason;
    Report.Context.Add(TEXT("MatchId"), MatchId);
    Service->SendPlayerReport(
        Report,
        FBetideCallback<bool>::CreateWeakLambda(&GameInstance, [](const TBetideResult<bool> &Result) {
            if (!Result.bOk)
            {
                UE_LOG(LogUCIK, Warning, TEXT("%s"), *Result.Error.GetLogString());
                return;
            }
            UE_LOG(LogUCIK, Log, TEXT("Report submitted: %d"), Result.GetValue());
        }));
}

Attach useful match details in Context. A submitted report is not a ban. Query sanctions separately and let your server decide how each action affects access.

Check active sanctions

List player sanctions
List player sanctions
Preparing your graph…

Loading the interactive viewer.

Check active sanctions
Check active sanctions
Preparing your graph…

Loading the interactive viewer.

Game module dependencies: UCIKCore, BetideCore.

#include "Engine/GameInstance.h"
#include "Platform/UCIKPlatformSubsystem.h"
#include "UCIKCore.h"

void CheckPlayerSanctions(UGameInstance &GameInstance, const FUCIK_PlayerHandle &Player)
{
    auto *Service = GameInstance.GetSubsystem<UUCIKPlatformSubsystem>();
    if (!Service)
        return;

    Service->IsPlayerSanctioned(
        Player,
        FBetideCallback<bool>::CreateWeakLambda(&GameInstance, [](const TBetideResult<bool> &Result) {
            if (!Result.bOk)
            {
                UE_LOG(LogUCIK, Warning, TEXT("%s"), *Result.Error.GetLogString());
                return;
            }
            UE_LOG(LogUCIK, Log, TEXT("Has active sanction: %d"), Result.GetValue());
        }));
}
void ListPlayerSanctions(UGameInstance &GameInstance, const FUCIK_PlayerHandle &Player)
{
    auto *Service = GameInstance.GetSubsystem<UUCIKPlatformSubsystem>();
    if (!Service)
        return;
    Service->QuerySanctions(
        Player, FBetideCallback<TArray<FUCIK_Sanction>>::CreateWeakLambda(
                    &GameInstance, [](const TBetideResult<TArray<FUCIK_Sanction>> &Result) {
                        if (!Result.bOk)
                        {
                            UE_LOG(LogUCIK, Warning, TEXT("%s"), *Result.Error.GetLogString());
                            return;
                        }
                        for (const FUCIK_Sanction &Sanction : Result.GetValue())
                            UE_LOG(LogUCIK, Log, TEXT("%s: %s"), *Sanction.Action,
                                   *Sanction.ReferenceId);
                    }));
}

Server kicks require the player’s handle to be reported through UUCIKPlayerLinkComponent on their PlayerController. Call the kick from trusted server logic; the host cannot kick itself.

Block, mute, or remove

Block a player
Block a player
Preparing your graph…

Loading the interactive viewer.

Unblock a player
Unblock a player
Preparing your graph…

Loading the interactive viewer.

List blocked players
List blocked players
Preparing your graph…

Loading the interactive viewer.

Save a local mute
Save a local mute
Preparing your graph…

Loading the interactive viewer.

Remove a player from the server
Remove a player from the server
Preparing your graph…

Loading the interactive viewer.

Game module dependencies: UCIKCore, BetideCore.

Block a player
#include "Engine/GameInstance.h"
#include "Social/UCIKSocialSubsystem.h"
#include "UCIKCore.h"

void BlockPlayer(UGameInstance &GameInstance, const FUCIK_PlayerHandle &Player)
{
    auto *Service = GameInstance.GetSubsystem<UUCIKSocialSubsystem>();
    if (!Service)
        return;
    Service->BlockPlayer(
        Player,
        FBetideCallback<bool>::CreateWeakLambda(&GameInstance, [](const TBetideResult<bool> &Result) {
            if (!Result.bOk)
            {
                UE_LOG(LogUCIK, Warning, TEXT("%s"), *Result.Error.GetLogString());
                return;
            }
            UE_LOG(LogUCIK, Log, TEXT("Block completed: %d"), Result.GetValue());
        }));
}
Unblock a player
#include "Engine/GameInstance.h"
#include "Social/UCIKSocialSubsystem.h"
#include "UCIKCore.h"

void UnblockPlayer(UGameInstance &GameInstance, const FUCIK_PlayerHandle &Player)
{
    auto *Service = GameInstance.GetSubsystem<UUCIKSocialSubsystem>();
    if (!Service)
        return;
    Service->UnblockPlayer(
        Player,
        FBetideCallback<bool>::CreateWeakLambda(&GameInstance, [](const TBetideResult<bool> &Result) {
            if (!Result.bOk)
            {
                UE_LOG(LogUCIK, Warning, TEXT("%s"), *Result.Error.GetLogString());
                return;
            }
            UE_LOG(LogUCIK, Log, TEXT("Unblock completed: %d"), Result.GetValue());
        }));
}
List blocked players
#include "Engine/GameInstance.h"
#include "Social/UCIKSocialSubsystem.h"
#include "UCIKCore.h"

void ListBlockedPlayers(UGameInstance &GameInstance)
{
    auto *Service = GameInstance.GetSubsystem<UUCIKSocialSubsystem>();
    if (!Service)
        return;
    Service->GetBlockedPlayers(FBetideCallback<TArray<FUCIK_PlayerHandle>>::CreateWeakLambda(
        &GameInstance, [](const TBetideResult<TArray<FUCIK_PlayerHandle>> &Result) {
            if (!Result.bOk)
            {
                UE_LOG(LogUCIK, Warning, TEXT("%s"), *Result.Error.GetLogString());
                return;
            }
            for (const FUCIK_PlayerHandle &Player : Result.GetValue())
                UE_LOG(LogUCIK, Log, TEXT("%s"), *Player.ToString());
        }));
}
Save a local mute
#include "Engine/GameInstance.h"
#include "Social/UCIKSocialSubsystem.h"
#include "UCIKCore.h"

void SetPlayerMute(UGameInstance &GameInstance, const FUCIK_PlayerHandle &Player, bool bMuted)
{
    if (auto *Service = GameInstance.GetSubsystem<UUCIKSocialSubsystem>())
    {
        Service->SetPlayerMuted(Player, bMuted);
        UE_LOG(LogUCIK, Log, TEXT("Muted: %d"), Service->IsPlayerMuted(Player));
    }
}
Remove a player from the server
#include "Engine/GameInstance.h"
#include "Platform/UCIKPlatformSubsystem.h"
#include "UCIKCore.h"

void RemovePlayerFromServer(UGameInstance &GameInstance, const FUCIK_PlayerHandle &Player,
                            const FText &Reason)
{
    if (auto *Service = GameInstance.GetSubsystem<UUCIKPlatformSubsystem>())
    {
        const FBetideError Error = Service->KickPlayerFromServer(Player, Reason);
        if (Error.IsError())
            UE_LOG(LogUCIK, Warning, TEXT("%s"), *Error.GetLogString());
        else
            UE_LOG(LogUCIK, Log, TEXT("Player removed"));
    }
}

Blocking, local voice muting, lobby removal, and server kicks are separate actions. Persistent mutes are stored on this machine. A sanction with no expiry is permanent; a failed query must not be treated as a clean record.

Was this page helpful?