Skip to content

Commit

Permalink
Merge pull request #399 from trilitech/staging
Browse files Browse the repository at this point in the history
Update main from staging, 24 May
  • Loading branch information
timothymcmackin authored May 24, 2024
2 parents 23f552b + e876e9c commit 94f5001
Show file tree
Hide file tree
Showing 13 changed files with 169 additions and 18 deletions.
6 changes: 3 additions & 3 deletions docs/smart-contracts/languages/smartpy.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,17 @@ import smartpy as sp
@sp.module
def main():
class StoreGreeting(sp.Contract):
def __init__(self, greeting): # Note the indentation
def __init__(self, greeting): # Note the indentation
# Initialize the storage with a string passed at deployment time
# Cast the greeting parameter to a string
sp.cast(greeting, sp.string)
self.data.greeting = greeting

@sp.entrypoint # Note the indentation
@sp.entrypoint # Note the indentation
def replace(self, params):
self.data.greeting = params.text

@sp.entrypoint # Note the indentation
@sp.entrypoint # Note the indentation
def append(self, params):
self.data.greeting += params.text

Expand Down
16 changes: 8 additions & 8 deletions docs/smart-contracts/views.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,10 @@ def callView(self, a, b):
sp.cast(a, sp.int)
sp.cast(b, sp.int)
viewResponseOpt = sp.view(
"get_larger", # Name of the view
sp.address("KT1K6kivc91rZoDeCqEWjH8YqDn3iz6iEZkj"), # Address of the contract
sp.record(a=a, b=b), # Parameters to pass
sp.int # Return type of the view
"get_larger", # Name of the view
sp.address("KT1K6kivc91rZoDeCqEWjH8YqDn3iz6iEZkj"), # Address of the contract
sp.record(a=a, b=b), # Parameters to pass
sp.int # Return type of the view
)
if viewResponseOpt.is_some():
self.data.myval = viewResponseOpt.unwrap_some()
Expand All @@ -185,10 +185,10 @@ If the view takes no parameters, pass `()` for the parameter:

```python
viewResponseOpt = sp.view(
"no_param_view", # Name of the view
sp.address("KT1K6kivc91rZoDeCqEWjH8YqDn3iz6iEZkj"), # Address of the contract
(), # No parameter
sp.int # Return type of the view
"no_param_view", # Name of the view
sp.address("KT1K6kivc91rZoDeCqEWjH8YqDn3iz6iEZkj"), # Address of the contract
(), # No parameter
sp.int # Return type of the view
)
```

Expand Down
12 changes: 6 additions & 6 deletions docs/tutorials/smart-contract/smartpy.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -114,17 +114,17 @@ You can work with SmartPy code in any IDE, but this online IDE keeps you from ha
@sp.module
def main():
class StoreGreeting(sp.Contract):
def __init__(self, greeting): # Note the indentation
def __init__(self, greeting): # Note the indentation
# Initialize the storage with a string passed at deployment time
# Cast the greeting parameter to a string
sp.cast(greeting, sp.string)
self.data.greeting = greeting

@sp.entrypoint # Note the indentation
@sp.entrypoint # Note the indentation
def replace(self, params):
self.data.greeting = params.text

