diff --git a/Packages/io.chainsafe.web3-unity.web3auth/Runtime/IWeb3AuthConfig.cs b/Packages/io.chainsafe.web3-unity.web3auth/Runtime/IWeb3AuthConfig.cs
index fe51eb798..bab136ced 100644
--- a/Packages/io.chainsafe.web3-unity.web3auth/Runtime/IWeb3AuthConfig.cs
+++ b/Packages/io.chainsafe.web3-unity.web3auth/Runtime/IWeb3AuthConfig.cs
@@ -1,7 +1,10 @@
+using System;
using System.Threading;
using System.Threading.Tasks;
using ChainSafe.Gaming.EmbeddedWallet;
-using TWeb3Auth = Web3Auth;
+using Network = Web3Auth.Network;
+using ThemeModes = Web3Auth.ThemeModes;
+using Language = Web3Auth.Language;
namespace ChainSafe.GamingSdk.Web3Auth
{
@@ -10,10 +13,33 @@ namespace ChainSafe.GamingSdk.Web3Auth
///
public interface IWeb3AuthConfig : IEmbeddedWalletConfig
{
+ // Name of the App.
+ public string AppName { get; }
+ // Client ID you get from Web3Auth dashboard.
+ public string ClientId { get; }
+ // Redirect URI for the app.
+ public string RedirectUri { get; }
+ // Network to connect to (MainNet, TestNet...).
+ public Network Network { get; }
+ public ThemeModes Theme { get; }
+ public Language Language { get; }
+
///
/// Gets or sets the Web3AuthOptions for configuring the Web3Auth instance associated with the wallet.
///
- public Web3AuthOptions Web3AuthOptions { get; }
+ public Web3AuthOptions Web3AuthOptions => new Web3AuthOptions
+ {
+ clientId = ClientId,
+ redirectUrl = new Uri(RedirectUri),
+ network = Network,
+
+ whiteLabel = new()
+ {
+ mode = Theme,
+ defaultLanguage = Language,
+ appName = AppName,
+ }
+ };
///
/// Login Provider to use when connecting the wallet, like Google, facebook etc...
@@ -23,12 +49,21 @@ public interface IWeb3AuthConfig : IEmbeddedWalletConfig
///
/// Get the SessionId on connection from the provider.
///
- public Task SessionTask { get; set; }
+ public Task SessionTask { get; }
+ ///
+ /// Token for cancelling a connection
+ ///
public CancellationToken CancellationToken { get; }
+ ///
+ /// Remember this session
+ ///
public bool RememberMe { get; }
+ ///
+ /// Remember a previous session and login automatically
+ ///
public bool AutoLogin { get; }
}
}
diff --git a/Packages/io.chainsafe.web3-unity.web3auth/Runtime/Web3AuthConnectionProvider.cs b/Packages/io.chainsafe.web3-unity.web3auth/Runtime/Web3AuthConnectionProvider.cs
index 46fd7ae4b..4d2fac29d 100644
--- a/Packages/io.chainsafe.web3-unity.web3auth/Runtime/Web3AuthConnectionProvider.cs
+++ b/Packages/io.chainsafe.web3-unity.web3auth/Runtime/Web3AuthConnectionProvider.cs
@@ -29,10 +29,15 @@ public class Web3AuthConnectionProvider : ConnectionProvider, ILogoutHandler, IW
public override Sprite ButtonIcon { get; protected set; }
[field: SerializeField] public override string ButtonText { get; protected set; } = "Web3Auth";
+
+ [field: Space] [field: SerializeField] public string AppName { get; private set; } = "ChainSafe Gaming SDK";
+ [field: SerializeField] public string ClientId { get; private set; }
+
+ [field: SerializeField] public string RedirectUri { get; private set; }
- [SerializeField] private string clientId;
- [SerializeField] private string redirectUri;
- [SerializeField] private Network network;
+ [field: SerializeField] public Network Network { get; private set; }
+ [field: SerializeField] public Web3Auth.ThemeModes Theme { get; private set; } = Web3Auth.ThemeModes.dark;
+ [field: SerializeField] public Web3Auth.Language Language { get; private set; } = Web3Auth.Language.en;
[Space]
@@ -56,6 +61,16 @@ public class Web3AuthConnectionProvider : ConnectionProvider, ILogoutHandler, IW
public override bool IsAvailable => true;
+ public Task SessionTask { get; private set; }
+
+ public Task ProviderTask => _rememberMe ? default : _modal.SelectProvider();
+
+ public CancellationToken CancellationToken => _rememberMe ? default : _modal.CancellationToken;
+
+ public bool RememberMe => _rememberMe || RememberSession;
+
+ public bool AutoLogin => _rememberMe;
+
#if UNITY_WEBGL && !UNITY_EDITOR
private TaskCompletionSource _initializeTcs;
@@ -242,27 +257,4 @@ public Task OnWeb3Initialized(Web3 web3)
}
public bool AutoApproveTransactions => !enableWalletGui;
-
- public Web3AuthOptions Web3AuthOptions => new Web3AuthOptions
- {
- clientId = clientId,
- redirectUrl = new Uri(redirectUri),
- network = network,
- whiteLabel = new()
- {
- mode = Web3Auth.ThemeModes.dark,
- defaultLanguage = Web3Auth.Language.en,
- appName = "ChainSafe Gaming SDK",
- }
- };
-
- public Task SessionTask { get; set; }
-
- public Task ProviderTask => _rememberMe ? default : _modal.SelectProvider();
-
- public CancellationToken CancellationToken => _rememberMe ? default : _modal.CancellationToken;
-
- public bool RememberMe => _rememberMe || RememberSession;
-
- public bool AutoLogin => _rememberMe;
}
diff --git a/Packages/io.chainsafe.web3-unity.web3auth/Runtime/Web3AuthProvider.cs b/Packages/io.chainsafe.web3-unity.web3auth/Runtime/Web3AuthProvider.cs
index 5b93f0953..b67a91ad8 100644
--- a/Packages/io.chainsafe.web3-unity.web3auth/Runtime/Web3AuthProvider.cs
+++ b/Packages/io.chainsafe.web3-unity.web3auth/Runtime/Web3AuthProvider.cs
@@ -70,7 +70,7 @@ public override async Task Connect()
if (!_config.AutoLogin && providerTask != null
//On webGL providerTask is always completed, so we don't have to go through another login flow.
#if UNITY_WEBGL && !UNITY_EDITOR
- && !providerTask.IsCompleted
+ && !providerTask.IsCompleted
#endif
)
{
diff --git a/Packages/io.chainsafe.web3-unity.web3auth/Runtime/Web3AuthWalletExtensions.cs b/Packages/io.chainsafe.web3-unity.web3auth/Runtime/Web3AuthWalletExtensions.cs
index ba7754724..ad321bbb2 100644
--- a/Packages/io.chainsafe.web3-unity.web3auth/Runtime/Web3AuthWalletExtensions.cs
+++ b/Packages/io.chainsafe.web3-unity.web3auth/Runtime/Web3AuthWalletExtensions.cs
@@ -45,16 +45,4 @@ public static IWeb3ServiceCollection UseWeb3AuthWallet(this IWeb3ServiceCollecti
return collection;
}
-
- ///
- /// Replaces the existing Web3AuthWallet configuration within an IWeb3ServiceCollection with the provided configuration.
- ///
- /// The IWeb3ServiceCollection to configure the Web3AuthWallet within.
- /// The configuration for the Web3AuthWallet.
- /// The modified IWeb3ServiceCollection with the Web3AuthWallet configuration replaced.
- public static IWeb3ServiceCollection ConfigureWeb3AuthWallet(this IWeb3ServiceCollection collection, IWeb3AuthConfig configuration)
- {
- collection.Replace(ServiceDescriptor.Singleton(typeof(IWeb3AuthConfig), configuration));
- return collection;
- }
}
diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/EmbeddedWallet.meta b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/EmbeddedWallet.meta
new file mode 100644
index 000000000..43dff6b70
--- /dev/null
+++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/EmbeddedWallet.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 40e337b219833ea42a40af71b7671255
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/UI/FlexibleGridLayout.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/UI/FlexibleGridLayout.cs
deleted file mode 100644
index b5bb24b8d..000000000
--- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/UI/FlexibleGridLayout.cs
+++ /dev/null
@@ -1,198 +0,0 @@
-using UnityEngine;
-using UnityEngine.UI;
-
-// Lifted from https://github.com/rob1997/Controller/blob/main/Packages/com.ekaka.ui/Runtime/Common/FlexibleGridLayout.cs
-public class FlexibleGridLayout : LayoutGroup
-{
- public enum FitType
- {
- FixedRows,
- FixedColumns,
- }
-
- public new RectOffset padding = new RectOffset();
-
- public FitType fitType;
-
- public int rows;
- public int columns;
-
- public Vector2 cellSize;
- public Vector2 spacing;
-
- public bool fitX;
- public bool fitY;
-
- public bool centerX;
- public bool centerY;
-
- [Tooltip(
- "instead of using pixels for size, fit cell to anchor (percentage of screen size) - this makes layout more responsive")]
- public bool anchorFitX;
-
- [Tooltip("cell width will be calculated as a percentage of this Rect's width, if null we instead use Screen.width")]
- public RectTransform anchorRectX;
-
- [Tooltip(
- "instead of using pixels for size, fit cell to anchor (percentage of screen size) - this makes layout more responsive")]
- public bool anchorFitY;
-
- [Tooltip(
- "cell height will be calculated as a percentage of this Rect's height, if null we instead use Screen.height")]
- public RectTransform anchorRectY;
-
- [Tooltip("value is normalized (0 - 1), cell size as a percentage of screen size")]
- public Vector2 anchorCellSize;
-
- private int _childCount;
-
- public override void CalculateLayoutInputHorizontal()
- {
- base.CalculateLayoutInputHorizontal();
-
- switch (fitType)
- {
- case FitType.FixedRows:
- columns = Mathf.CeilToInt(transform.childCount / (float)rows);
- break;
- case FitType.FixedColumns:
- rows = Mathf.CeilToInt(transform.childCount / (float)columns);
- break;
- }
-
- Rect parentRect = rectTransform.rect;
-
- float parentWidth = parentRect.width;
- float parentHeight = parentRect.height;
-
- float cellWidth = (parentWidth - (spacing.x * (columns - 1)) - padding.left - padding.right) / (float)columns;
-
- float cellHeight = (parentHeight - (spacing.y * (rows - 1)) - padding.top - padding.bottom) / (float)rows;
-
- if (anchorRectX != null && anchorRectX.rect.width <= 0)
- {
- //can't ForceRebuildLayoutImmediate in case it's in another layout causing a circular dependency causing a stack overflow
- LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
-
- return;
- }
-
- float rectWidth = (float)Screen.width;
-
- if (fitX)
- cellSize.x = cellWidth;
-
- else
- {
- if (anchorFitX)
- {
- if (anchorRectX != null)
- {
- if (anchorRectX.rect.width <= 0)
- {
- //can't ForceRebuildLayoutImmediate in case it's in another layout causing a circular dependency causing a stack overflow
- LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
-
- return;
- }
-
- rectWidth = anchorRectX.rect.width;
- }
-
- cellSize.x = rectWidth * anchorCellSize.x;
- }
- }
-
- anchorCellSize.x = cellSize.x / rectWidth;
-
- float rectHeight = (float)Screen.height;
-
- if (fitY)
- cellSize.y = cellHeight;
-
- else
- {
- if (anchorFitY)
- {
- if (anchorRectY != null)
- {
- if (anchorRectY.rect.height <= 0)
- {
- //can't ForceRebuildLayoutImmediate in case it's in another layout causing a circular dependency causing a stack overflow
- LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
-
- return;
- }
-
- rectHeight = anchorRectY.rect.height;
- }
-
- cellSize.y = rectHeight * anchorCellSize.y;
- }
- }
-
- anchorCellSize.y = cellSize.y / rectHeight;
-
- int childrenCount = rectChildren.Count;
-
- for (int i = 0; i < childrenCount; i++)
- {
- int rowCount = i / columns;
- int columnCount = i % columns;
-
- RectTransform item = rectChildren[i];
-
- var xPos = (cellSize.x * columnCount) + (spacing.x * columnCount) + padding.left;
-
- if (centerX)
- {
- int itemsPerRow = rowCount + 1 == rows && childrenCount % columns != 0
- ? childrenCount % columns
- : columns;
-
- float spaceLeftOnRow = parentWidth - (cellSize.x * itemsPerRow) - (spacing.x * (itemsPerRow - 1)) -
- padding.left - padding.right;
- xPos += (float)spaceLeftOnRow / 2f;
- }
-
- var yPos = (cellSize.y * rowCount) + (spacing.y * rowCount) + padding.top;
-
- if (centerY)
- {
- float spaceLeftOnColumn = parentHeight - (cellSize.y * rows) - (spacing.y * (rows - 1)) - padding.top -
- padding.bottom;
- yPos += (float)spaceLeftOnColumn / 2f;
- }
-
- SetChildAlongAxis(item, 0, xPos, cellSize.x);
- SetChildAlongAxis(item, 1, yPos, cellSize.y);
- }
-
- //Set Preferred sizes
- SetLayoutInputForAxis(0, (cellSize.x * columns) + (spacing.x * (columns - 1)) + padding.left + padding.right, 0,
- 0);
- SetLayoutInputForAxis(0, (cellSize.y * rows) + (spacing.y * (rows - 1)) + padding.top + padding.bottom, 0, 1);
- }
-
- public override void CalculateLayoutInputVertical()
- {
- }
-
- public override void SetLayoutHorizontal()
- {
- }
-
- public override void SetLayoutVertical()
- {
- }
-
- private void Update()
- {
- //Whenever new element is added
- if (_childCount != transform.childCount)
- {
- LayoutRebuilder.ForceRebuildLayoutImmediate(rectTransform);
- _childCount = transform.childCount;
- }
- }
-}
\ No newline at end of file
diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/UI/FlexibleGridLayout.cs.meta b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/UI/FlexibleGridLayout.cs.meta
deleted file mode 100644
index 704d1c52c..000000000
--- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/UI/FlexibleGridLayout.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: b2bc2141c1169a5409308c3858911525
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/UI/Resizer.cs b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/UI/Resizer.cs
index 163c09dd5..a48d5d090 100644
--- a/Packages/io.chainsafe.web3-unity/Runtime/Scripts/UI/Resizer.cs
+++ b/Packages/io.chainsafe.web3-unity/Runtime/Scripts/UI/Resizer.cs
@@ -6,13 +6,9 @@ namespace ChainSafe.Gaming.UnityPackage.UI
///
/// Resizes a rect Transform responsively/based on percentage.
///
- [ExecuteInEditMode, RequireComponent(typeof(RectTransform))]
+ [RequireComponent(typeof(RectTransform))]
public class Resizer : MonoBehaviour
{
- [SerializeField] private bool executeInEditMode;
-
- [Space]
-
[SerializeField] private bool resizeWidth;
[SerializeField] private bool resizeHeight;
@@ -70,15 +66,5 @@ void ResizeAxis(RectTransform.Axis axis, float parent, float normalized, float t
_rectTransform.SetSizeWithCurrentAnchors(axis, target);
}
}
-
-#if UNITY_EDITOR
- private void Update()
- {
- if (executeInEditMode)
- {
- Resize();
- }
- }
-#endif
}
}
diff --git a/src/ChainSafe.Gaming.EmbeddedWallet/EmbeddedWalletExtensions.cs b/src/ChainSafe.Gaming.EmbeddedWallet/EmbeddedWalletExtensions.cs
index 4dc065e7c..90c231b8b 100644
--- a/src/ChainSafe.Gaming.EmbeddedWallet/EmbeddedWalletExtensions.cs
+++ b/src/ChainSafe.Gaming.EmbeddedWallet/EmbeddedWalletExtensions.cs
@@ -4,8 +4,17 @@
namespace ChainSafe.Gaming.EmbeddedWallet
{
+ ///
+ /// Extension methods for Embedded Wallet.
+ ///
public static class EmbeddedWalletExtensions
{
+ ///
+ /// Use Embedded Wallet as signer and transaction executor.
+ ///
+ /// Service collection to bind implementations to.
+ /// Configuration for the embedded wallet.
+ /// The same service collection that was passed in. This enables fluent style.
public static IWeb3ServiceCollection UseEmbeddedWallet(this IWeb3ServiceCollection services, IEmbeddedWalletConfig config)
{
services.AddSingleton(_ => config);
diff --git a/src/ChainSafe.Gaming.EmbeddedWallet/EmbeddedWalletTransaction.cs b/src/ChainSafe.Gaming.EmbeddedWallet/EmbeddedWalletTransaction.cs
index c7a0948ce..f4e9bf541 100644
--- a/src/ChainSafe.Gaming.EmbeddedWallet/EmbeddedWalletTransaction.cs
+++ b/src/ChainSafe.Gaming.EmbeddedWallet/EmbeddedWalletTransaction.cs
@@ -3,8 +3,15 @@
namespace ChainSafe.Gaming.EmbeddedWallet
{
+ ///
+ /// Transaction object for handling embedded wallet transactions.
+ ///
public class EmbeddedWalletTransaction
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Initial transaction request.
public EmbeddedWalletTransaction(TransactionRequest request)
{
Request = request;
@@ -12,8 +19,14 @@ public EmbeddedWalletTransaction(TransactionRequest request)
Response = new TaskCompletionSource();
}
+ ///
+ /// Initial Transaction Request.
+ ///
public TransactionRequest Request { get; private set; }
+ ///
+ /// Awaitable Transaction Response.
+ ///
public TaskCompletionSource Response { get; private set; }
}
}
\ No newline at end of file
diff --git a/src/ChainSafe.Gaming.EmbeddedWallet/EmbeddedWalletTransactionExecutor.cs b/src/ChainSafe.Gaming.EmbeddedWallet/EmbeddedWalletTransactionExecutor.cs
index 21987b9aa..0ea7f5dce 100644
--- a/src/ChainSafe.Gaming.EmbeddedWallet/EmbeddedWalletTransactionExecutor.cs
+++ b/src/ChainSafe.Gaming.EmbeddedWallet/EmbeddedWalletTransactionExecutor.cs
@@ -3,10 +3,14 @@
using ChainSafe.Gaming.Evm.Providers;
using ChainSafe.Gaming.Evm.Transactions;
using ChainSafe.Gaming.InProcessSigner;
+using ChainSafe.Gaming.Web3.Core.Evm;
using TransactionExecutor = ChainSafe.Gaming.InProcessTransactionExecutor.InProcessTransactionExecutor;
namespace ChainSafe.Gaming.EmbeddedWallet
{
+ ///
+ /// Implementation of for handling embedded wallet transactions.
+ ///
public class EmbeddedWalletTransactionExecutor : TransactionExecutor, IEmbeddedWalletTransactionHandler
{
private readonly TransactionPool transactionPool;
diff --git a/src/ChainSafe.Gaming.EmbeddedWallet/IEmbeddedWalletConfig.cs b/src/ChainSafe.Gaming.EmbeddedWallet/IEmbeddedWalletConfig.cs
index 04f227899..e9e97744a 100644
--- a/src/ChainSafe.Gaming.EmbeddedWallet/IEmbeddedWalletConfig.cs
+++ b/src/ChainSafe.Gaming.EmbeddedWallet/IEmbeddedWalletConfig.cs
@@ -1,7 +1,13 @@
namespace ChainSafe.Gaming.EmbeddedWallet
{
+ ///
+ /// Configuration for the Embedded Wallet.
+ ///
public interface IEmbeddedWalletConfig
{
+ ///
+ /// Automatically execute transactions without user approval.
+ ///
public bool AutoApproveTransactions { get; }
}
}
\ No newline at end of file
diff --git a/src/ChainSafe.Gaming.EmbeddedWallet/TransactionPool.cs b/src/ChainSafe.Gaming.EmbeddedWallet/TransactionPool.cs
index 7a77df45d..d635caf0f 100644
--- a/src/ChainSafe.Gaming.EmbeddedWallet/TransactionPool.cs
+++ b/src/ChainSafe.Gaming.EmbeddedWallet/TransactionPool.cs
@@ -5,6 +5,9 @@
namespace ChainSafe.Gaming.EmbeddedWallet
{
+ ///
+ /// Pool for managing embedded wallet transactions.
+ ///
public class TransactionPool
{
private readonly Dictionary transactions = new();
@@ -13,8 +16,16 @@ public class TransactionPool
private int Index => transactions.Keys.Min();
+ ///
+ /// Number of transactions in the pool.
+ ///
public int Count => transactions.Count;
+ ///
+ /// Add a new transaction to the pool.
+ ///
+ /// Initial Transaction Request.
+ /// Transaction for embedded wallet.
public EmbeddedWalletTransaction Enqueue(TransactionRequest request)
{
var transaction = new EmbeddedWalletTransaction(request);
@@ -24,13 +35,25 @@ public EmbeddedWalletTransaction Enqueue(TransactionRequest request)
return transaction;
}
+ ///
+ /// Get the next (oldest) transaction in the pool.
+ ///
+ /// Transaction to get.
public EmbeddedWalletTransaction Peek()
{
+ AssertTransaction();
+
return transactions[Index];
}
+ ///
+ /// Remove the next (oldest) transaction in the pool.
+ ///
+ /// Removed transaction.
public EmbeddedWalletTransaction Dequeue()
{
+ AssertTransaction();
+
var transaction = transactions[Index];
transactions.Remove(Index);
@@ -38,11 +61,11 @@ public EmbeddedWalletTransaction Dequeue()
return transaction;
}
- public void AssertTransaction(int index)
+ private void AssertTransaction()
{
- if (!transactions.ContainsKey(index))
+ if (Count.Equals(0))
{
- throw new Web3Exception("Transaction not found.");
+ throw new Web3Exception("Transaction pool empty.");
}
}
}
diff --git a/src/UnitySampleProject/Assets/Resources/Web3AuthConnectionProvider.asset b/src/UnitySampleProject/Assets/Resources/Web3AuthConnectionProvider.asset
index fcf59a13b..2474bc0b5 100644
--- a/src/UnitySampleProject/Assets/Resources/Web3AuthConnectionProvider.asset
+++ b/src/UnitySampleProject/Assets/Resources/Web3AuthConnectionProvider.asset
@@ -14,9 +14,12 @@ MonoBehaviour:
m_EditorClassIdentifier:
k__BackingField: {fileID: 21300000, guid: 402d42d6692b5e3498f900fe29e10a89, type: 3}
k__BackingField: Web3Auth
- clientId: BIYV6RYoZYbQ8VulPi65LoJMXQisHcTKQ296pOstx4LmzOp9HN3LR1tfAeaM3DMuN6c3AHEvvcMFLEE6lnuefAQ
- redirectUri: torusapp://io.chainsafe.gamingsdk.sdkdemoscene/auth
- network: 1
+ k__BackingField: ChainSafe Gaming SDK
+ k__BackingField: BIYV6RYoZYbQ8VulPi65LoJMXQisHcTKQ296pOstx4LmzOp9HN3LR1tfAeaM3DMuN6c3AHEvvcMFLEE6lnuefAQ
+ k__BackingField: torusapp://io.chainsafe.gamingsdk.sdkdemoscene/auth
+ k__BackingField: 1
+ k__BackingField: 1
+ k__BackingField: 0
modalScreenFactory:
LandscapePrefab: {fileID: 4903352956951587407, guid: 9e5f859444d8b4a448e79b28a6033fd7, type: 3}
PortraitPrefab: {fileID: 7393159509175253276, guid: 5ed2d6739dc24144cb021a0cb4bd8178, type: 3}