Remove duplicated directory
This commit is contained in:
parent
66453fdda3
commit
0861e34492
Binary file not shown.
Before Width: | Height: | Size: 9.6 KiB |
Binary file not shown.
Before Width: | Height: | Size: 9.6 KiB |
@ -1,150 +0,0 @@
|
|||||||
#include "DicordRpcPrivatePCH"
|
|
||||||
#include "DiscordRpcBlueprint.h"
|
|
||||||
#include "discord-rpc.h"
|
|
||||||
|
|
||||||
DEFINE_LOG_CATEGORY(Discord)
|
|
||||||
|
|
||||||
static UDiscordRpc* self = nullptr;
|
|
||||||
|
|
||||||
static void ReadyHandler()
|
|
||||||
{
|
|
||||||
UE_LOG(Discord, Log, TEXT("Discord connected"));
|
|
||||||
if (self) {
|
|
||||||
self->IsConnected = true;
|
|
||||||
self->OnConnected.Broadcast();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DisconnectHandler(int errorCode, const char* message)
|
|
||||||
{
|
|
||||||
auto msg = FString(message);
|
|
||||||
UE_LOG(Discord, Log, TEXT("Discord disconnected (%d): %s"), errorCode, *msg);
|
|
||||||
if (self) {
|
|
||||||
self->IsConnected = false;
|
|
||||||
self->OnDisconnected.Broadcast(errorCode, msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ErroredHandler(int errorCode, const char* message)
|
|
||||||
{
|
|
||||||
auto msg = FString(message);
|
|
||||||
UE_LOG(Discord, Log, TEXT("Discord error (%d): %s"), errorCode, *msg);
|
|
||||||
if (self) {
|
|
||||||
self->OnErrored.Broadcast(errorCode, msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void JoinGameHandler(const char* joinSecret)
|
|
||||||
{
|
|
||||||
auto secret = FString(joinSecret);
|
|
||||||
UE_LOG(Discord, Log, TEXT("Discord join %s"), *secret);
|
|
||||||
if (self) {
|
|
||||||
self->OnJoin.Broadcast(secret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SpectateGameHandler(const char* spectateSecret)
|
|
||||||
{
|
|
||||||
auto secret = FString(spectateSecret);
|
|
||||||
UE_LOG(Discord, Log, TEXT("Discord spectate %s"), *secret);
|
|
||||||
if (self) {
|
|
||||||
self->OnSpectate.Broadcast(secret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void JoinRequestHandler(const DiscordJoinRequest* request)
|
|
||||||
{
|
|
||||||
FDiscordJoinRequestData jr;
|
|
||||||
jr.userId = ANSI_TO_TCHAR(request->userId);
|
|
||||||
jr.username = ANSI_TO_TCHAR(request->username);
|
|
||||||
jr.discriminator = ANSI_TO_TCHAR(request->discriminator);
|
|
||||||
jr.avatar = ANSI_TO_TCHAR(request->avatar);
|
|
||||||
UE_LOG(Discord, Log, TEXT("Discord join request from %s#%s"), *jr.username, *jr.discriminator);
|
|
||||||
if (self) {
|
|
||||||
self->OnJoinRequest.Broadcast(jr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDiscordRpc::Initialize(const FString& applicationId,
|
|
||||||
bool autoRegister,
|
|
||||||
const FString& optionalSteamId)
|
|
||||||
{
|
|
||||||
self = this;
|
|
||||||
IsConnected = false;
|
|
||||||
DiscordEventHandlers handlers{};
|
|
||||||
handlers.ready = ReadyHandler;
|
|
||||||
handlers.disconnected = DisconnectHandler;
|
|
||||||
handlers.errored = ErroredHandler;
|
|
||||||
if (OnJoin.IsBound()) {
|
|
||||||
handlers.joinGame = JoinGameHandler;
|
|
||||||
}
|
|
||||||
if (OnSpectate.IsBound()) {
|
|
||||||
handlers.spectateGame = SpectateGameHandler;
|
|
||||||
}
|
|
||||||
if (OnJoinRequest.IsBound()) {
|
|
||||||
handlers.joinRequest = JoinRequestHandler;
|
|
||||||
}
|
|
||||||
auto appId = StringCast<ANSICHAR>(*applicationId);
|
|
||||||
auto steamId = StringCast<ANSICHAR>(*optionalSteamId);
|
|
||||||
Discord_Initialize(
|
|
||||||
(const char*)appId.Get(), &handlers, autoRegister, (const char*)steamId.Get());
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDiscordRpc::Shutdown()
|
|
||||||
{
|
|
||||||
Discord_Shutdown();
|
|
||||||
self = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDiscordRpc::RunCallbacks()
|
|
||||||
{
|
|
||||||
Discord_RunCallbacks();
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDiscordRpc::UpdatePresence()
|
|
||||||
{
|
|
||||||
DiscordRichPresence rp{};
|
|
||||||
|
|
||||||
auto state = StringCast<ANSICHAR>(*RichPresence.state);
|
|
||||||
rp.state = state.Get();
|
|
||||||
|
|
||||||
auto details = StringCast<ANSICHAR>(*RichPresence.details);
|
|
||||||
rp.details = details.Get();
|
|
||||||
|
|
||||||
auto largeImageKey = StringCast<ANSICHAR>(*RichPresence.largeImageKey);
|
|
||||||
rp.largeImageKey = largeImageKey.Get();
|
|
||||||
|
|
||||||
auto largeImageText = StringCast<ANSICHAR>(*RichPresence.largeImageText);
|
|
||||||
rp.largeImageText = largeImageText.Get();
|
|
||||||
|
|
||||||
auto smallImageKey = StringCast<ANSICHAR>(*RichPresence.smallImageKey);
|
|
||||||
rp.smallImageKey = smallImageKey.Get();
|
|
||||||
|
|
||||||
auto smallImageText = StringCast<ANSICHAR>(*RichPresence.smallImageText);
|
|
||||||
rp.smallImageText = smallImageText.Get();
|
|
||||||
|
|
||||||
auto partyId = StringCast<ANSICHAR>(*RichPresence.partyId);
|
|
||||||
rp.partyId = partyId.Get();
|
|
||||||
|
|
||||||
auto matchSecret = StringCast<ANSICHAR>(*RichPresence.matchSecret);
|
|
||||||
rp.matchSecret = matchSecret.Get();
|
|
||||||
|
|
||||||
auto joinSecret = StringCast<ANSICHAR>(*RichPresence.joinSecret);
|
|
||||||
rp.joinSecret = joinSecret.Get();
|
|
||||||
|
|
||||||
auto spectateSecret = StringCast<ANSICHAR>(*RichPresence.spectateSecret);
|
|
||||||
rp.spectateSecret = spectateSecret.Get();
|
|
||||||
|
|
||||||
rp.startTimestamp = RichPresence.startTimestamp;
|
|
||||||
rp.endTimestamp = RichPresence.endTimestamp;
|
|
||||||
rp.partySize = RichPresence.partySize;
|
|
||||||
rp.partyMax = RichPresence.partyMax;
|
|
||||||
rp.instance = RichPresence.instance;
|
|
||||||
|
|
||||||
Discord_UpdatePresence(&rp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDiscordRpc::ClearPresence()
|
|
||||||
{
|
|
||||||
Discord_ClearPresence();
|
|
||||||
}
|
|
@ -1,71 +0,0 @@
|
|||||||
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
|
|
||||||
|
|
||||||
#include "DiscordRpcPrivatePCH.h"
|
|
||||||
#include "IPluginManager.h"
|
|
||||||
#include "ModuleManager.h"
|
|
||||||
|
|
||||||
#define LOCTEXT_NAMESPACE "FDiscordRpcModule"
|
|
||||||
|
|
||||||
void FDiscordRpcModule::StartupModule()
|
|
||||||
{
|
|
||||||
#if !PLATFORM_LINUX
|
|
||||||
#if defined(DISCORD_DYNAMIC_LIB)
|
|
||||||
// Get the base directory of this plugin
|
|
||||||
FString BaseDir = IPluginManager::Get().FindPlugin("DiscordRpc")->GetBaseDir();
|
|
||||||
const FString SDKDir = FPaths::Combine(*BaseDir, TEXT("ThirdParty"), TEXT("DiscordRpcLibrary"));
|
|
||||||
#if PLATFORM_WINDOWS
|
|
||||||
const FString LibName = TEXT("discord-rpc");
|
|
||||||
const FString LibDir = FPaths::Combine(*SDKDir, TEXT("Win64"));
|
|
||||||
if (!LoadDependency(LibDir, LibName, DiscordRpcLibraryHandle)) {
|
|
||||||
FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT(LOCTEXT_NAMESPACE, "Failed to load DiscordRpc plugin. Plug-in will not be functional."));
|
|
||||||
FreeDependency(DiscordRpcLibraryHandle);
|
|
||||||
}
|
|
||||||
#elif PLATFORM_MAC
|
|
||||||
const FString LibName = TEXT("discord-rpc");
|
|
||||||
const FString LibDir = FPaths::Combine(*SDKDir, TEXT("Mac"));
|
|
||||||
if (!LoadDependency(LibDir, LibName, DiscordRpcLibraryHandle)) {
|
|
||||||
FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT(LOCTEXT_NAMESPACE, "Failed to load DiscordRpc plugin. Plug-in will not be functional."));
|
|
||||||
FreeDependency(DiscordRpcLibraryHandle);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void FDiscordRpcModule::ShutdownModule()
|
|
||||||
{
|
|
||||||
// Free the dll handle
|
|
||||||
#if !PLATFORM_LINUX
|
|
||||||
#if defined(DISCORD_DYNAMIC_LIB)
|
|
||||||
FreeDependency(DiscordRpcLibraryHandle);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FDiscordAPIModule::LoadDependency(const FString& Dir, const FString& Name, void*& Handle)
|
|
||||||
{
|
|
||||||
FString Lib = Name + TEXT(".") + FPlatformProcess::GetModuleExtension();
|
|
||||||
FString Path = Dir.IsEmpty() ? *Lib : FPaths::Combine(*Dir, *Lib);
|
|
||||||
|
|
||||||
Handle = FPlatformProcess::GetDllHandle(*Path);
|
|
||||||
|
|
||||||
if (Handle == nullptr)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FDiscordAPIModule::FreeDependency(void*& Handle)
|
|
||||||
{
|
|
||||||
if (Handle != nullptr)
|
|
||||||
{
|
|
||||||
FPlatformProcess::FreeDllHandle(Handle);
|
|
||||||
Handle = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef LOCTEXT_NAMESPACE
|
|
||||||
|
|
||||||
IMPLEMENT_MODULE(FDiscordRpcModule, DiscordRpc)
|
|
@ -1,154 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "CoreMinimal.h"
|
|
||||||
#include "Engine.h"
|
|
||||||
#include "DiscordRpcBlueprint.generated.h"
|
|
||||||
|
|
||||||
// unreal's header tool hates clang-format
|
|
||||||
// clang-format off
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ask to join callback data
|
|
||||||
*/
|
|
||||||
USTRUCT(BlueprintType)
|
|
||||||
struct FDiscordJoinRequestData {
|
|
||||||
GENERATED_USTRUCT_BODY()
|
|
||||||
|
|
||||||
UPROPERTY(BlueprintReadOnly)
|
|
||||||
FString userId;
|
|
||||||
UPROPERTY(BlueprintReadOnly)
|
|
||||||
FString username;
|
|
||||||
UPROPERTY(BlueprintReadOnly)
|
|
||||||
FString discriminator;
|
|
||||||
UPROPERTY(BlueprintReadOnly)
|
|
||||||
FString avatar;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
DECLARE_LOG_CATEGORY_EXTERN(Discord, Log, All);
|
|
||||||
|
|
||||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FDiscordConnected);
|
|
||||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FDiscordDisconnected, int, errorCode, const FString&, errorMessage);
|
|
||||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FDiscordErrored, int, errorCode, const FString&, errorMessage);
|
|
||||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FDiscordJoin, const FString&, joinSecret);
|
|
||||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FDiscordSpectate, const FString&, spectateSecret);
|
|
||||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FDiscordJoinRequest, const FDiscordJoinRequestData&, joinRequest);
|
|
||||||
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rich presence data
|
|
||||||
*/
|
|
||||||
USTRUCT(BlueprintType)
|
|
||||||
struct FDiscordRichPresence {
|
|
||||||
GENERATED_USTRUCT_BODY()
|
|
||||||
|
|
||||||
UPROPERTY(BlueprintReadWrite)
|
|
||||||
FString state;
|
|
||||||
UPROPERTY(BlueprintReadWrite)
|
|
||||||
FString details;
|
|
||||||
// todo, timestamps are 64bit, does that even matter?
|
|
||||||
UPROPERTY(BlueprintReadWrite)
|
|
||||||
int startTimestamp;
|
|
||||||
UPROPERTY(BlueprintReadWrite)
|
|
||||||
int endTimestamp;
|
|
||||||
UPROPERTY(BlueprintReadWrite)
|
|
||||||
FString largeImageKey;
|
|
||||||
UPROPERTY(BlueprintReadWrite)
|
|
||||||
FString largeImageText;
|
|
||||||
UPROPERTY(BlueprintReadWrite)
|
|
||||||
FString smallImageKey;
|
|
||||||
UPROPERTY(BlueprintReadWrite)
|
|
||||||
FString smallImageText;
|
|
||||||
UPROPERTY(BlueprintReadWrite)
|
|
||||||
FString partyId;
|
|
||||||
UPROPERTY(BlueprintReadWrite)
|
|
||||||
int partySize;
|
|
||||||
UPROPERTY(BlueprintReadWrite)
|
|
||||||
int partyMax;
|
|
||||||
UPROPERTY(BlueprintReadWrite)
|
|
||||||
FString matchSecret;
|
|
||||||
UPROPERTY(BlueprintReadWrite)
|
|
||||||
FString joinSecret;
|
|
||||||
UPROPERTY(BlueprintReadWrite)
|
|
||||||
FString spectateSecret;
|
|
||||||
UPROPERTY(BlueprintReadWrite)
|
|
||||||
bool instance;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
UCLASS(BlueprintType, meta = (DisplayName = "Discord RPC"), Category = "Discord")
|
|
||||||
class DISCORDRPC_API UDiscordRpc : public UObject {
|
|
||||||
GENERATED_BODY()
|
|
||||||
|
|
||||||
public:
|
|
||||||
UFUNCTION(BlueprintCallable,
|
|
||||||
meta = (DisplayName = "Initialize connection", Keywords = "Discord rpc"),
|
|
||||||
Category = "Discord")
|
|
||||||
void Initialize(const FString& applicationId,
|
|
||||||
bool autoRegister,
|
|
||||||
const FString& optionalSteamId);
|
|
||||||
|
|
||||||
UFUNCTION(BlueprintCallable,
|
|
||||||
meta = (DisplayName = "Shut down connection", Keywords = "Discord rpc"),
|
|
||||||
Category = "Discord")
|
|
||||||
void Shutdown();
|
|
||||||
|
|
||||||
UFUNCTION(BlueprintCallable,
|
|
||||||
meta = (DisplayName = "Check for callbacks", Keywords = "Discord rpc"),
|
|
||||||
Category = "Discord")
|
|
||||||
void RunCallbacks();
|
|
||||||
|
|
||||||
UFUNCTION(BlueprintCallable,
|
|
||||||
meta = (DisplayName = "Send presence", Keywords = "Discord rpc"),
|
|
||||||
Category = "Discord")
|
|
||||||
void UpdatePresence();
|
|
||||||
|
|
||||||
UFUNCTION(BlueprintCallable,
|
|
||||||
meta = (DisplayName = "Clear presence", Keywords = "Discord rpc"),
|
|
||||||
Category = "Discord")
|
|
||||||
void ClearPresence();
|
|
||||||
|
|
||||||
UPROPERTY(BlueprintReadOnly,
|
|
||||||
meta = (DisplayName = "Is Discord connected", Keywords = "Discord rpc"),
|
|
||||||
Category = "Discord")
|
|
||||||
bool IsConnected;
|
|
||||||
|
|
||||||
UPROPERTY(BlueprintAssignable,
|
|
||||||
meta = (DisplayName = "On connection", Keywords = "Discord rpc"),
|
|
||||||
Category = "Discord")
|
|
||||||
FDiscordConnected OnConnected;
|
|
||||||
|
|
||||||
UPROPERTY(BlueprintAssignable,
|
|
||||||
meta = (DisplayName = "On disconnection", Keywords = "Discord rpc"),
|
|
||||||
Category = "Discord")
|
|
||||||
FDiscordDisconnected OnDisconnected;
|
|
||||||
|
|
||||||
UPROPERTY(BlueprintAssignable,
|
|
||||||
meta = (DisplayName = "On error message", Keywords = "Discord rpc"),
|
|
||||||
Category = "Discord")
|
|
||||||
FDiscordErrored OnErrored;
|
|
||||||
|
|
||||||
UPROPERTY(BlueprintAssignable,
|
|
||||||
meta = (DisplayName = "When Discord user presses join", Keywords = "Discord rpc"),
|
|
||||||
Category = "Discord")
|
|
||||||
FDiscordJoin OnJoin;
|
|
||||||
|
|
||||||
UPROPERTY(BlueprintAssignable,
|
|
||||||
meta = (DisplayName = "When Discord user presses spectate", Keywords = "Discord rpc"),
|
|
||||||
Category = "Discord")
|
|
||||||
FDiscordSpectate OnSpectate;
|
|
||||||
|
|
||||||
UPROPERTY(BlueprintAssignable,
|
|
||||||
meta = (DisplayName = "When Discord another user sends a join request",
|
|
||||||
Keywords = "Discord rpc"),
|
|
||||||
Category = "Discord")
|
|
||||||
FDiscordJoinRequest OnJoinRequest;
|
|
||||||
|
|
||||||
UPROPERTY(BlueprintReadWrite,
|
|
||||||
meta = (DisplayName = "Rich presence info", Keywords = "Discord rpc"),
|
|
||||||
Category = "Discord")
|
|
||||||
FDiscordRichPresence RichPresence;
|
|
||||||
};
|
|
@ -1,20 +0,0 @@
|
|||||||
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "ModuleManager.h"
|
|
||||||
|
|
||||||
class FDiscordRpcModule : public IModuleInterface {
|
|
||||||
public:
|
|
||||||
/** IModuleInterface implementation */
|
|
||||||
virtual void StartupModule() override;
|
|
||||||
virtual void ShutdownModule() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
/** Handle to the test dll we will load */
|
|
||||||
void* DiscordLibraryHandle;
|
|
||||||
|
|
||||||
/** StartupModule is covered with defines, these functions are the place to put breakpoints */
|
|
||||||
static bool LoadDependency(const FString& Dir, const FString& Name, void*& Handle);
|
|
||||||
static void FreeDependency(void*& Handle);
|
|
||||||
};
|
|
@ -1,51 +0,0 @@
|
|||||||
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
|
|
||||||
|
|
||||||
using UnrealBuildTool;
|
|
||||||
|
|
||||||
public class discordrpc : ModuleRules
|
|
||||||
{
|
|
||||||
public discordrpc(ReadOnlyTargetRules Target) : base(Target)
|
|
||||||
{
|
|
||||||
Definitions.Add("DISCORD_DYNAMIC_LIB=1");
|
|
||||||
|
|
||||||
PublicIncludePaths.AddRange(
|
|
||||||
new string[] {
|
|
||||||
"DiscordRpc/Public"
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
PrivateIncludePaths.AddRange(
|
|
||||||
new string[] {
|
|
||||||
"DiscordRpc/Private"
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
PublicDependencyModuleNames.AddRange(
|
|
||||||
new string[]
|
|
||||||
{
|
|
||||||
"Core",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
PrivateDependencyModuleNames.AddRange(
|
|
||||||
new string[]
|
|
||||||
{
|
|
||||||
"CoreUObject",
|
|
||||||
"Engine",
|
|
||||||
"Slate",
|
|
||||||
"SlateCore",
|
|
||||||
"Projects"
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
DynamicallyLoadedModuleNames.AddRange(
|
|
||||||
new string[]
|
|
||||||
{
|
|
||||||
// ... add any modules that your module loads dynamically here ...
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
string BaseDirectory = Path.GetFullPath(Path.Combine(ModuleDirectory, "..", "..", "ThirdParty", "DiscordRpcLibrary"));
|
|
||||||
PublicIncludePaths.Add(Path.Combine(BaseDirectory, "Include"));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"FileVersion": 3,
|
|
||||||
"Version": 1,
|
|
||||||
"VersionName": "1.0",
|
|
||||||
"FriendlyName": "Discord RPC",
|
|
||||||
"Description": "Wrap the Discord RPC library.",
|
|
||||||
"Category": "Messaging",
|
|
||||||
"CreatedBy": "Chris Marsh <chris@discordapp.com>",
|
|
||||||
"CreatedByURL": "https://discordapp.com/",
|
|
||||||
"DocsURL": "",
|
|
||||||
"MarketplaceURL": "",
|
|
||||||
"SupportURL": "",
|
|
||||||
"CanContainContent": true,
|
|
||||||
"IsBetaVersion": true,
|
|
||||||
"Installed": false,
|
|
||||||
"Modules": [
|
|
||||||
{
|
|
||||||
"Name": "DiscordRpc",
|
|
||||||
"Type": "Runtime",
|
|
||||||
"LoadingPhase": "PreDefault"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user