Unreal SDK
Build Web3 games with Blueprint and C++ - no blockchain knowledge required.
The Unreal SDK is currently under development and has not been released yet. The Vidya SDK plugin is not available on the Unreal Marketplace at this time. This documentation serves as a specification and preview of the upcoming SDK. Stay tuned for the official release!
Installation
- Download the latest Vidya SDK plugin from the Unreal Marketplace
- Install the plugin to your project
- Enable the Vidya SDK plugin in Edit > Plugins
Getting Started
Setup & Authentication (Blueprint)
// In your GameMode or PlayerController
UCLASS()
class AMyGameMode : public AGameModeBase
{
GENERATED_BODY()
private:
UPROPERTY()
UVidyaSDK* Vidya;
UPROPERTY()
UPlayer* Player;
protected:
virtual void BeginPlay() override;
UFUNCTION()
void OnLoginComplete(const FSession& Session);
};
void AMyGameMode::BeginPlay()
{
Super::BeginPlay();
// Initialize with your project ID
FVidyaConfig Config;
Config.ProjectId = TEXT("your-project-id"); // Get from dashboard.vidya.game
Config.Environment = EVidyaEnvironment::Production; // Production | Testnet | Local
Vidya = UVidyaSDK::Create(Config);
// Authenticate player (creates a session)
FLoginOptions LoginOptions;
LoginOptions.Provider = EAuthProvider::Google; // Google | Discord | Email | Apple
Vidya->Auth->Login(LoginOptions,
FOnLoginComplete::CreateUObject(this, &AMyGameMode::OnLoginComplete));
}
void AMyGameMode::OnLoginComplete(const FSession& Session)
{
// Get the authenticated player object from the session
Player = UPlayer::FromSession(Session);
// Now use the player object throughout your game
Vidya->Inventory->GetItems(Player,
FOnGetItemsComplete::CreateLambda([](const TArray<UItem*>& Items)
{
UE_LOG(LogVidya, Log, TEXT("Loaded %d items"), Items.Num());
}));
}
Core Configuration
FVidyaConfig Config;
Config.ProjectId = TEXT("your-project-id"); // Required: Your Vidya project ID
Config.Environment = EVidyaEnvironment::Production; // Required: Production | Testnet | Local
// Optional: Advanced configuration
Config.Chain = TEXT("polygon"); // Default: "polygon"
Config.SponsorGas = true; // Default: true - Users don't pay gas
// Optional: Custom contract addresses (rarely needed)
Config.Contracts.Inventory = TEXT("0x...");
Config.Contracts.Marketplace = TEXT("0x...");
Config.Contracts.Fabricator = TEXT("0x...");
UVidyaSDK* Vidya = UVidyaSDK::Create(Config);
The Player Object
The Vidya SDK uses a Player object to represent users throughout the system. This provides type safety and clear permission management.
Creating Player Objects
There are only two ways to create a Player object:
1. Authenticated Player (Full Access)
// After authentication, create player from session
UPlayer* Player = UPlayer::FromSession(Session);
// This player can read and write
bool bCanWrite = Player->CanWrite(); // true
2. Read-Only Player (View Only)
// Create a read-only player from a wallet address
UPlayer* ReadOnlyPlayer = UPlayer::FromWallet(TEXT("0x742d35Cc6634C0532925a3b844Bc9e7595f5b123"));
// This player can only read data
bool bCanWrite = ReadOnlyPlayer->CanWrite(); // false
bool bIsReadOnly = ReadOnlyPlayer->IsReadOnly(); // true
Finding Players
When you need to interact with other players, use the lookup methods:
// Find player by username
Vidya->Player->FindByUsername(TEXT("CoolGamer123"),
FOnPlayerFound::CreateLambda([](UPlayer* OtherPlayer)
{
if (OtherPlayer)
{
UE_LOG(LogVidya, Log, TEXT("Found player: %s"), *OtherPlayer->GetPlayerId());
}
}));
// Find player by wallet address
Vidya->Player->FindByWallet(TEXT("0x742d35Cc6634C0532925a3b844Bc9e7595f5b123"),
FOnPlayerFound::CreateLambda([](UPlayer* WalletPlayer) { /* ... */ }));
// Find player by ENS name
Vidya->Player->FindByEns(TEXT("coolplayer.eth"),
FOnPlayerFound::CreateLambda([](UPlayer* EnsPlayer) { /* ... */ }));
// Find multiple players at once
FFindMultipleOptions Options;
Options.Usernames = {TEXT("Player1"), TEXT("Player2")};
Options.Wallets = {TEXT("0x123..."), TEXT("0x456...")};
Vidya->Player->FindMultiple(Options,
FOnPlayersFound::CreateLambda([](const TArray<UPlayer*>& Players) { /* ... */ }));
Authentication
Login Methods
// Social login (recommended)
FLoginOptions LoginOptions;
LoginOptions.Provider = EAuthProvider::Google; // Google | Discord | Email | Apple
Vidya->Auth->Login(LoginOptions,
FOnLoginComplete::CreateLambda([this](const FSession& Session)
{
Player = UPlayer::FromSession(Session);
}));
// Email/password authentication
FLoginOptions EmailOptions;
EmailOptions.Provider = EAuthProvider::Email;
EmailOptions.Email = TEXT("player@example.com");
EmailOptions.Password = TEXT("secure-password");
Vidya->Auth->Login(EmailOptions, /* callback */);
// Guest mode (instant play)
Vidya->Auth->LoginAsGuest(
FOnLoginComplete::CreateLambda([this](const FSession& Session)
{
Player = UPlayer::FromSession(Session);
}));
Session Management
// Check authentication status
if (Vidya->Auth->IsAuthenticated())
{
FSession Session = Vidya->Auth->GetSession();
UPlayer* Player = UPlayer::FromSession(Session);
Vidya->Auth->GetProfile(
FOnGetProfile::CreateLambda([](const FPlayerProfile& Profile)
{
UE_LOG(LogVidya, Log, TEXT("Welcome back, %s!"), *Profile.Username);
}));
}
// Listen to auth events
Vidya->Auth->OnLogin.AddLambda([this](const FSession& Session)
{
UPlayer* Player = UPlayer::FromSession(Session);
UE_LOG(LogVidya, Log, TEXT("Player logged in: %s"), *Player->GetPlayerId());
});
Vidya->Auth->OnLogout.AddLambda([]()
{
UE_LOG(LogVidya, Log, TEXT("Player logged out"));
});
// Logout
Vidya->Auth->Logout();
Core Systems
Inventory System
All inventory operations use Player objects:
// Get current player's inventory
FSession Session = Vidya->Auth->GetSession();
UPlayer* Player = UPlayer::FromSession(Session);
Vidya->Inventory->GetItems(Player,
FOnGetItemsComplete::CreateLambda([](const TArray<UItem*>& Items)
{
for (UItem* Item : Items)
{
UE_LOG(LogVidya, Log, TEXT("Item: %s x%d"), *Item->GetName(), Item->GetQuantity());
}
}));
// Get another player's inventory (read-only)
Vidya->Player->FindByUsername(TEXT("FriendName"),
FOnPlayerFound::CreateLambda([this](UPlayer* OtherPlayer)
{
if (OtherPlayer)
{
Vidya->Inventory->GetItems(OtherPlayer, /* callback */);
}
}));
// Get a specific item by ID
Vidya->Inventory->GetItem(Player, TEXT("sword-001"),
FOnGetItemComplete::CreateLambda([](UItem* Sword)
{
if (Sword)
{
UE_LOG(LogVidya, Log, TEXT("Found sword!"));
}
}));
// Get a specific item by predicate
auto Predicate = [](UItem* Item) -> bool
{
return Item->GetName() == TEXT("Legendary Sword") && !Item->IsEquipped();
};
Vidya->Inventory->GetItem(Player, Predicate,
FOnGetItemComplete::CreateLambda([](UItem* LegendaryWeapon) { /* ... */ }));
// Transfer an item using the item's method
Vidya->Player->FindByWallet(TEXT("0x456..."),
FOnPlayerFound::CreateLambda([this](UPlayer* Recipient)
{
if (Recipient && MySword)
{
MySword->Transfer(Recipient, 1);
}
}));
// Equipment management using item methods
if (Weapon)
{
Weapon->Equip(FOnEquipComplete::CreateLambda([](bool bSuccess)
{
if (bSuccess)
{
UE_LOG(LogVidya, Log, TEXT("Weapon equipped!"));
}
}));
}
// Consume an item
if (HealthPotion && HealthPotion->GetQuantity() > 0)
{
HealthPotion->Consume(1, FOnConsumeComplete::CreateLambda([](bool bSuccess) { /* ... */ }));
}
// List an item on marketplace
if (RareItem)
{
RareItem->List(50.0f, 1, 7, // price, quantity, duration
FOnListComplete::CreateLambda([](const FListing& Listing)
{
UE_LOG(LogVidya, Log, TEXT("Item listed!"));
}));
}
Marketplace System
// Browse marketplace
FMarketplaceFilter Filter;
Filter.Category = TEXT("weapons");
Filter.MinPrice = 10;
Filter.MaxPrice = 100;
Filter.Sort = EMarketplaceSort::PriceAsc;
Filter.Limit = 20;
Vidya->Marketplace->GetListings(Filter,
FOnGetListingsComplete::CreateLambda([](const TArray<FListing>& Listings)
{
for (const FListing& Listing : Listings)
{
UE_LOG(LogVidya, Log, TEXT("Listing: %s - $%.2f"),
*Listing.Item->GetName(), Listing.Price);
}
}));
// Buy items (requires authentication)
FBuyItemOptions BuyOptions;
BuyOptions.Listing = SwordListing;
BuyOptions.Quantity = 2;
Vidya->Marketplace->BuyItem(BuyOptions,
FOnPurchaseComplete::CreateLambda([](const FPurchase& Purchase)
{
UE_LOG(LogVidya, Log, TEXT("Purchase complete!"));
}));
// Create listing
FCreateListingOptions ListingOptions;
ListingOptions.Item = ItemToSell;
ListingOptions.Price = 50.0f; // USD
ListingOptions.Quantity = 1;
ListingOptions.Duration = 7; // Days
Vidya->Marketplace->CreateListing(ListingOptions, /* callback */);
Crafting System
// Get craftable recipes for current player
FSession Session = Vidya->Auth->GetSession();
UPlayer* Player = UPlayer::FromSession(Session);
Vidya->Crafting->GetCraftableRecipes(Player,
FOnGetRecipesComplete::CreateLambda([this, Player](const TArray<FRecipe>& Recipes)
{
for (const FRecipe& Recipe : Recipes)
{
if (Recipe.Name == TEXT("Epic Sword"))
{
// Check requirements
Vidya->Crafting->CheckRequirements(Player, Recipe,
FOnCheckRequirements::CreateLambda([this, Recipe](const FRequirementsResult& Result)
{
if (!Result.bSuccess)
{
for (const FMissingItem& Missing : Result.MissingItems)
{
UE_LOG(LogVidya, Warning, TEXT("Need %d more %s"),
Missing.Required - Missing.Have, *Missing.Item->GetName());
}
}
else
{
// Craft item
FCraftOptions CraftOptions;
CraftOptions.Player = Player;
CraftOptions.Recipe = Recipe;
Vidya->Crafting->CraftItem(CraftOptions, /* callback */);
}
}));
}
}
}));
Gacha System
// Get available gacha boxes
Vidya->Gacha->GetBoxes(
FOnGetBoxesComplete::CreateLambda([this, Player](const TArray<FGachaBox>& Boxes)
{
for (const FGachaBox& Box : Boxes)
{
if (Box.Name == TEXT("Premium Box"))
{
// Open loot box
FOpenBoxOptions OpenOptions;
OpenOptions.Player = Player;
OpenOptions.Box = Box;
Vidya->Gacha->OpenBox(OpenOptions,
FOnOpenBoxComplete::CreateLambda([](const FGachaReward& Reward)
{
UE_LOG(LogVidya, Log, TEXT("Got %s!"), *Reward.Item->GetName());
}));
}
}
}));
Leaderboards
// Submit score
FSubmitScoreOptions ScoreOptions;
ScoreOptions.LeaderboardId = TEXT("weekly-score");
ScoreOptions.Score = 15000;
ScoreOptions.Metadata.Add(TEXT("level"), TEXT("45"));
ScoreOptions.Metadata.Add(TEXT("character"), TEXT("warrior"));
Vidya->Leaderboard->SubmitScore(ScoreOptions);
// Get leaderboard
FLeaderboardOptions Options;
Options.Type = ELeaderboardType::Weekly;
Options.Limit = 100;
Vidya->Leaderboard->GetLeaderboard(TEXT("weekly-score"), Options,
FOnGetLeaderboard::CreateLambda([](const FLeaderboard& Leaderboard)
{
for (const FLeaderboardEntry& Entry : Leaderboard.Entries)
{
UE_LOG(LogVidya, Log, TEXT("#%d: %s - %d"),
Entry.Rank, *Entry.Player->GetPlayerId(), Entry.Score);
}
}));
Social System
// Send friend request
Vidya->Player->FindByUsername(TEXT("CoolPlayer"),
FOnPlayerFound::CreateLambda([this](UPlayer* NewFriend)
{
if (NewFriend)
{
Vidya->Social->SendFriendRequest(NewFriend, TEXT("Let's team up!"));
}
}));
// Create guild
FCreateGuildOptions GuildOptions;
GuildOptions.Name = TEXT("Elite Warriors");
GuildOptions.Tag = TEXT("ELITE");
GuildOptions.Description = TEXT("Top players only");
GuildOptions.MaxMembers = 100;
Vidya->Social->CreateGuild(GuildOptions,
FOnGuildCreated::CreateLambda([](const FGuild& Guild)
{
UE_LOG(LogVidya, Log, TEXT("Guild created: %s"), *Guild.Name);
}));
AI NPCs
// Spawn NPC
FSpawnNPCOptions SpawnOptions;
SpawnOptions.DefinitionId = TEXT("merchant-001");
SpawnOptions.Location = FVector(100, 0, 50);
Vidya->NPC->SpawnNPC(SpawnOptions,
FOnNPCSpawned::CreateLambda([this](UNPC* NPC)
{
// Interact with NPC
FInteractOptions InteractOptions;
InteractOptions.NpcId = NPC->GetDefinition()->Id;
InteractOptions.Action = TEXT("talk");
Vidya->NPC->Interact(InteractOptions, /* callback */);
}));
Currency System
// Get balances
FSession Session = Vidya->Auth->GetSession();
UPlayer* Player = UPlayer::FromSession(Session);
Vidya->Currency->GetBalances(Player,
FOnGetBalances::CreateLambda([](const FCurrencyBalances& Balances)
{
UE_LOG(LogVidya, Log, TEXT("Gold: %d, Gems: %d"),
Balances.Gold, Balances.Gems);
}));
// Transfer currency
FTransferOptions TransferOptions;
TransferOptions.From = Player;
TransferOptions.To = Recipient;
TransferOptions.Currency = TEXT("gold");
TransferOptions.Amount = 100;
Vidya->Currency->Transfer(TransferOptions);
Blueprint Support
All SDK functionality is exposed to Blueprint for visual scripting:
Blueprint Setup
- Create a Blueprint based on GameMode or PlayerController
- Add a VidyaSDK variable
- Initialize in BeginPlay event
Blueprint Events
The SDK provides Blueprint-friendly events:
- OnLoginComplete
- OnItemReceived
- OnFriendRequestReceived
- OnTransactionComplete
- OnLeaderboardUpdated
Blueprint Functions
All SDK methods are exposed as Blueprint nodes with proper categories and tooltips.
Advanced Features
Error Handling
// Using delegates with error handling
Vidya->Marketplace->BuyItem(BuyOptions,
FOnPurchaseComplete::CreateLambda([](const FPurchase& Purchase)
{
if (Purchase.bSuccess)
{
UE_LOG(LogVidya, Log, TEXT("Purchase successful!"));
}
else
{
switch (Purchase.Error.Code)
{
case EVidyaErrorCode::InsufficientBalance:
UE_LOG(LogVidya, Error, TEXT("Not enough funds"));
break;
case EVidyaErrorCode::PlayerNotAuthenticated:
UE_LOG(LogVidya, Error, TEXT("Please login first"));
break;
case EVidyaErrorCode::ReadOnlyPlayer:
UE_LOG(LogVidya, Error, TEXT("This action requires authentication"));
break;
default:
UE_LOG(LogVidya, Error, TEXT("Error: %s"), *Purchase.Error.Message);
}
}
}));
Event System
// Subscribe to module events
Vidya->Inventory->OnItemReceived.AddLambda([this](const FItemReceivedEvent& Event)
{
if (Event.Player->GetPlayerId() == Player->GetPlayerId())
{
ShowNotification(FString::Printf(TEXT("Received %s!"), *Event.Item->GetName()));
}
});
Vidya->Social->OnFriendRequestReceived.AddLambda([this](const FFriendRequestEvent& Event)
{
ShowNotification(FString::Printf(TEXT("Friend request from %s"), *Event.From->GetPlayerId()));
});
// Global transaction events
Vidya->OnTransaction.AddLambda([](const FTransaction& Transaction)
{
UE_LOG(LogVidya, Log, TEXT("Transaction %s: %s"),
*Transaction.Id, *UEnum::GetValueAsString(Transaction.Status));
});
Complete Example
// GameClient.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "VidyaSDK.h"
#include "GameClient.generated.h"
UCLASS()
class MYGAME_API AGameClient : public AGameModeBase
{
GENERATED_BODY()
private:
UPROPERTY()
UVidyaSDK* Vidya;
UPROPERTY()
UPlayer* Player;
protected:
virtual void BeginPlay() override;
UFUNCTION()
void Initialize();
UFUNCTION()
void SendGiftToFriend(const FString& FriendUsername, const FString& ItemName);
UFUNCTION()
void ParticipateInGuildEvent(const FString& GuildId);
private:
void SetupEventListeners();
void ShowNotification(const FString& Message);
UFUNCTION()
void OnLoginComplete(const FSession& Session);
UFUNCTION()
void OnItemReceived(const FItemReceivedEvent& Event);
UFUNCTION()
void OnFriendRequestReceived(const FFriendRequestEvent& Event);
};
// GameClient.cpp
#include "GameClient.h"
void AGameClient::BeginPlay()
{
Super::BeginPlay();
Initialize();
}
void AGameClient::Initialize()
{
// Initialize SDK
FVidyaConfig Config;
Config.ProjectId = TEXT("your-project-id");
Config.Environment = EVidyaEnvironment::Production;
Vidya = UVidyaSDK::Create(Config);
// Authenticate
FLoginOptions LoginOptions;
LoginOptions.Provider = EAuthProvider::Discord;
Vidya->Auth->Login(LoginOptions,
FOnLoginComplete::CreateUObject(this, &AGameClient::OnLoginComplete));
}
void AGameClient::OnLoginComplete(const FSession& Session)
{
Player = UPlayer::FromSession(Session);
SetupEventListeners();
}
void AGameClient::SendGiftToFriend(const FString& FriendUsername, const FString& ItemName)
{
// Find friend
Vidya->Player->FindByUsername(FriendUsername,
FOnPlayerFound::CreateLambda([this, ItemName](UPlayer* Friend)
{
if (!Friend) return;
// Find item using predicate
auto Predicate = [ItemName](UItem* Item) -> bool
{
return Item->GetName() == ItemName &&
Item->IsTradeable() &&
Item->GetQuantity() > 0;
};
Vidya->Inventory->GetMyItem(Predicate,
FOnGetItemComplete::CreateLambda([this, Friend](UItem* Item)
{
if (!Item)
{
UE_LOG(LogVidya, Error, TEXT("Tradeable item not found"));
return;
}
// Transfer using item method
Item->Transfer(Friend, 1);
// Check if already friends and send request if not
Vidya->Social->GetFriends(
FOnGetFriends::CreateLambda([this, Friend](const TArray<FFriend>& Friends)
{
bool bIsFriend = Friends.ContainsByPredicate([Friend](const FFriend& F)
{
return F.Player->GetPlayerId() == Friend->GetPlayerId();
});
if (!bIsFriend)
{
Vidya->Social->SendFriendRequest(Friend, TEXT("Thanks for playing!"));
}
}));
}));
}));
}
void AGameClient::SetupEventListeners()
{
Vidya->Inventory->OnItemReceived.AddUObject(this, &AGameClient::OnItemReceived);
Vidya->Social->OnFriendRequestReceived.AddUObject(this, &AGameClient::OnFriendRequestReceived);
}
void AGameClient::OnItemReceived(const FItemReceivedEvent& Event)
{
if (Event.Player->GetPlayerId() == Player->GetPlayerId())
{
ShowNotification(FString::Printf(TEXT("Received %s!"), *Event.Item->GetName()));
}
}
void AGameClient::OnFriendRequestReceived(const FFriendRequestEvent& Event)
{
ShowNotification(FString::Printf(TEXT("Friend request from %s"), *Event.From->GetPlayerId()));
}
void AGameClient::ShowNotification(const FString& Message)
{
UE_LOG(LogVidya, Log, TEXT("[Notification] %s"), *Message);
// Show UI notification
}
API Reference
For detailed API documentation, see the SDK documentation.
Unreal-Specific Features
Actor Components
The SDK includes ready-to-use Actor Components:
- UVidyaAuthComponent - Handles authentication UI
- UVidyaInventoryComponent - Manages inventory display
- UVidyaMarketplaceComponent - Marketplace browser
- UVidyaSocialComponent - Friends and guild management
Widget Blueprints
Pre-built UI widgets included:
- WBP_VidyaLogin - Authentication screen
- WBP_VidyaInventory - Inventory grid
- WBP_VidyaMarketplace - Marketplace browser
- WBP_VidyaCrafting - Crafting interface
- WBP_VidyaLeaderboard - Leaderboard display
- WBP_VidyaSocial - Social features
- WBP_VidyaNPCDialog - NPC interaction
Replication Support
The SDK supports Unreal's replication system:
// In your replicated actor
UFUNCTION(Server, Reliable)
void ServerTransferItem(UPlayer* ToPlayer, UItem* Item, int32 Quantity);
void AMyActor::ServerTransferItem_Implementation(UPlayer* ToPlayer, UItem* Item, int32 Quantity)
{
if (Item && ToPlayer)
{
Item->Transfer(ToPlayer, Quantity);
}
}
Mobile Optimization
// Configure for mobile
FMobileConfig MobileConfig;
MobileConfig.bAutoManageSession = true;
MobileConfig.bBiometricAuth = true;
MobileConfig.bLowBandwidthMode = true;
Vidya->ConfigureMobile(MobileConfig);
C++ and Blueprint Support
The SDK provides full C++ support with Blueprint exposure:
// All classes are marked with appropriate specifiers
UCLASS(BlueprintType, Blueprintable)
class VIDYASDK_API UItem : public UObject
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "Vidya|Item")
FString GetName() const;
UFUNCTION(BlueprintCallable, Category = "Vidya|Item")
int32 GetQuantity() const;
UFUNCTION(BlueprintCallable, Category = "Vidya|Item", meta = (CallInEditor = "true"))
void Transfer(UPlayer* ToPlayer, int32 Quantity);
};