这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -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);
}
}
});

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>
/// A controller script for side-loaded browser games and making awaitable JsonRPC requests.
/// </summary>
public class HyperPlayController : MonoBehaviour
{
[DllImport("__Internal")]
public static extern string Request(string message, string gameObjectName, string callback, string fallback);

private readonly Dictionary<string, TaskCompletionSource<RpcResponseMessage>> _requestTcsMap = new Dictionary<string, TaskCompletionSource<RpcResponseMessage>>();

/// <summary>
/// Make JsonRPC request to the HyperPlay side-loaded browser games on HyperPlay desktop client.
/// </summary>
/// <param name="method">JsonRPC method name.</param>
/// <param name="parameters">JsonRPC request parameters.</param>
/// <returns>Rpc Response.</returns>
public Task<RpcResponseMessage> 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<RpcResponseMessage>();

_requestTcsMap.Add(id, requestTcs);

Request(message, gameObject.name, nameof(Response), nameof(RequestError));

return requestTcs.Task;
}

/// <summary>
/// JsonRPC Response callback.
/// </summary>
/// <param name="result">Response Result string.</param>
/// <exception cref="Web3Exception">Throws Exception if response has errors.</exception>
public void Response(string result)
{
var response = JsonConvert.DeserializeObject<RpcResponseMessage>(result);

if (_requestTcsMap.TryGetValue(response.Id.ToString(), out TaskCompletionSource<RpcResponseMessage> requestTcs))
{
if (!requestTcs.TrySetResult(response))
{
requestTcs.SetException(new Web3Exception("Error setting result."));
}
}

else
{
throw new Web3Exception("Can't find Request Task.");
}
}

/// <summary>
/// Request Error callback.
/// </summary>
/// <param name="error">Error message.</param>
/// <exception cref="Web3Exception">Throws exception if setting error fails.</exception>
public void RequestError(string error)
{
var response = JsonConvert.DeserializeObject<RpcResponseMessage>(error);

if (_requestTcsMap.TryGetValue(response.Id.ToString(), out TaskCompletionSource<RpcResponseMessage> 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.");
}
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>
/// Concrete implementation of <see cref="HyperPlayProvider"/> for side-loaded browser games on HyperPlay desktop client.
/// </summary>
public class HyperPlayWebGLProvider : HyperPlayProvider
{
private readonly IHyperPlayConfig _config;
private readonly IHyperPlayData _data;
private readonly DataStorage _dataStorage;
private readonly HyperPlayController _hyperPlayController;

/// <summary>
/// Initializes a new instance of the <see cref="HyperPlayWebGLProvider"/> class.
/// </summary>
/// <param name="config">Injected <see cref="HyperPlayConfig"/>.</param>
/// <param name="data">Injected <see cref="IHyperPlayData"/>.</param>
/// <param name="dataStorage">Injected <see cref="DataStorage"/>.</param>
/// <param name="httpClient">HttpClient to make requests.</param>
/// <param name="chainConfig">ChainConfig to fetch chain data.</param>
/// <param name="chainRegistryProvider">Injected <see cref="ChainRegistryProvider"/>.</param>
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<HyperPlayController>();

if (_hyperPlayController == null)
{
GameObject controllerObj = new GameObject(nameof(HyperPlayController), typeof(HyperPlayController));

_hyperPlayController = controllerObj.GetComponent<HyperPlayController>();
}

Object.DontDestroyOnLoad(_hyperPlayController.gameObject);
}

/// <summary>
/// Connect to wallet from a side-loaded browser game via HyperPlay desktop client and return the account address.
/// </summary>
/// <returns>Signed-in account public address.</returns>
public override async Task<string> Connect()
{
string[] accounts = await Perform<string[]>("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;
}

/// <summary>
/// Make RPC request on HyperPlay desktop client.
/// </summary>
/// <param name="method">RPC request method name.</param>
/// <param name="parameters">RPC request parameters.</param>
/// <typeparam name="T">RPC request response type.</typeparam>
/// <returns>RPC request Response.</returns>
public override async Task<T> Perform<T>(string method, params object[] parameters)
{
var response = await _hyperPlayController.Request(method, parameters);

return response.Result.ToObject<T>();
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 14 additions & 5 deletions src/ChainSafe.Gaming.HyperPlay/HyperPlayExtensions.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -19,6 +15,19 @@ public static class HyperPlayExtensions
/// <param name="config">Config for connecting via HyperPlay.</param>
/// <returns>The same service collection that was passed in. This enables fluent style.</returns>
public static IWeb3ServiceCollection UseHyperPlay(this IWeb3ServiceCollection collection, IHyperPlayConfig config)
{
return collection.UseHyperPlay<HyperPlayProvider>(config);
}

/// <summary>
/// Binds implementation of <see cref="IWalletProvider"/> as <see cref="T"/> to Web3 as a service.
/// </summary>
/// <param name="collection">Service collection to bind implementations to.</param>
/// <param name="config">Config for connecting via HyperPlay.</param>
/// <typeparam name="T">Type of <see cref="HyperPlayProvider"/>.</typeparam>
/// <returns>The same service collection that was passed in. This enables fluent style.</returns>
public static IWeb3ServiceCollection UseHyperPlay<T>(this IWeb3ServiceCollection collection, IHyperPlayConfig config)
where T : HyperPlayProvider
{
collection.AssertServiceNotBound<IHyperPlayData>();

Expand All @@ -28,7 +37,7 @@ public static IWeb3ServiceCollection UseHyperPlay(this IWeb3ServiceCollection co

collection.Replace(ServiceDescriptor.Singleton(typeof(IHyperPlayConfig), config));

collection.UseWalletProvider<HyperPlayProvider>(config);
collection.UseWalletProvider<T>(config);

return collection;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<HyperPlayWebGLProvider>(config);
#else
services.UseHyperPlay(config);
#endif
services.UseWalletSigner().UseWalletTransactionExecutor();
});
}

Expand Down