@sp.entrypoint # Note the indentation
@sp.entrypoint # Note the indentation
def append(self, params):
self.data.greeting += params.text
```
Expand Down Expand Up @@ -178,17 +178,17 @@ import smartpy as sp
@sp.module
def main():
class StoreGreeting(sp.Contract):
def __init__(self, greeting): # Note the indentation
def __init__(self, greeting): # Note the indentation
# Initialize the storage with a string passed at deployment time
# Cast the greeting parameter to a string
sp.cast(greeting, sp.string)
self.data.greeting = greeting

@sp.entrypoint # Note the indentation
@sp.entrypoint # Note the indentation
def replace(self, params):
self.data.greeting = params.text

@sp.entrypoint # Note the indentation
@sp.entrypoint # Note the indentation
def append(self, params):
self.data.greeting += params.text

Expand Down
4 changes: 4 additions & 0 deletions docs/unity.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ For a walkthrough of installing and using the SDK in an existing Unity project,
The SDK includes tutorial scenes that demonstrate how to use the SDK.
For information about setting up and using the scenes, see [Tutorial scenes](./unity/scenes).

## Sample game

For information about a complete sample game that you can load locally and explore, see [Sample game](./unity/sample-game).

## SDK objects

The SDK provides objects that you can use to interact with user wallets and with Tezos.
Expand Down
4 changes: 3 additions & 1 deletion docs/unity/connecting-accounts.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Connecting accounts
authors: Tim McMackin
last_update:
date: 11 January 2024
date: 14 May 2024
---

Connecting to a user's wallet is a prerequisite to working with Tezos in any application.
Expand All @@ -14,6 +14,8 @@ Game developers can also use the wallet and its account as a unique account iden

For an example of connecting to wallets, see the [WalletConnection tutorial scene](./scenes#wallet-connection-scene).

For more information about Tezos wallets, see [Installing and funding a wallet](../developing/wallet-setup).

## Best practices

When working with wallets, be sure to follow the advice in [Best practices and avoiding flaws](../dApps/best-practices) for wallet connections.
Expand Down
144 changes: 144 additions & 0 deletions docs/unity/sample-game.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
---
title: Sample game
authors: Tim McMackin
last_update:
date: 22 May 2024
---

The sample game for the Unity SDK is a single-player third-person shooter with survival elements.
Players receive tokens that represent in-game items and the game tracks and transfers them via the Tezos blockchain.
You can import this game into the Unity Editor and work with it yourself.

The game shows how developers might structure a large-scale dApp by separating different features into different components, as described below in [Architecture](#architecture).
In particular, it handles some Tezos interaction from the Unity game itself, including connecting to the user's wallet and prompting them to sign a payload to authenticate.
The rest of the Tezos interaction happens in the backend application, including distributing tokens that represent in-game objects.
The Unity game also allows users to transfer those tokens to other accounts.

The source code for the Unity frontend application is here: https://github.com/baking-bad/tezos-unity-game.
To open it locally, see [Opening the sample game](#opening-the-sample-game).
To play the game, go to https://game.baking-bad.org.

The source code for the backend application is here: https://github.com/k-karuna/tezos_game_back.

![A screenshot from within the game interface](/img/unity/sample-game-ui.png)

## Architecture

The sample game uses these main components:

- **User wallets** as a source of user identity and authentication.
The user doesn't make any direct transactions from the wallet and pays no tez to the application or in fees.
For more information about Tezos wallets, see [Installing and funding a wallet](../developing/wallet-setup).

- The **Unity WebGL application** is the front end of the application.
It connects to the user wallet, sends the sign request, runs the game interface, and sends requests to the backend.

- The **backend application** hosts a REST API for the Unity application to call.
The Unity application calls it from the `Assets/Scripts/Api/GameApi.cs` file for tasks such as these:

- Getting the signed payload from the wallet
- Verifying the signed payload
- Tracking events such as the beginning and end of a game session
- Sending tokens to players' accounts

The backend application is responsible for most of the interaction with the smart contract, including transferring tokens to players.
It securely manages the private key for the administrator account, which is responsible for minting and transferring tokens.
This way, the game client itself has no access to the private key.

For information about the REST API endpoints, see this page: https://game.baking-bad.org/back/swagger/.

- The **backend database** stores persistent information about players, such as the number of games they have played.

- The **smart contract** is a program that runs on the Tezos blockchain to manage tokens that represent in-game items.
It maintains a ledger of tokens and owners and allows the backend's administrator account to transfer them to players.
The sample game uses a custom contract, but you can use the SDK's built-in FA2-compliant contract; see [Managing contracts](./managing-contracts).
You can view and interact with the contract on a block explorer, such as tzkt.io: https://tzkt.io/KT1TSZfPJ5uZW1GjcnXmvt1npAQ2nh5S1FAj/operations.

- The **Interplanetary File System (IPFS)** stores metadata for the tokens, including pictures and descriptions.

This diagram shows the basic interaction between these components:

![The architecture of the sample game, showing interaction between the user wallet, the Unity WebGL application, the backend, and the smart contract](/img/unity/sample-game-architecture.png)

## Authentication

The game uses the user's Tezos account as a source of authentication.
It prompts the user to connect their Tezos wallet so it can retrieve the user's account address.
For more information about connecting to user wallets, see [Connecting accounts](./connecting-accounts).

When the wallet is connected, the game prompts the user to sign a payload to prove that they have the key for the account.
The process follows these general steps:

1. The user loads the game client and clicks the button to connect.
1. The game client requests an authentication payload from the backend.
1. The backend [generates a random string](https://github.com/k-karuna/tezos_game_back/blob/e6bc9c021b86704ec1ce1b5e3fd799977d05034f/api/views.py#L20) and sends it to the Unity application.
1. The Unity application [sends the string as a signing request payload](https://github.com/baking-bad/tezos-unity-game/blob/7e3fb6454896896f7e0ac77f09d2b5f02e104aa7/Assets/Scripts/Managers/UserDataManager.cs#L108) to the wallet.
1. The user signs the payload in their wallet application.
1. The Unity application [receives the signed payload and sends it to the backend](https://github.com/baking-bad/tezos-unity-game/blob/9b71d3832dac076d74bd822c19b5f93909434190/Assets/Scripts/Managers/UserDataManager.cs#L78).
1. The backend [verifies that the payload is correctly signed](https://github.com/k-karuna/tezos_game_back/blob/e6bc9c021b86704ec1ce1b5e3fd799977d05034f/api/views.py#L50).
1. The game [allows the user to play if validation is successful](https://github.com/baking-bad/tezos-unity-game/blob/9b71d3832dac076d74bd822c19b5f93909434190/Assets/Scripts/Managers/UserDataManager.cs#L80).

Here is a diagram of the process:

![Authentication flow diagram](/img/unity/unity-sample-game-authentication.png)

For more information about signing messages, see [Signing messages](./quickstart#signing-messages) in the Unity SDK quickstart.

## Tokens

The game uses Tezos tokens to represent in-game items, such as weapons, armor, and power-ups.
Because these tokens are compliant with the [FA2](../architecture/tokens/FA2) standard, players can see their tokens in their wallets and in applications such as block explorers.
They could also set up a third-party platform to show and trade their tokens.

The smart contract that manages the tokens has one [token type](https://better-call.dev/mainnet/KT1TSZfPJ5uZW1GjcnXmvt1npAQ2nh5S1FAj/tokens) for each in-game item.
For example, tokens with the ID 1 represent armor:

![Example of a token type](/img/unity/sample-game-token-types.png)

The contract pre-mints a supply of 1000 of each token type so tokens are available when players claim them.
When a player claims a token with the Claim Reward button and solves a captcha, the game client calls the backend, which verifies the captcha and calls the contract's `transfer` entrypoint to send one of that token type to the player's account.
This diagram shows the interaction between the game and the player's wallet:

![A diagram of the interaction between the player's wallet and the components of the application, showing how tokens are read from the wallet information and distributed from the smart contract to the wallet](/img/unity/sample-game-architecture-play.png)

An account can have only one of each token type, which makes the tokens similar to NFTs, but they are not NFTs because any number of accounts can have one of each token.
Therefore, they are technically fungible tokens because tokens of the same type are interchangeable, but the backend sends only one token of each type to each account.

To see the tokens that an account has, you can check the ledger in the contract's storage.
The ledger has entries that are indexed by the account address and the token type.
For example, this ledger entry shows that account `tz1eQQnDbkTpTnu3FXix28xKdaWYRqrsZcZv` has one token of type 16:

![The contract ledger on Better Call Dev, showing one entry](/img/unity/sample-game-ledger-entry.png)

The contract uses standard FA2 entrypoints including `transfer`, plus other custom entrypoints for this implementation.
You can see these entrypoints on block explorers: https://better-call.dev/mainnet/KT1TSZfPJ5uZW1GjcnXmvt1npAQ2nh5S1FAj/interact.

## User data

The game uses the Unity SDK to get player data from the backend and work with it locally.
The [`UserDataManager.cs`](https://github.com/baking-bad/tezos-unity-game/blob/master/Assets/Scripts/Managers/UserDataManager.cs) file manages this player data, which includes:

- The tokens that the account owns
- The player's statistics
- Information about the active game session
- The player's currently equipped equipment
- Pending rewards, which represent in-game items that the user has earned but has not received a token for yet

Some of this information (such as the tokens that the player owns) comes from Tezos and other information (such as the player's statistics) comes from the backend.
Information about the current game session and pending rewards are non-persistent data that are stored by the Unity application.

The `UserDataManager` class responds to [events](./reference/EventManager) such as when the user connects their wallet and then loads information from the backend and from Tezos directly.

## Opening the sample game

Follow these steps to open the sample game in the Unity editor:

1. Clone the sample game repository at https://github.com/baking-bad/tezos-unity-game.

1. In Unity Hub, click **Add > Add project from disk**.

1. Select the repository folder and click **Add Project**.

1. If Unity Hub prompts you to install a specific version of Unity Editor, follow the prompts to install that version.

1. Click the project in Unity Hub to open it in Unity Editor.
1 change: 1 addition & 0 deletions sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ const sidebars = {
items: [
'unity/quickstart',
'unity/scenes',
'unity/sample-game',
'unity/prefabs',
'unity/connecting-accounts',
'unity/managing-contracts',
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/img/unity/sample-game-architecture.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/img/unity/sample-game-ledger-entry.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/img/unity/sample-game-token-types.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/img/unity/sample-game-ui.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 94f5001

Please sign in to comment.