Skip to content

Commit

Permalink
Initial commit with v2.0.0 release
Browse files Browse the repository at this point in the history
  • Loading branch information
patrykf-dev committed Oct 16, 2023
0 parents commit eb4b163
Show file tree
Hide file tree
Showing 20 changed files with 1,207 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Binaries/
Intermediate/
29 changes: 29 additions & 0 deletions GameSwiftSdk.uplugin
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"FileVersion": 3,
"VersionName": "2.0.0",
"Version": 200,
"FriendlyName": "GameSwiftUnrealSdk",
"Description": "GameSwift Unreal SDK is Unity toolset created to integrate with GameSwift ID ecosystem.",
"Category": "Other",
"CreatedBy": "GameSwift",
"CreatedByURL": "https://gameswift.io/",
"DocsURL": "https://docs.gameswift.io/gameswift-products/sdk",
"CanContainContent": true,
"IsBetaVersion": false,
"IsExperimentalVersion": false,
"Installed": false,
"Modules": [
{
"Name": "GameSwiftSdk",
"Type": "Runtime",
"LoadingPhase": "PreDefault",
"WhitelistPlatforms": [
"Win64",
"Win32",
"Mac",
"IOS",
"Android"
]
}
]
}
160 changes: 160 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# Overview

GameSwift Unreal SDK is a toolset created to to help you seamlessly
integrate [GameSwift ecosystem](https://platform.gameswift.io/) into your Unreal Engine projects. Key features of
GameSwift Unreal SDK are:

* **Rapid integration**

Installation and integration process is streamlined and can be completed in under 30 minutes. This means you can focus
more on building your game and less on complex API integration.

* **Safety**

Firstly, [GameSwift Launcher](https://launcher.gameswift.io/) is equipped with a robust DRM system that guarantees
players launch your game without altering any game files.
Secondly, [Multiple Logins Blocker](#multiple-logins-blocker) ensures that a user account is logged in from exactly
one device at a time. Both of these features prevent various types of abuses and help you maintain a secure and fair
gaming environment.

* **Blueprint support**

All SDK features can be accessed both in C++ code and in the Unreal Engine Blueprint system. This versatility
ensures that not only programmers but also non-coding individuals can work on GameSwift ecosystem integration.

* **Multiplatform support**

The wrapper is designed to work seamlessly on multiple platforms, making it adaptable for a variety of game
development projects. You can bring the best gaming experiences with GameSwift Unreal SDK for Windows, MacOS and
mobile.

GameSwift Unreal SDK is compatible with Unreal Engine versions 4.24 and beyond. We are committed to keeping
it up-to-date with newer Unreal Engine releases, including Unreal Engine 5 and upcoming versions.

# Installation

1. Add SDK to you project. This can be done in two ways:
* Add SDK as [git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules) to your repository by invoking the
following command:
```bash
git submodule add https://github.com/GameSwift/gameswift-unreal-sdk YourMainProjectDir/Plugins/GameSwiftUnrealSdk
```
* Download this repository contents
from [newest release](https://github.com/GameSwift/gameswift-unreal-sdk/releases/) and unpack the plugin to
the `Plugins/GameSwiftUnrealSdk` folder. If you don't have a `Plugins` folder in your main project directory yet,
create it.
2. Open Project Settings in the editor and navigate to `Plugins > GameSwiftSdk`. Fill in following
fields: `ClientId`, `ClientRedirectUri`, `ClientAuthenticationSecret`. These secrets
are [distributed by GameSwift](#contact-us).
![Plugin secrets](https://github-production-user-asset-6210df.s3.amazonaws.com/109578061/275326695-cad47683-f07a-4d60-a9eb-338e454e6f12.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20231015%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20231015T155030Z&X-Amz-Expires=300&X-Amz-Signature=5f594705cef1e88f03b416a8397762fcc610522672ffb78ce0e0bed12208ef51&X-Amz-SignedHeaders=host&actor_id=109578061&key_id=0&repo_id=704859033)
3. Add `GameSwiftSdk` to `PublicDependencyModuleNames` in your main `*.Build.cs` file.
# Integration
You can handle GameSwift login in 2 ways: [with launcher](#logging-in-from-launcher)
or [without launcher](#logging-in-without-launcher). You can download GameSwift
launcher [here](https://launcher.gameswift.io/). As long as your game targets Windows or MacOS, we strongly recommend to
use data passed from our launcher. By doing so, you won't need to implement any login screen for your game as launcher
already handles user credentials ina secure way.If you are building for mobile, you will need to create a login screen
and implement connection with GameSwift backend [the other way](#logging-in-without-launcher).

No matter which approach you choose (C++ or Blueprints), be sure that `AuthorizeAndReadUserInfoFromLauncher`
or `LoginAndAuthorize` is called at the application startup.This method wil succeed provided that:

1. User has internet connection.
2. User did not attempt to login simultaneously from multiple devices (applicable only for
applications with [Multiple Logins Blocker](#multiple-logins-blocker) enabled).
3. User launched the game via launcher instead of your game executable file (provided that you
used [with launcher](#logging-in-from-launcher) flow).

Otherwise, you should retry calling this method or close the application as it may not be launched the intended way.

## Launcher authentication - C++

Authorizing the user and getting his info can be done by
calling `UGameSwiftAuthenticationManager::AuthorizeAndReadUserInfoFromLauncher`.

```cpp
void ASampleCharacter::ReadUserInfoFromLauncher()
{
FGetUserInfoDelegate SuccessDelegate;
SuccessDelegate.BindUFunction(this, "OnSuccess");
FBaseSdkFailDelegate FailDelegate;
FailDelegate.BindUFunction(this, "OnError");
UGameSwiftAuthenticationManager::AuthorizeAndReadUserInfoFromLauncher(SuccessDelegate, FailDelegate);
}
void ASampleCharacter::OnSuccess(const FOAuthUserInfoResponse& Response)
{
// success - you can read user nickname and other data from Response
}
void ASampleCharacter::OnError(const FBaseSdkFailResponse& Response)
{
// fail - close the application or retry authorization
}
```

## Launcher authentication - Blueprint

`AuthorizeAndReadUserInfoFromLauncher` node is responsible for authorizing the user, who accessed the game through
GameSwift Launcher.

![Launcher login with Blueprints](https://github-production-user-asset-6210df.s3.amazonaws.com/109578061/275194063-dfb534d1-a6ea-45de-a892-1b60841a6952.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20231015%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20231015T155121Z&X-Amz-Expires=300&X-Amz-Signature=509ef88a05d06069d351a8e471035592768ba0e7475ad8517df11d1ef2ccc674&X-Amz-SignedHeaders=host&actor_id=109578061&key_id=0&repo_id=704859033)

## Non-launcher authentication - C++

With this approach you need to create a custom login widget, which will enable user to input the login data and
authorize.

Authorizing the user and getting his info can be done by calling `UGameSwiftAuthenticationManager::LoginAndAuthorize`.

```cpp
void ASampleCharacter::LoginAndAuthorize()
{
Fstring EmailOrNickname = "[email protected]";
Fstring Password = "Password123";
FGetUserInfoDelegate SuccessDelegate;
SuccessDelegate.BindUFunction(this, "OnSuccess");
FBaseSdkFailDelegate FailDelegate;
FailDelegate.BindUFunction(this, "OnError");
UGameSwiftAuthenticationManager::LoginAndAuthorize(EmailOrNickname, Password,
SuccessDelegate, FailDelegate);
}
void ASampleCharacter::OnSuccess(const FOAuthUserInfoResponse& Response)
{
// success - you can read user nickname and other data from Response
}
void ASampleCharacter::OnError(const FBaseSdkFailResponse& Response)
{
// fail - close the application or retry authorization
}
```

## Non-launcher authentication - Blueprint

`GetUserCredentials` node in the sample below is your implementation of retrieving login data from your custom login
widget. Then, you can pass retrieved data to `LoginAndAuthorize` node.

![Non launcher login with Blueprints](https://github-production-user-asset-6210df.s3.amazonaws.com/109578061/275194061-6bd7b194-49c9-4898-bc49-1fd146baa9d9.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20231015%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20231015T155137Z&X-Amz-Expires=300&X-Amz-Signature=d5ed67496752a06bf27352d60840374e60342f77f816ffa71b04fd17bf8100d3&X-Amz-SignedHeaders=host&actor_id=109578061&key_id=0&repo_id=704859033)

## Multiple Logins Blocker

Multiple Logins Blocker is an optional, powerful feature of GameSwift Unreal SDK that ensures a user's account can
only be logged in on one device at a time. This component's setup is done in Project Settings
under `Plugins > GameSwiftSdk`.

If enabled, this component works in background of your game, sending periodic heartbeats to GameSwift server at time
intervals specified by you. When server receives these heartbeats, it recognizes that the user is already logged in and
will block any additional login attempts from this user for a configurable duration. If you want to configure the lock
duration, feel free to [contact us](#contact-us).

# Contact Us

If you have any questions, concerns, or feedback, please don't hesitate to reach out to GameSwift team. We're here to
assist you and can be contacted via email at [[email protected]](mailto:[email protected]).
Binary file added Resources/Icon128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions Source/GameSwiftSdk/GameSwiftSdk.Build.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.IO;
using UnrealBuildTool;

public class GameSwiftSdk : ModuleRules
{
public GameSwiftSdk(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;

PublicIncludePaths.Add(Path.Combine(ModuleDirectory, "Public"));
PrivateIncludePaths.Add(Path.Combine(ModuleDirectory, "Private"));

PublicDependencyModuleNames.AddRange(new[]
{
"Core",
"CoreUObject",
"HTTP",
"Json",
"JsonUtilities",
"Engine"
});
}
}
100 changes: 100 additions & 0 deletions Source/GameSwiftSdk/Private/BackendResponses.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#include "BackendResponses.h"

bool FOAuthUserInfoResponse::Parse(const FJsonObject& JsonObject, FOAuthUserInfoResponse& ParsedResponse)
{
bool SuccessfulRead = true;
SuccessfulRead &= JsonObject.TryGetStringField("userId", ParsedResponse.UserId);
SuccessfulRead &= JsonObject.TryGetStringField("nickname", ParsedResponse.Nickname);
SuccessfulRead &= JsonObject.TryGetStringField("avatarUrl", ParsedResponse.AvatarUrl);
SuccessfulRead &= JsonObject.TryGetStringField("country", ParsedResponse.Country);
return SuccessfulRead;
}

bool FAuthorizeResponse::Parse(const FJsonObject& JsonObject, FAuthorizeResponse& ParsedResponse)
{
bool SuccessfulRead = true;
SuccessfulRead &= JsonObject.TryGetStringField("code", ParsedResponse.Code);
return SuccessfulRead;
}

bool FTokenResponse::Parse(const FJsonObject& JsonObject, FTokenResponse& ParsedResponse)
{
bool SuccessfulRead = true;
SuccessfulRead &= JsonObject.TryGetStringField("access_token", ParsedResponse.AccessToken);
SuccessfulRead &= JsonObject.TryGetStringField("refresh_token", ParsedResponse.RefreshToken);
return SuccessfulRead;
}

bool FWalletsResponse::Parse(const TArray<FJsonObject> JsonObject, FWalletsResponse& ParsedResponse)
{
bool SuccessfulRead = true;

for (const auto WalletElement : JsonObject)
{
FWallet Wallet = FWallet();
SuccessfulRead &= WalletElement.TryGetStringField("address", Wallet.Address);
SuccessfulRead &= WalletElement.TryGetStringField("name", Wallet.Name);
SuccessfulRead &= WalletElement.TryGetStringField("walletId", Wallet.WalletId);

TArray<FGame> Games;
TArray<TSharedPtr<FJsonValue>> GamesArray = WalletElement.GetArrayField("games");
for (const TSharedPtr<FJsonValue>& GameValue : GamesArray)
{
FGame Game = FGame();
TSharedPtr<FJsonObject> GameObject = GameValue->AsObject();
Game.GameId = GameObject->GetStringField("gameId");
Games.Add(Game);
}
Wallet.Games = Games;

FChain Chain = FChain();
TSharedPtr<FJsonObject> ChainObject = WalletElement.GetObjectField("chain");
Chain.ChainId = ChainObject->GetStringField("chainId");
Chain.ChainName = ChainObject->GetStringField("chainName");
Wallet.Chain = Chain;

ParsedResponse.Wallets.Add(Wallet);
}

return SuccessfulRead;
}

bool FWalletBalanceResponse::Parse(const FJsonObject& JsonObject, FWalletBalanceResponse& ParsedResponse)
{
bool SuccessfulRead = true;

const TArray<TSharedPtr<FJsonValue>>* NftsArray;
SuccessfulRead &= JsonObject.TryGetArrayField("nfts", NftsArray);
for (const TSharedPtr<FJsonValue>& NftValue : *NftsArray)
{
FNft Nft = FNft();
TSharedPtr<FJsonObject> GameObject = NftValue->AsObject();
Nft.Address = GameObject->GetStringField("address");
Nft.Balance = GameObject->GetNumberField("balance");
Nft.Id = GameObject->GetStringField("id");
ParsedResponse.Nfts.Add(Nft);
}

const TArray<TSharedPtr<FJsonValue>>* TokensArray;
SuccessfulRead &= JsonObject.TryGetArrayField("tokens", TokensArray);
for (const TSharedPtr<FJsonValue>& TokenValue : *TokensArray)
{
FToken Token = FToken();
TSharedPtr<FJsonObject> GameObject = TokenValue->AsObject();
Token.Address = GameObject->GetStringField("address");
Token.Balance = GameObject->GetNumberField("balance");
ParsedResponse.Tokens.Add(Token);
}

return SuccessfulRead;
}

bool FLoginResponse::Parse(const FJsonObject& JsonObject, FLoginResponse& ParsedResponse)
{
bool SuccessfulRead = true;
SuccessfulRead &= JsonObject.TryGetStringField("userId", ParsedResponse.UserId);
SuccessfulRead &= JsonObject.TryGetStringField("email", ParsedResponse.Email);
SuccessfulRead &= JsonObject.TryGetStringField("nickname", ParsedResponse.Nickname);
SuccessfulRead &= JsonObject.TryGetStringField("accessToken", ParsedResponse.AccessToken);
return SuccessfulRead;
}
Loading

0 comments on commit eb4b163

Please sign in to comment.