diff --git a/Packages/io.chainsafe.web3-unity.hyperplay/Runtime/Plugins.meta b/Packages/io.chainsafe.web3-unity.hyperplay/Runtime/Plugins.meta
new file mode 100644
index 000000000..b43dfb8c9
--- /dev/null
+++ b/Packages/io.chainsafe.web3-unity.hyperplay/Runtime/Plugins.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 573bc83104efa7646bca1108f5feaa20
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Packages/io.chainsafe.web3-unity.hyperplay/Runtime/Plugins/EthereumWindow.jslib b/Packages/io.chainsafe.web3-unity.hyperplay/Runtime/Plugins/EthereumWindow.jslib
new file mode 100644
index 000000000..6be9dd2c2
--- /dev/null
+++ b/Packages/io.chainsafe.web3-unity.hyperplay/Runtime/Plugins/EthereumWindow.jslib
@@ -0,0 +1,36 @@
+mergeInto(LibraryManager.library, {
+ Request: async function (message, gameObjectName, callback, fallback) {
+ const parsedObjectName = UTF8ToString(gameObjectName);
+ const parsedCallback = UTF8ToString(callback);
+ const parsedFallback = UTF8ToString(fallback);
+ let request = JSON.parse(UTF8ToString(message));
+ try
+ {
+ const response = await window.ethereum.request(request);
+ let rpcResponse =
+ {
+ jsonrpc: "2.0",
+ result: response,
+ id: request.id,
+ error: null
+ }
+
+ var json = JSON.stringify(rpcResponse);
+ nethereumUnityInstance.SendMessage(parsedObjectName, parsedCallback, json);
+ }
+ catch(e)
+ {
+ let rpcResponse =
+ {
+ jsonrpc: "2.0",
+ id: request.id,
+ error:
+ {
+ message: e.message
+ }
+ }
+ var json = JSON.stringify(rpcResponse);
+ nethereumUnityInstance.SendMessage(parsedObjectName, parsedFallback, json);
+ }
+ }
+});
\ No newline at end of file
diff --git a/Packages/io.chainsafe.web3-unity.hyperplay/Runtime/Plugins/EthereumWindow.jslib.meta b/Packages/io.chainsafe.web3-unity.hyperplay/Runtime/Plugins/EthereumWindow.jslib.meta
new file mode 100644
index 000000000..7b9a54aee
--- /dev/null
+++ b/Packages/io.chainsafe.web3-unity.hyperplay/Runtime/Plugins/EthereumWindow.jslib.meta
@@ -0,0 +1,32 @@
+fileFormatVersion: 2
+guid: 6f07ffb4f5724d94f9015b3a22dfa5b7
+PluginImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ iconMap: {}
+ executionOrder: {}
+ defineConstraints: []
+ isPreloaded: 0
+ isOverridable: 1
+ isExplicitlyReferenced: 0
+ validateReferences: 1
+ platformData:
+ - first:
+ Any:
+ second:
+ enabled: 0
+ settings: {}
+ - first:
+ Editor: Editor
+ second:
+ enabled: 0
+ settings:
+ DefaultValueInitialized: true
+ - first:
+ WebGL: WebGL
+ second:
+ enabled: 1
+ settings: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Packages/io.chainsafe.web3-unity.hyperplay/Runtime/Scripts/HyperPlayController.cs b/Packages/io.chainsafe.web3-unity.hyperplay/Runtime/Scripts/HyperPlayController.cs
new file mode 100644
index 000000000..eda2a9a97
--- /dev/null
+++ b/Packages/io.chainsafe.web3-unity.hyperplay/Runtime/Scripts/HyperPlayController.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+using ChainSafe.Gaming.Web3;
+using Nethereum.JsonRpc.Client.RpcMessages;
+using Newtonsoft.Json;
+using UnityEngine;
+
+namespace ChainSafe.Gaming.HyperPlay
+{
+ ///
+ /// A controller script for side-loaded browser games and making awaitable JsonRPC requests.
+ ///
+ public class HyperPlayController : MonoBehaviour
+ {
+ [DllImport("__Internal")]
+ public static extern string Request(string message, string gameObjectName, string callback, string fallback);
+
+ private readonly Dictionary> _requestTcsMap = new Dictionary>();
+
+ ///
+ /// Make JsonRPC request to the HyperPlay side-loaded browser games on HyperPlay desktop client.
+ ///
+ /// JsonRPC method name.
+ /// JsonRPC request parameters.
+ /// Rpc Response.
+ public Task Request(string method, params object[] parameters)
+ {
+ string id = Guid.NewGuid().ToString();
+
+ var request = new RpcRequestMessage(id, method, parameters);
+
+ string message = JsonConvert.SerializeObject(request);
+
+ var requestTcs = new TaskCompletionSource();
+
+ _requestTcsMap.Add(id, requestTcs);
+
+ Request(message, gameObject.name, nameof(Response), nameof(RequestError));
+
+ return requestTcs.Task;
+ }
+
+ ///
+ /// JsonRPC Response callback.
+ ///
+ /// Response Result string.
+ /// Throws Exception if response has errors.
+ public void Response(string result)
+ {
+ var response = JsonConvert.DeserializeObject(result);
+
+ if (_requestTcsMap.TryGetValue(response.Id.ToString(), out TaskCompletionSource requestTcs))
+ {
+ if (!requestTcs.TrySetResult(response))
+ {
+ requestTcs.SetException(new Web3Exception("Error setting result."));
+ }
+ }
+
+ else
+ {
+ throw new Web3Exception("Can't find Request Task.");
+ }
+ }
+
+ ///
+ /// Request Error callback.
+ ///
+ /// Error message.
+ /// Throws exception if setting error fails.
+ public void RequestError(string error)
+ {
+ var response = JsonConvert.DeserializeObject(error);
+
+ if (_requestTcsMap.TryGetValue(response.Id.ToString(), out TaskCompletionSource requestTcs))
+ {
+ if (!requestTcs.TrySetException(new Web3Exception(response.Error.Message)))
+ {
+ requestTcs.SetException(new Web3Exception($"Error setting error: {response.Error.Message}"));
+ }
+ }
+
+ else
+ {
+ throw new Web3Exception("Can't find request Task.");
+ }
+ }
+ }
+}
diff --git a/Packages/io.chainsafe.web3-unity.hyperplay/Runtime/Scripts/HyperPlayController.cs.meta b/Packages/io.chainsafe.web3-unity.hyperplay/Runtime/Scripts/HyperPlayController.cs.meta
new file mode 100644
index 000000000..b7f2d1454
--- /dev/null
+++ b/Packages/io.chainsafe.web3-unity.hyperplay/Runtime/Scripts/HyperPlayController.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: dd065f9f0732b2c44b758fa81040b54e
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Packages/io.chainsafe.web3-unity.hyperplay/Runtime/Scripts/HyperPlayWebGLProvider.cs b/Packages/io.chainsafe.web3-unity.hyperplay/Runtime/Scripts/HyperPlayWebGLProvider.cs
new file mode 100644
index 000000000..054fc736e
--- /dev/null
+++ b/Packages/io.chainsafe.web3-unity.hyperplay/Runtime/Scripts/HyperPlayWebGLProvider.cs
@@ -0,0 +1,90 @@
+using System.Threading.Tasks;
+using ChainSafe.Gaming.Evm;
+using ChainSafe.Gaming.LocalStorage;
+using ChainSafe.Gaming.Web3;
+using ChainSafe.Gaming.Web3.Environment;
+using UnityEngine;
+
+namespace ChainSafe.Gaming.HyperPlay
+{
+ ///
+ /// Concrete implementation of for side-loaded browser games on HyperPlay desktop client.
+ ///
+ public class HyperPlayWebGLProvider : HyperPlayProvider
+ {
+ private readonly IHyperPlayConfig _config;
+ private readonly IHyperPlayData _data;
+ private readonly DataStorage _dataStorage;
+ private readonly HyperPlayController _hyperPlayController;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Injected .
+ /// Injected .
+ /// Injected .
+ /// HttpClient to make requests.
+ /// ChainConfig to fetch chain data.
+ /// Injected .
+ public HyperPlayWebGLProvider(IHyperPlayConfig config, IHyperPlayData data, DataStorage dataStorage, IHttpClient httpClient, IChainConfig chainConfig, ChainRegistryProvider chainRegistryProvider) : base(config, data, dataStorage, httpClient, chainConfig, chainRegistryProvider)
+ {
+ _config = config;
+ _data = data;
+ _dataStorage = dataStorage;
+
+ // Initialize Unity controller.
+ _hyperPlayController = Object.FindObjectOfType();
+
+ if (_hyperPlayController == null)
+ {
+ GameObject controllerObj = new GameObject(nameof(HyperPlayController), typeof(HyperPlayController));
+
+ _hyperPlayController = controllerObj.GetComponent();
+ }
+
+ Object.DontDestroyOnLoad(_hyperPlayController.gameObject);
+ }
+
+ ///
+ /// Connect to wallet from a side-loaded browser game via HyperPlay desktop client and return the account address.
+ ///
+ /// Signed-in account public address.
+ public override async Task Connect()
+ {
+ string[] accounts = await Perform("eth_requestAccounts");
+
+ string account = accounts[0];
+
+ // Saved account exists.
+ if (_data.RememberSession)
+ {
+ return account;
+ }
+
+ if (_config.RememberSession)
+ {
+ _data.RememberSession = true;
+
+ _data.SavedAccount = account;
+
+ await _dataStorage.Save(_data);
+ }
+
+ return account;
+ }
+
+ ///
+ /// Make RPC request on HyperPlay desktop client.
+ ///
+ /// RPC request method name.
+ /// RPC request parameters.
+ /// RPC request response type.
+ /// RPC request Response.
+ public override async Task Perform(string method, params object[] parameters)
+ {
+ var response = await _hyperPlayController.Request(method, parameters);
+
+ return response.Result.ToObject();
+ }
+ }
+}
diff --git a/Packages/io.chainsafe.web3-unity.hyperplay/Runtime/Scripts/HyperPlayWebGLProvider.cs.meta b/Packages/io.chainsafe.web3-unity.hyperplay/Runtime/Scripts/HyperPlayWebGLProvider.cs.meta
new file mode 100644
index 000000000..67877e92b
--- /dev/null
+++ b/Packages/io.chainsafe.web3-unity.hyperplay/Runtime/Scripts/HyperPlayWebGLProvider.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: bf3150495260dda4db527f68c58bcafc
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/src/ChainSafe.Gaming.HyperPlay/HyperPlayExtensions.cs b/src/ChainSafe.Gaming.HyperPlay/HyperPlayExtensions.cs
index f1fde1cb0..4508ab6bc 100644
--- a/src/ChainSafe.Gaming.HyperPlay/HyperPlayExtensions.cs
+++ b/src/ChainSafe.Gaming.HyperPlay/HyperPlayExtensions.cs
@@ -1,9 +1,5 @@
-using ChainSafe.Gaming.Evm.Signers;
using ChainSafe.Gaming.LocalStorage;
using ChainSafe.Gaming.Web3.Build;
-using ChainSafe.Gaming.Web3.Core;
-using ChainSafe.Gaming.Web3.Core.Evm;
-using ChainSafe.Gaming.Web3.Core.Logout;
using ChainSafe.Gaming.Web3.Evm.Wallet;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
@@ -19,6 +15,19 @@ public static class HyperPlayExtensions
/// Config for connecting via HyperPlay.
/// The same service collection that was passed in. This enables fluent style.
public static IWeb3ServiceCollection UseHyperPlay(this IWeb3ServiceCollection collection, IHyperPlayConfig config)
+ {
+ return collection.UseHyperPlay(config);
+ }
+
+ ///
+ /// Binds implementation of as to Web3 as a service.
+ ///
+ /// Service collection to bind implementations to.
+ /// Config for connecting via HyperPlay.
+ /// Type of .
+ /// The same service collection that was passed in. This enables fluent style.
+ public static IWeb3ServiceCollection UseHyperPlay(this IWeb3ServiceCollection collection, IHyperPlayConfig config)
+ where T : HyperPlayProvider
{
collection.AssertServiceNotBound();
@@ -28,7 +37,7 @@ public static IWeb3ServiceCollection UseHyperPlay(this IWeb3ServiceCollection co
collection.Replace(ServiceDescriptor.Singleton(typeof(IHyperPlayConfig), config));
- collection.UseWalletProvider(config);
+ collection.UseWalletProvider(config);
return collection;
}
diff --git a/src/UnitySampleProject/Assets/Samples/web3.unity SDK HyperPlay/1.0.0/Web3.Unity HyperPlay Samples/Scripts/HyperPlayLoginProvider.cs b/src/UnitySampleProject/Assets/Samples/web3.unity SDK HyperPlay/1.0.0/Web3.Unity HyperPlay Samples/Scripts/HyperPlayLoginProvider.cs
index f71ba2bad..93263321f 100644
--- a/src/UnitySampleProject/Assets/Samples/web3.unity SDK HyperPlay/1.0.0/Web3.Unity HyperPlay Samples/Scripts/HyperPlayLoginProvider.cs
+++ b/src/UnitySampleProject/Assets/Samples/web3.unity SDK HyperPlay/1.0.0/Web3.Unity HyperPlay Samples/Scripts/HyperPlayLoginProvider.cs
@@ -44,10 +44,16 @@ public Web3Builder ConfigureServices(Web3Builder web3Builder)
{
return web3Builder.Configure(services =>
{
- services.UseHyperPlay(new HyperPlayConfig
+ var config = new HyperPlayConfig
{
RememberSession = rememberMeToggle.isOn || _storedSessionAvailable,
- }).UseWalletSigner().UseWalletTransactionExecutor();
+ };
+#if UNITY_WEBGL && !UNITY_EDITOR
+ services.UseHyperPlay(config);
+#else
+ services.UseHyperPlay(config);
+#endif
+ services.UseWalletSigner().UseWalletTransactionExecutor();
});
}