diff --git a/Assets/Dojo/Plugins/iOS/libdojo_c.a b/Assets/Dojo/Plugins/iOS/libdojo_c.a index 0a10292a..e29687c2 100644 --- a/Assets/Dojo/Plugins/iOS/libdojo_c.a +++ b/Assets/Dojo/Plugins/iOS/libdojo_c.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c3545dc9d7cd4af28b8bf0cd7a5ae8639973bb7d577e7622097de2f513930195 -size 144244704 +oid sha256:814409d4b9345041f772e8008ebbc9597c9a77108986fe8a7721ad8f4d938c11 +size 98288592 diff --git a/Assets/Dojo/Plugins/iOS/libdojo_c.dylib b/Assets/Dojo/Plugins/iOS/libdojo_c.dylib deleted file mode 100755 index f30b263c..00000000 Binary files a/Assets/Dojo/Plugins/iOS/libdojo_c.dylib and /dev/null differ diff --git a/Assets/Dojo/Runtime/Starknet/StarknetInterop.cs b/Assets/Dojo/Runtime/Starknet/StarknetInterop.cs index 38989d62..134b984d 100644 --- a/Assets/Dojo/Runtime/Starknet/StarknetInterop.cs +++ b/Assets/Dojo/Runtime/Starknet/StarknetInterop.cs @@ -12,234 +12,334 @@ namespace Dojo.Starknet { - public class StarknetInterop + public class StarknetInterop + { +#if UNITY_IOS + // Stub implementations for non-WebGL platforms + public static IntPtr NewProvider(CString nodeUrl) { - [DllImport("__Internal")] - public static extern IntPtr NewProvider(CString nodeUrl); + Debug.LogWarning("NewProvider called on non-WebGL platform."); + return IntPtr.Zero; + } - [DllImport("__Internal")] - public static extern IntPtr NewAccount(IntPtr provider, CString privateKey, CString address, Action cb); + public static IntPtr NewAccount(IntPtr provider, CString privateKey, CString address, Action cb) + { + Debug.LogWarning("NewAccount called on non-WebGL platform."); + cb(IntPtr.Zero); + return IntPtr.Zero; + } - public class NewAccountHelper - { - public static TaskCompletionSource Tcs; + public static string AccountAddress(IntPtr account) + { + Debug.LogWarning("AccountAddress called on non-WebGL platform."); + return "0x0"; + } - [MonoPInvokeCallback(typeof(Action))] - public static void Callback(IntPtr result) - { - Tcs.SetResult(result); - } - } + public static string AccountChainId(IntPtr account) + { + Debug.LogWarning("AccountChainId called on non-WebGL platform."); + return "0x0"; + } - public static Task NewAccountAsync(IntPtr provider, SigningKey privateKey, FieldElement address) - { - NewAccountHelper.Tcs = new TaskCompletionSource(); - NewAccount(provider, new CString(privateKey.Inner.Hex()), new CString(address.Hex()), NewAccountHelper.Callback); - return NewAccountHelper.Tcs.Task; - } + public static void AccountNonce(IntPtr account, Action cb) + { + Debug.LogWarning("AccountNonce called on non-WebGL platform."); + cb("0x0"); + } - [DllImport("__Internal")] - public static extern string AccountAddress(IntPtr account); + public static void AccountExecuteRaw(IntPtr account, CString calls, Action cb) + { + Debug.LogWarning("AccountExecuteRaw called on non-WebGL platform."); + cb("0x0"); + } - [DllImport("__Internal")] - public static extern string AccountChainId(IntPtr account); + public static void AccountDeployBurner(IntPtr account, CString privateKey, Action cb) + { + Debug.LogWarning("AccountDeployBurner called on non-WebGL platform."); + cb(IntPtr.Zero); + } - [DllImport("__Internal")] - public static extern void AccountNonce(IntPtr account, Action cb); + public static void Call(IntPtr provider, CString call, CString blockId, Action cb) + { + Debug.LogWarning("Call called on non-WebGL platform."); + cb("[]"); + } - public class AccountNonceHelper - { - public static TaskCompletionSource Tcs; + public static void WaitForTransaction(IntPtr provider, CString transactionHash, Action cb) + { + Debug.LogWarning("WaitForTransaction called on non-WebGL platform."); + cb(false); + } - [MonoPInvokeCallback(typeof(Action))] - public static void Callback(string result) - { - Tcs.SetResult(new FieldElement(result)); - } - } + public static string NewSigningKey() + { + Debug.LogWarning("NewSigningKey called on non-WebGL platform."); + return "0x0"; + } - public static Task AccountNonceAsync(IntPtr account) - { - AccountNonceHelper.Tcs = new TaskCompletionSource(); - AccountNonce(account, AccountNonceHelper.Callback); - return AccountNonceHelper.Tcs.Task; - } + public static string Sign(CString privateKey, CString hash) + { + Debug.LogWarning("Sign called on non-WebGL platform."); + return "0x0"; + } - [DllImport("__Internal")] - public static extern void AccountExecuteRaw(IntPtr account, CString calls, Action cb); + public static string NewVerifyingKey(CString privateKey) + { + Debug.LogWarning("NewVerifyingKey called on non-WebGL platform."); + return "0x0"; + } - public class AccountExecuteRawHelper - { - public static TaskCompletionSource Tcs; + public static bool Verify(CString publicKey, CString hash, CString r, CString s) + { + Debug.LogWarning("Verify called on non-WebGL platform."); + return false; + } - [MonoPInvokeCallback(typeof(Action))] - public static void Callback(string result) - { - Tcs.SetResult(new FieldElement(result)); - } - } + private static string SerializeByteArray(CString byteArray) + { + Debug.LogWarning("SerializeByteArray called on non-WebGL platform."); + return "[]"; + } - struct SerializedCall - { - public SerializedCall(FieldElement to, string selector, FieldElement[] calldata) - { - this.to = to.Hex(); - this.selector = selector; - this.calldata = calldata.Select(f => f.Hex()).ToArray(); - } + private static string DeserializeByteArray(CString felts) + { + Debug.LogWarning("DeserializeByteArray called on non-WebGL platform."); + return ""; + } - // hex string of address - public string to; - // the unhashed selector - public string selector; - // array of hex strings - public string[] calldata; - } + public static string PoseidonHash(CString str) + { + Debug.LogWarning("PoseidonHash called on non-WebGL platform."); + return "0x0"; + } +#else + [DllImport("__Internal")] + public static extern IntPtr NewProvider(CString nodeUrl); - class SerializedBlockId - { - public static object Serialize(dojo.BlockId blockId) - { - return blockId.tag switch - { - dojo.BlockId_Tag.Hash => new BlockIdHash { Hash = new FieldElement(blockId.hash).Hex() }, - dojo.BlockId_Tag.Number => new BlockIdNumber { Number = blockId.number.ToString() }, - dojo.BlockId_Tag.BlockTag_ => new BlockIdTag - { - BlockTag = blockId.block_tag switch - { - dojo.BlockTag.Latest => "Latest", - dojo.BlockTag.Pending => "Pending", - _ => throw new Exception("Unknown block tag") - } - }, - _ => throw new Exception("Unknown block id type") - }; - } + [DllImport("__Internal")] + public static extern IntPtr NewAccount(IntPtr provider, CString privateKey, CString address, Action cb); - public struct BlockIdHash - { - public string Hash; - } + [DllImport("__Internal")] + public static extern string AccountAddress(IntPtr account); - public struct BlockIdNumber - { - public string Number; - } + [DllImport("__Internal")] + public static extern string AccountChainId(IntPtr account); - public struct BlockIdTag - { - public string BlockTag; - } - } + [DllImport("__Internal")] + public static extern void AccountNonce(IntPtr account, Action cb); - public static Task AccountExecuteRawAsync(IntPtr account, dojo.Call[] calls) - { - AccountExecuteRawHelper.Tcs = new TaskCompletionSource(); - AccountExecuteRaw(account, new CString(JsonConvert.SerializeObject(calls.Select(call => new SerializedCall(new FieldElement(call.to), call.selector, call.calldata.ToArray().Select(f => new FieldElement(f)).ToArray())).ToArray())), AccountExecuteRawHelper.Callback); - return AccountExecuteRawHelper.Tcs.Task; - } + [DllImport("__Internal")] + public static extern void AccountExecuteRaw(IntPtr account, CString calls, Action cb); - [DllImport("__Internal")] - public static extern void AccountDeployBurner(IntPtr account, CString privateKey, Action cb); + [DllImport("__Internal")] + public static extern void AccountDeployBurner(IntPtr account, CString privateKey, Action cb); - public class AccountDeployBurnerHelper - { - public static TaskCompletionSource Tcs; + [DllImport("__Internal")] + public static extern void Call(IntPtr provider, CString call, CString blockId, Action cb); - [MonoPInvokeCallback(typeof(Action))] - public static void Callback(IntPtr result) - { - Tcs.SetResult(result); - } - } + [DllImport("__Internal")] + public static extern void WaitForTransaction(IntPtr provider, CString transactionHash, Action cb); - public static Task AccountDeployBurnerAsync(IntPtr account, SigningKey signingKey) - { - AccountDeployBurnerHelper.Tcs = new TaskCompletionSource(); - AccountDeployBurner(account, new CString(signingKey.Inner.Hex()), AccountDeployBurnerHelper.Callback); - return AccountDeployBurnerHelper.Tcs.Task; - } + [DllImport("__Internal")] + public static extern string NewSigningKey(); - [DllImport("__Internal")] - public static extern void Call(IntPtr provider, CString call, CString blockId, Action cb); + [DllImport("__Internal")] + public static extern string Sign(CString privateKey, CString hash); - public class CallHelper - { - public static TaskCompletionSource Tcs; + [DllImport("__Internal")] + public static extern string NewVerifyingKey(CString privateKey); - [MonoPInvokeCallback(typeof(Action))] - public static void Callback(string result) - { - Tcs.SetResult(JsonConvert.DeserializeObject(result).Select(f => new FieldElement(f)).ToArray()); - } - } + [DllImport("__Internal")] + public static extern bool Verify(CString publicKey, CString hash, CString r, CString s); - public static Task CallAsync(IntPtr provider, dojo.Call call, dojo.BlockId blockId) - { - WaitForTransactionHelper.Tcs = new TaskCompletionSource(); - var serializedCall = new SerializedCall(new FieldElement(call.to), call.selector, call.calldata.ToArray().Select(f => new FieldElement(f)).ToArray()); - object serializedBlockId = SerializedBlockId.Serialize(blockId); + [DllImport("__Internal")] + private static extern string SerializeByteArray(CString byteArray); - Call(provider, new CString(JsonConvert.SerializeObject(serializedCall)), new CString(JsonConvert.SerializeObject(serializedBlockId)), CallHelper.Callback); - return CallHelper.Tcs.Task; - } + [DllImport("__Internal")] + private static extern string DeserializeByteArray(CString felts); - [DllImport("__Internal")] - public static extern void WaitForTransaction(IntPtr provider, CString transactionHash, Action cb); + [DllImport("__Internal")] + public static extern string PoseidonHash(CString str); +#endif - public class WaitForTransactionHelper - { - public static TaskCompletionSource Tcs; + public class NewAccountHelper + { + public static TaskCompletionSource Tcs; + + [MonoPInvokeCallback(typeof(Action))] + public static void Callback(IntPtr result) + { + Tcs.SetResult(result); + } + } + + public static Task NewAccountAsync(IntPtr provider, SigningKey privateKey, FieldElement address) + { + NewAccountHelper.Tcs = new TaskCompletionSource(); + NewAccount(provider, new CString(privateKey.Inner.Hex()), new CString(address.Hex()), NewAccountHelper.Callback); + return NewAccountHelper.Tcs.Task; + } + + public class AccountNonceHelper + { + public static TaskCompletionSource Tcs; + + [MonoPInvokeCallback(typeof(Action))] + public static void Callback(string result) + { + Tcs.SetResult(new FieldElement(result)); + } + } + + public static Task AccountNonceAsync(IntPtr account) + { + AccountNonceHelper.Tcs = new TaskCompletionSource(); + AccountNonce(account, AccountNonceHelper.Callback); + return AccountNonceHelper.Tcs.Task; + } + + public class AccountExecuteRawHelper + { + public static TaskCompletionSource Tcs; + + [MonoPInvokeCallback(typeof(Action))] + public static void Callback(string result) + { + Tcs.SetResult(new FieldElement(result)); + } + } - [MonoPInvokeCallback(typeof(Action))] - public static void Callback(bool result) + struct SerializedCall + { + public SerializedCall(FieldElement to, string selector, FieldElement[] calldata) + { + this.to = to.Hex(); + this.selector = selector; + this.calldata = calldata.Select(f => f.Hex()).ToArray(); + } + + // hex string of address + public string to; + // the unhashed selector + public string selector; + // array of hex strings + public string[] calldata; + } + + class SerializedBlockId + { + public static object Serialize(dojo.BlockId blockId) + { + return blockId.tag switch + { + dojo.BlockId_Tag.Hash => new BlockIdHash { Hash = new FieldElement(blockId.hash).Hex() }, + dojo.BlockId_Tag.Number => new BlockIdNumber { Number = blockId.number.ToString() }, + dojo.BlockId_Tag.BlockTag_ => new BlockIdTag + { + BlockTag = blockId.block_tag switch { - Tcs.SetResult(result); + dojo.BlockTag.Latest => "Latest", + dojo.BlockTag.Pending => "Pending", + _ => throw new Exception("Unknown block tag") } - } + }, + _ => throw new Exception("Unknown block id type") + }; + } + + public struct BlockIdHash + { + public string Hash; + } + + public struct BlockIdNumber + { + public string Number; + } + + public struct BlockIdTag + { + public string BlockTag; + } + } - public static Task WaitForTransactionAsync(IntPtr provider, FieldElement transactionHash) - { - WaitForTransactionHelper.Tcs = new TaskCompletionSource(); - WaitForTransaction(provider, new CString(transactionHash.Hex()), WaitForTransactionHelper.Callback); - return WaitForTransactionHelper.Tcs.Task; - } + public static Task AccountExecuteRawAsync(IntPtr account, dojo.Call[] calls) + { + AccountExecuteRawHelper.Tcs = new TaskCompletionSource(); + AccountExecuteRaw(account, new CString(JsonConvert.SerializeObject(calls.Select(call => new SerializedCall(new FieldElement(call.to), call.selector, call.calldata.ToArray().Select(f => new FieldElement(f)).ToArray())).ToArray())), AccountExecuteRawHelper.Callback); + return AccountExecuteRawHelper.Tcs.Task; + } - [DllImport("__Internal")] - public static extern string NewSigningKey(); + public class AccountDeployBurnerHelper + { + public static TaskCompletionSource Tcs; - [DllImport("__Internal")] - public static extern string Sign(CString privateKey, CString hash); + [MonoPInvokeCallback(typeof(Action))] + public static void Callback(IntPtr result) + { + Tcs.SetResult(result); + } + } - [DllImport("__Internal")] - public static extern string NewVerifyingKey(CString privateKey); + public static Task AccountDeployBurnerAsync(IntPtr account, SigningKey signingKey) + { + AccountDeployBurnerHelper.Tcs = new TaskCompletionSource(); + AccountDeployBurner(account, new CString(signingKey.Inner.Hex()), AccountDeployBurnerHelper.Callback); + return AccountDeployBurnerHelper.Tcs.Task; + } - [DllImport("__Internal")] - public static extern bool Verify(CString publicKey, CString hash, CString r, CString s); + public class CallHelper + { + public static TaskCompletionSource Tcs; - [DllImport("__Internal")] - private static extern string SerializeByteArray(CString byteArray); + [MonoPInvokeCallback(typeof(Action))] + public static void Callback(string result) + { + Tcs.SetResult(JsonConvert.DeserializeObject(result).Select(f => new FieldElement(f)).ToArray()); + } + } + + public static Task CallAsync(IntPtr provider, dojo.Call call, dojo.BlockId blockId) + { + WaitForTransactionHelper.Tcs = new TaskCompletionSource(); + var serializedCall = new SerializedCall(new FieldElement(call.to), call.selector, call.calldata.ToArray().Select(f => new FieldElement(f)).ToArray()); + object serializedBlockId = SerializedBlockId.Serialize(blockId); + + Call(provider, new CString(JsonConvert.SerializeObject(serializedCall)), new CString(JsonConvert.SerializeObject(serializedBlockId)), CallHelper.Callback); + return CallHelper.Tcs.Task; + } + + public class WaitForTransactionHelper + { + public static TaskCompletionSource Tcs; + + [MonoPInvokeCallback(typeof(Action))] + public static void Callback(bool result) + { + Tcs.SetResult(result); + } + } + + public static Task WaitForTransactionAsync(IntPtr provider, FieldElement transactionHash) + { + WaitForTransactionHelper.Tcs = new TaskCompletionSource(); + WaitForTransaction(provider, new CString(transactionHash.Hex()), WaitForTransactionHelper.Callback); + return WaitForTransactionHelper.Tcs.Task; + } public static FieldElement[] SerializeByteArray(string byteArray) { return JsonConvert.DeserializeObject(SerializeByteArray(new CString(byteArray))).Select(f => new FieldElement(f)).ToArray(); } - [DllImport("__Internal")] - private static extern string DeserializeByteArray(CString felts); - public static string DeserializeByteArray(FieldElement[] felts) { return DeserializeByteArray(new CString(JsonConvert.SerializeObject(felts.Select(f => f.Hex()).ToArray()))); } - [DllImport("__Internal")] - public static extern string PoseidonHash(CString str); - public static string PoseidonHash(FieldElement[] felts) { return PoseidonHash(new CString(JsonConvert.SerializeObject(felts.Select(f => f.Hex()).ToArray()))); } - } + } } \ No newline at end of file diff --git a/Assets/Dojo/Runtime/Torii/ToriiClient.cs b/Assets/Dojo/Runtime/Torii/ToriiClient.cs index f0eece58..2a501cba 100644 --- a/Assets/Dojo/Runtime/Torii/ToriiClient.cs +++ b/Assets/Dojo/Runtime/Torii/ToriiClient.cs @@ -7,398 +7,422 @@ using Newtonsoft.Json; using System.Linq; using System.Numerics; +using AOT; namespace Dojo.Torii { - public unsafe class ToriiClient + public unsafe class ToriiClient + { + private dojo.FnPtr_FieldElement_CArrayStruct_Void.@delegate onEntityStateUpdate; + private dojo.FnPtr_FieldElement_CArrayStruct_Void.@delegate onEventMessagesUpdate; + private dojo.FnPtr_Token_Void.@delegate onTokenUpdate; + private dojo.FnPtr_TokenBalance_Void.@delegate onTokenBalanceUpdate; + private dojo.ToriiClient* client; + private dojo.Subscription* entitySubscription; + private dojo.Subscription* eventMessagesSubscription; + private dojo.Subscription* tokenUpdateSubscription; + private dojo.Subscription* tokenBalanceUpdateSubscription; + + // Static fields to store dispatch settings + private static bool entityUpdateDispatchToMainThread; + private static bool eventMessageUpdateDispatchToMainThread; + private static bool tokenUpdateDispatchToMainThread; + private static bool tokenBalanceUpdateDispatchToMainThread; + + [MonoPInvokeCallback(typeof(dojo.FnPtr_CString_Void.@delegate))] + private static void LogCallback(CString msg) { - private dojo.FnPtr_FieldElement_CArrayStruct_Void.@delegate onEntityStateUpdate; - private dojo.FnPtr_FieldElement_CArrayStruct_Void.@delegate onEventMessagesUpdate; - private dojo.FnPtr_Token_Void.@delegate onTokenUpdate; - private dojo.FnPtr_TokenBalance_Void.@delegate onTokenBalanceUpdate; - private dojo.ToriiClient* client; - private dojo.Subscription* entitySubscription; - private dojo.Subscription* eventMessagesSubscription; - private dojo.Subscription* tokenUpdateSubscription; - private dojo.Subscription* tokenBalanceUpdateSubscription; - - public ToriiClient(string toriiUrl, string relayUrl, FieldElement worldAddress, bool dispatchEventsToMainThread = true) + Debug.Log(msg); + } + + [MonoPInvokeCallback(typeof(dojo.FnPtr_FieldElement_CArrayStruct_Void.@delegate))] + private static void EntityStateUpdateCallback(dojo.FieldElement key, dojo.CArrayStruct models) + { + var mappedModels = new Model[(int)models.data_len]; + for (var i = 0; i < (int)models.data_len; i++) { - CString ctoriiUrl = CString.FromString(toriiUrl); - CString crelayUrl = CString.FromString(relayUrl); - - var result = dojo.client_new(ctoriiUrl, crelayUrl, worldAddress.Inner); - if (result.tag == dojo.ResultToriiClient_Tag.ErrToriiClient) - { - throw new Exception(result.err.message); - } - - client = result._ok; - dojo.client_set_logger(client, new dojo.FnPtr_CString_Void((msg) => Debug.Log(msg))); - - RegisterEntityStateUpdateEvent(null, dispatchEventsToMainThread); - RegisterEventMessageUpdateEvent(null, dispatchEventsToMainThread); - RegisterTokenUpdateEvent(new FieldElement[] { }, new BigInteger[] { }, dispatchEventsToMainThread); - RegisterTokenBalanceUpdateEvent(new FieldElement[] { }, new FieldElement[] { }, new BigInteger[] { }, dispatchEventsToMainThread); + mappedModels[i] = new Model(models.data[i]); } - // We assume the torii client won't be copied around. - // So we can free the underlying c client when the managed client is garbage collected. - ~ToriiClient() + if (entityUpdateDispatchToMainThread) + { + UnityMainThreadDispatcher.Instance().Enqueue(() => ToriiEvents.Instance.EntityUpdated(new FieldElement(key), mappedModels)); + } + else { - dojo.subscription_cancel(entitySubscription); - dojo.subscription_cancel(eventMessagesSubscription); - dojo.subscription_cancel(tokenUpdateSubscription); - dojo.subscription_cancel(tokenBalanceUpdateSubscription); + ToriiEvents.Instance.EntityUpdated(new FieldElement(key), mappedModels); + } + + dojo.carray_free(models.data, models.data_len); + } - dojo.client_free(client); + [MonoPInvokeCallback(typeof(dojo.FnPtr_FieldElement_CArrayStruct_Void.@delegate))] + private static void EventMessageUpdateCallback(dojo.FieldElement key, dojo.CArrayStruct models) + { + var mappedModels = new Model[(int)models.data_len]; + for (var i = 0; i < (int)models.data_len; i++) + { + mappedModels[i] = new Model(models.data[i]); } - public dojo.WorldMetadata WorldMetadata() + if (eventMessageUpdateDispatchToMainThread) { - // TODO: implement a managed type for WorldMetadata too - dojo.ResultWorldMetadata result = dojo.client_metadata(client); - if (result.tag == dojo.ResultWorldMetadata_Tag.ErrWorldMetadata) - { - throw new Exception(result.err.message); - } - - return result.ok; + UnityMainThreadDispatcher.Instance().Enqueue(() => ToriiEvents.Instance.EventMessageUpdated(new FieldElement(key), mappedModels)); + } + else + { + ToriiEvents.Instance.EventMessageUpdated(new FieldElement(key), mappedModels); } - public Page Tokens(FieldElement[] contractAddresses = null, BigInteger[] tokenIds = null, uint limit = 1000, string cursor = null) + dojo.carray_free(models.data, models.data_len); + } + + [MonoPInvokeCallback(typeof(dojo.FnPtr_Token_Void.@delegate))] + private static void TokenUpdateCallback(dojo.Token token) + { + var mappedToken = new Token( + new FieldElement(token.contract_address), + new BigInteger(token.token_id.data, false, true), + token.name, + token.symbol, + token.decimals, + JsonConvert.DeserializeObject>(token.metadata) + ); + + Action emit = () => ToriiEvents.Instance.TokenUpdated(mappedToken); + + if (tokenUpdateDispatchToMainThread) { - if (contractAddresses == null) contractAddresses = new FieldElement[] { }; - if (tokenIds == null) tokenIds = new BigInteger[] { }; - - var nativeContractAddresses = contractAddresses.Select(c => c.Inner).ToArray(); - var nativeTokenIds = tokenIds.Select(t => - { - var bytes = t.ToByteArray(); - Array.Resize(ref bytes, 32); - return new dojo.U256 { data = bytes.Reverse().ToArray() }; - }).ToArray(); - - dojo.FieldElement* nativeContractAddressesPtr; - fixed (dojo.FieldElement* ptr = nativeContractAddresses) - { - nativeContractAddressesPtr = ptr; - } - - - dojo.U256* nativeTokenIdsPtr; - fixed (dojo.U256* ptr = nativeTokenIds) - { - nativeTokenIdsPtr = ptr; - } - - dojo.ResultPageToken result = dojo.client_tokens(client, nativeContractAddressesPtr, (UIntPtr)nativeContractAddresses.Length, nativeTokenIdsPtr, (UIntPtr)nativeTokenIds.Length, limit, cursor is null ? new dojo.COptionc_char { tag = dojo.COptionc_char_Tag.Nonec_char } : new dojo.COptionc_char { tag = dojo.COptionc_char_Tag.Somec_char, some = cursor }); - if (result.tag == dojo.ResultPageToken_Tag.ErrPageToken) - { - throw new Exception(result.err.message); - } - - var items = result.ok.items.ToArray().Select(t => new Token(new FieldElement(t.contract_address), new BigInteger(t.token_id.data, false, true), t.name, t.symbol, t.decimals, JsonConvert.DeserializeObject>(t.metadata))).ToArray(); - var nextCursor = result.ok.next_cursor.tag == dojo.COptionc_char_Tag.Somec_char ? result.ok.next_cursor.some : null; - - dojo.carray_free(result.ok._items.data, result.ok._items.data_len); - return new Page(items, nextCursor); + UnityMainThreadDispatcher.Instance().Enqueue(emit); } + else + { + emit(); + } + } - public Page TokenBalances(FieldElement[] contractAddresses = null, FieldElement[] accountAddresses = null, BigInteger[] tokenIds = null, uint limit = 1000, string cursor = null) + [MonoPInvokeCallback(typeof(dojo.FnPtr_TokenBalance_Void.@delegate))] + private static void TokenBalanceUpdateCallback(dojo.TokenBalance balance) + { + var mappedTokenBalance = new TokenBalance( + new BigInteger(balance.balance.data, false, true), + new FieldElement(balance.account_address), + new FieldElement(balance.contract_address), + new BigInteger(balance.token_id.data, false, true) + ); + + Action emit = () => ToriiEvents.Instance.TokenBalanceUpdated(mappedTokenBalance); + + if (tokenBalanceUpdateDispatchToMainThread) + { + UnityMainThreadDispatcher.Instance().Enqueue(emit); + } + else { - if (contractAddresses == null) contractAddresses = new FieldElement[] { }; - if (accountAddresses == null) accountAddresses = new FieldElement[] { }; - if (tokenIds == null) tokenIds = new BigInteger[] { }; - - var nativeContractAddresses = contractAddresses.Select(c => c.Inner).ToArray(); - var nativeAccountAddresses = accountAddresses.Select(a => a.Inner).ToArray(); - var nativeTokenIds = tokenIds.Select(t => - { - var bytes = t.ToByteArray(); - Array.Resize(ref bytes, 32); - return new dojo.U256 { data = bytes.Reverse().ToArray() }; - }).ToArray(); - - dojo.FieldElement* nativeAccountAddressesPtr; - fixed (dojo.FieldElement* ptr = nativeAccountAddresses) - { - nativeAccountAddressesPtr = ptr; - } - - dojo.FieldElement* nativeContractAddressesPtr; - fixed (dojo.FieldElement* ptr = nativeContractAddresses) - { - nativeContractAddressesPtr = ptr; - } - - dojo.U256* nativeTokenIdsPtr; - fixed (dojo.U256* ptr = nativeTokenIds) - { - nativeTokenIdsPtr = ptr; - } - - - dojo.ResultPageTokenBalance result = dojo.client_token_balances(client, nativeAccountAddressesPtr, (UIntPtr)nativeAccountAddresses.Length, nativeContractAddressesPtr, (UIntPtr)nativeContractAddresses.Length, nativeTokenIdsPtr, (UIntPtr)nativeTokenIds.Length, limit, cursor is null ? new dojo.COptionc_char { tag = dojo.COptionc_char_Tag.Nonec_char } : new dojo.COptionc_char { tag = dojo.COptionc_char_Tag.Somec_char, some = cursor }); - if (result.tag == dojo.ResultPageTokenBalance_Tag.ErrPageTokenBalance) - { - throw new Exception(result.err.message); - } - - var items = result.ok.items.ToArray().Select(t => new TokenBalance(new BigInteger(t.balance.data, false, true), new FieldElement(t.account_address), new FieldElement(t.contract_address), new BigInteger(t.token_id.data, false, true))).ToArray(); - var nextCursor = result.ok.next_cursor.tag == dojo.COptionc_char_Tag.Somec_char ? result.ok.next_cursor.some : null; - - dojo.carray_free(result.ok._items.data, result.ok._items.data_len); - return new Page(items, nextCursor); + emit(); } + } + public ToriiClient(string toriiUrl, string relayUrl, FieldElement worldAddress, bool dispatchEventsToMainThread = true) + { + CString ctoriiUrl = CString.FromString(toriiUrl); + CString crelayUrl = CString.FromString(relayUrl); + + var result = dojo.client_new(ctoriiUrl, crelayUrl, worldAddress.Inner); + if (result.tag == dojo.ResultToriiClient_Tag.ErrToriiClient) + { + throw new Exception(result.err.message); + } + + client = result._ok; + dojo.client_set_logger(client, new dojo.FnPtr_CString_Void(LogCallback)); + + RegisterEntityStateUpdateEvent(null, dispatchEventsToMainThread); + RegisterEventMessageUpdateEvent(null, dispatchEventsToMainThread); + RegisterTokenUpdateEvent(new FieldElement[] { }, new BigInteger[] { }, dispatchEventsToMainThread); + RegisterTokenBalanceUpdateEvent(new FieldElement[] { }, new FieldElement[] { }, new BigInteger[] { }, dispatchEventsToMainThread); + } - public Page Entities(Query query, bool historical = false) - { - var nativeQuery = query.ToNative(); + ~ToriiClient() + { + dojo.subscription_cancel(entitySubscription); + dojo.subscription_cancel(eventMessagesSubscription); + dojo.subscription_cancel(tokenUpdateSubscription); + dojo.subscription_cancel(tokenBalanceUpdateSubscription); - dojo.ResultPageEntity result = dojo.client_entities(client, nativeQuery); - if (result.tag == dojo.ResultPageEntity_Tag.ErrPageEntity) - { - throw new Exception(result.err.message); - } + dojo.client_free(client); + } - var items = result.ok.items.ToArray().Select(e => new Entity(e)).ToArray(); - var nextCursor = result.ok.next_cursor.tag == dojo.COptionc_char_Tag.Somec_char ? result.ok.next_cursor.some : null; + public dojo.WorldMetadata WorldMetadata() + { + dojo.ResultWorldMetadata result = dojo.client_metadata(client); + if (result.tag == dojo.ResultWorldMetadata_Tag.ErrWorldMetadata) + { + throw new Exception(result.err.message); + } - dojo.carray_free(result.ok._items.data, result.ok._items.data_len); - return new Page(items, nextCursor); - } + return result.ok; + } - public Page EventMessages(Query query) - { - var nativeQuery = query.ToNative(); + public Page Tokens(FieldElement[] contractAddresses = null, BigInteger[] tokenIds = null, uint limit = 1000, string cursor = null) + { + if (contractAddresses == null) contractAddresses = new FieldElement[] { }; + if (tokenIds == null) tokenIds = new BigInteger[] { }; + + var nativeContractAddresses = contractAddresses.Select(c => c.Inner).ToArray(); + var nativeTokenIds = tokenIds.Select(t => + { + var bytes = t.ToByteArray(); + Array.Resize(ref bytes, 32); + return new dojo.U256 { data = bytes.Reverse().ToArray() }; + }).ToArray(); + + dojo.FieldElement* nativeContractAddressesPtr; + fixed (dojo.FieldElement* ptr = nativeContractAddresses) + { + nativeContractAddressesPtr = ptr; + } + + dojo.U256* nativeTokenIdsPtr; + fixed (dojo.U256* ptr = nativeTokenIds) + { + nativeTokenIdsPtr = ptr; + } + + dojo.ResultPageToken result = dojo.client_tokens(client, nativeContractAddressesPtr, (UIntPtr)nativeContractAddresses.Length, nativeTokenIdsPtr, (UIntPtr)nativeTokenIds.Length, limit, cursor is null ? new dojo.COptionc_char { tag = dojo.COptionc_char_Tag.Nonec_char } : new dojo.COptionc_char { tag = dojo.COptionc_char_Tag.Somec_char, some = cursor }); + if (result.tag == dojo.ResultPageToken_Tag.ErrPageToken) + { + throw new Exception(result.err.message); + } + + var items = result.ok.items.ToArray().Select(t => new Token(new FieldElement(t.contract_address), new BigInteger(t.token_id.data, false, true), t.name, t.symbol, t.decimals, JsonConvert.DeserializeObject>(t.metadata))).ToArray(); + var nextCursor = result.ok.next_cursor.tag == dojo.COptionc_char_Tag.Somec_char ? result.ok.next_cursor.some : null; + + dojo.carray_free(result.ok._items.data, result.ok._items.data_len); + return new Page(items, nextCursor); + } - dojo.ResultPageEntity result = dojo.client_event_messages(client, nativeQuery); - if (result.tag == dojo.ResultPageEntity_Tag.ErrPageEntity) - { - throw new Exception(result.err.message); - } + public Page TokenBalances(FieldElement[] contractAddresses = null, FieldElement[] accountAddresses = null, BigInteger[] tokenIds = null, uint limit = 1000, string cursor = null) + { + if (contractAddresses == null) contractAddresses = new FieldElement[] { }; + if (accountAddresses == null) accountAddresses = new FieldElement[] { }; + if (tokenIds == null) tokenIds = new BigInteger[] { }; + + var nativeContractAddresses = contractAddresses.Select(c => c.Inner).ToArray(); + var nativeAccountAddresses = accountAddresses.Select(a => a.Inner).ToArray(); + var nativeTokenIds = tokenIds.Select(t => + { + var bytes = t.ToByteArray(); + Array.Resize(ref bytes, 32); + return new dojo.U256 { data = bytes.Reverse().ToArray() }; + }).ToArray(); + + dojo.FieldElement* nativeAccountAddressesPtr; + fixed (dojo.FieldElement* ptr = nativeAccountAddresses) + { + nativeAccountAddressesPtr = ptr; + } + + dojo.FieldElement* nativeContractAddressesPtr; + fixed (dojo.FieldElement* ptr = nativeContractAddresses) + { + nativeContractAddressesPtr = ptr; + } + + dojo.U256* nativeTokenIdsPtr; + fixed (dojo.U256* ptr = nativeTokenIds) + { + nativeTokenIdsPtr = ptr; + } + + dojo.ResultPageTokenBalance result = dojo.client_token_balances(client, nativeAccountAddressesPtr, (UIntPtr)nativeAccountAddresses.Length, nativeContractAddressesPtr, (UIntPtr)nativeContractAddresses.Length, nativeTokenIdsPtr, (UIntPtr)nativeTokenIds.Length, limit, cursor is null ? new dojo.COptionc_char { tag = dojo.COptionc_char_Tag.Nonec_char } : new dojo.COptionc_char { tag = dojo.COptionc_char_Tag.Somec_char, some = cursor }); + if (result.tag == dojo.ResultPageTokenBalance_Tag.ErrPageTokenBalance) + { + throw new Exception(result.err.message); + } + + var items = result.ok.items.ToArray().Select(t => new TokenBalance(new BigInteger(t.balance.data, false, true), new FieldElement(t.account_address), new FieldElement(t.contract_address), new BigInteger(t.token_id.data, false, true))).ToArray(); + var nextCursor = result.ok.next_cursor.tag == dojo.COptionc_char_Tag.Somec_char ? result.ok.next_cursor.some : null; + + dojo.carray_free(result.ok._items.data, result.ok._items.data_len); + return new Page(items, nextCursor); + } - var items = result.ok.items.ToArray().Select(e => new Entity(e)).ToArray(); - var nextCursor = result.ok.next_cursor.tag == dojo.COptionc_char_Tag.Somec_char ? result.ok.next_cursor.some : null; + public Page Entities(Query query, bool historical = false) + { + var nativeQuery = query.ToNative(); - dojo.carray_free(result.ok._items.data, result.ok._items.data_len); - return new Page(items, nextCursor); - } + dojo.ResultPageEntity result = dojo.client_entities(client, nativeQuery); + if (result.tag == dojo.ResultPageEntity_Tag.ErrPageEntity) + { + throw new Exception(result.err.message); + } - private void RegisterEntityStateUpdateEvent(Clause? clause = null, bool dispatchToMainThread = true) - { - onEntityStateUpdate = (key, models) => - { - var mappedModels = new Model[(int)models.data_len]; - for (var i = 0; i < (int)models.data_len; i++) - { - mappedModels[i] = new Model(models.data[i]); - // cleanup model - // dojo.model_free(&models.data[i]); - } - - // only run this when in unity play mode - // we need our unity main thread dispatcher to run this on the main thread - if (dispatchToMainThread) - { - UnityMainThreadDispatcher.Instance().Enqueue(() => ToriiEvents.Instance.EntityUpdated(new FieldElement(key), mappedModels)); - } - else - { - ToriiEvents.Instance.EntityUpdated(new FieldElement(key), mappedModels); - } - - // cleanup - dojo.carray_free(models.data, models.data_len); - // TODO: free field element - }; - - - var nativeClause = clause is null ? new dojo.COptionClause { tag = dojo.COptionClause_Tag.NoneClause } : new dojo.COptionClause { tag = dojo.COptionClause_Tag.SomeClause, some = clause.Value.ToNative() }; - dojo.ResultSubscription res = dojo.client_on_entity_state_update(client, nativeClause, new dojo.FnPtr_FieldElement_CArrayStruct_Void(onEntityStateUpdate)); - if (res.tag == dojo.ResultSubscription_Tag.ErrSubscription) - { - throw new Exception(res.err.message); - } - - entitySubscription = res._ok; - } + var items = result.ok.items.ToArray().Select(e => new Entity(e)).ToArray(); + var nextCursor = result.ok.next_cursor.tag == dojo.COptionc_char_Tag.Somec_char ? result.ok.next_cursor.some : null; - public void RegisterTokenUpdateEvent(FieldElement[] contractAddresses = null, BigInteger[] tokenIds = null, bool dispatchToMainThread = true) - { - if (contractAddresses == null) contractAddresses = new FieldElement[] { }; - if (tokenIds == null) tokenIds = new BigInteger[] { }; - - var nativeContractAddresses = contractAddresses.Select(c => c.Inner).ToArray(); - var nativeTokenIds = tokenIds.Select(t => - { - var bytes = t.ToByteArray(); - Array.Resize(ref bytes, 32); - return new dojo.U256 { data = bytes.Reverse().ToArray() }; - }).ToArray(); - - dojo.FieldElement* nativeContractAddressesPtr; - fixed (dojo.FieldElement* ptr = nativeContractAddresses) - { - nativeContractAddressesPtr = ptr; - } - - - dojo.U256* nativeTokenIdsPtr; - fixed (dojo.U256* ptr = nativeTokenIds) - { - nativeTokenIdsPtr = ptr; - } - - onTokenUpdate = (token) => - { - var mappedToken = new Token(new FieldElement(token.contract_address), new BigInteger(token.token_id.data, false, true), token.name, token.symbol, token.decimals, JsonConvert.DeserializeObject>(token.metadata)); - Action emit = () => ToriiEvents.Instance.TokenUpdated(mappedToken); - if (dispatchToMainThread) - { - UnityMainThreadDispatcher.Instance().Enqueue(emit); - } - else - { - emit(); - } - }; - - dojo.ResultSubscription res = dojo.client_on_token_update(client, nativeContractAddressesPtr, (UIntPtr)nativeContractAddresses.Length, nativeTokenIdsPtr, (UIntPtr)nativeTokenIds.Length, new dojo.FnPtr_Token_Void(onTokenUpdate)); - if (res.tag == dojo.ResultSubscription_Tag.ErrSubscription) - { - throw new Exception(res.err.message); - } - - tokenUpdateSubscription = res._ok; - } + dojo.carray_free(result.ok._items.data, result.ok._items.data_len); + return new Page(items, nextCursor); + } - public void RegisterTokenBalanceUpdateEvent(FieldElement[] contractAddresses = null, FieldElement[] accountAddresses = null, BigInteger[] tokenIds = null, bool dispatchToMainThread = true) - { - if (contractAddresses == null) contractAddresses = new FieldElement[] { }; - if (accountAddresses == null) accountAddresses = new FieldElement[] { }; - if (tokenIds == null) tokenIds = new BigInteger[] { }; - - var nativeContractAddresses = contractAddresses.Select(c => c.Inner).ToArray(); - var nativeAccountAddresses = accountAddresses.Select(a => a.Inner).ToArray(); - var nativeTokenIds = tokenIds.Select(t => - { - var bytes = t.ToByteArray(); - Array.Resize(ref bytes, 32); - return new dojo.U256 { data = bytes.Reverse().ToArray() }; - }).ToArray(); - - dojo.FieldElement* nativeAccountAddressesPtr; - fixed (dojo.FieldElement* ptr = nativeAccountAddresses) - { - nativeAccountAddressesPtr = ptr; - } - - dojo.FieldElement* nativeContractAddressesPtr; - fixed (dojo.FieldElement* ptr = nativeContractAddresses) - { - nativeContractAddressesPtr = ptr; - } - - - dojo.U256* nativeTokenIdsPtr; - fixed (dojo.U256* ptr = nativeTokenIds) - { - nativeTokenIdsPtr = ptr; - } - - onTokenBalanceUpdate = (balance) => - { - var mappedTokenBalance = new TokenBalance(new BigInteger(balance.balance.data, false, true), new FieldElement(balance.account_address), new FieldElement(balance.contract_address), new BigInteger(balance.token_id.data, false, true)); - Action emit = () => ToriiEvents.Instance.TokenBalanceUpdated(mappedTokenBalance); - if (dispatchToMainThread) - { - UnityMainThreadDispatcher.Instance().Enqueue(emit); - } - else - { - emit(); - } - }; - - dojo.ResultSubscription res = dojo.client_on_token_balance_update(client, nativeAccountAddressesPtr, (UIntPtr)nativeAccountAddresses.Length, nativeContractAddressesPtr, (UIntPtr)nativeContractAddresses.Length, nativeTokenIdsPtr, (UIntPtr)nativeTokenIds.Length, new dojo.FnPtr_TokenBalance_Void(onTokenBalanceUpdate)); - if (res.tag == dojo.ResultSubscription_Tag.ErrSubscription) - { - throw new Exception(res.err.message); - } - - tokenBalanceUpdateSubscription = res._ok; - } - public void UpdateEntitySubscription(Clause? clause = null) - { - var nativeClause = clause is null ? new dojo.COptionClause { tag = dojo.COptionClause_Tag.NoneClause } : new dojo.COptionClause { tag = dojo.COptionClause_Tag.SomeClause, some = clause.Value.ToNative() }; - dojo.client_update_entity_subscription(client, entitySubscription, nativeClause); - } + public Page EventMessages(Query query) + { + var nativeQuery = query.ToNative(); - private void RegisterEventMessageUpdateEvent(Clause? clause = null, bool dispatchToMainThread = true) - { - onEventMessagesUpdate = (key, models) => - { - var mappedModels = new Model[(int)models.data_len]; - for (var i = 0; i < (int)models.data_len; i++) - { - mappedModels[i] = new Model(models.data[i]); - // cleanup model - // dojo.model_free(&models.data[i]); - } - - // only run this when in unity play mode - // we need our unity main thread dispatcher to run this on the main thread - if (dispatchToMainThread) - { - UnityMainThreadDispatcher.Instance().Enqueue(() => ToriiEvents.Instance.EventMessageUpdated(new FieldElement(key), mappedModels)); - } - else - { - ToriiEvents.Instance.EventMessageUpdated(new FieldElement(key), mappedModels); - } - - // cleanup - dojo.carray_free(models.data, models.data_len); - // TODO: free field element - }; - - - var nativeClause = clause is null ? new dojo.COptionClause { tag = dojo.COptionClause_Tag.NoneClause } : new dojo.COptionClause { tag = dojo.COptionClause_Tag.SomeClause, some = clause.Value.ToNative() }; - - dojo.ResultSubscription res = dojo.client_on_event_message_update(client, nativeClause, new dojo.FnPtr_FieldElement_CArrayStruct_Void(onEventMessagesUpdate)); - if (res.tag == dojo.ResultSubscription_Tag.ErrSubscription) - { - throw new Exception(res.err.message); - } - - eventMessagesSubscription = res._ok; - } + dojo.ResultPageEntity result = dojo.client_event_messages(client, nativeQuery); + if (result.tag == dojo.ResultPageEntity_Tag.ErrPageEntity) + { + throw new Exception(result.err.message); + } - public void UpdateEventMessageSubscription(Clause? clause = null) - { - var nativeClause = clause is null ? new dojo.COptionClause { tag = dojo.COptionClause_Tag.NoneClause } : new dojo.COptionClause { tag = dojo.COptionClause_Tag.SomeClause, some = clause.Value.ToNative() }; - dojo.client_update_event_message_subscription(client, eventMessagesSubscription, nativeClause); - } + var items = result.ok.items.ToArray().Select(e => new Entity(e)).ToArray(); + var nextCursor = result.ok.next_cursor.tag == dojo.COptionc_char_Tag.Somec_char ? result.ok.next_cursor.some : null; - public Span PublishMessage(TypedData typedData, FieldElement[] signature) - { - var mappedSignature = signature.Select(s => s.Inner).ToArray(); - dojo.FieldElement* signaturePtr; - fixed (dojo.FieldElement* ptr = mappedSignature) - { - signaturePtr = ptr; - } - - var result = dojo.client_publish_message(client, new CString(JsonConvert.SerializeObject(typedData)), signaturePtr, (UIntPtr)signature.Length); - if (result.tag == dojo.ResultCArrayu8_Tag.ErrCArrayu8) - { - throw new Exception(result.err.message); - } - - return result.ok; - } + dojo.carray_free(result.ok._items.data, result.ok._items.data_len); + return new Page(items, nextCursor); + } + + private void RegisterEntityStateUpdateEvent(Clause? clause = null, bool dispatchToMainThread = true) + { + entityUpdateDispatchToMainThread = dispatchToMainThread; + onEntityStateUpdate = EntityStateUpdateCallback; + + var nativeClause = clause is null ? new dojo.COptionClause { tag = dojo.COptionClause_Tag.NoneClause } : new dojo.COptionClause { tag = dojo.COptionClause_Tag.SomeClause, some = clause.Value.ToNative() }; + dojo.ResultSubscription res = dojo.client_on_entity_state_update(client, nativeClause, new dojo.FnPtr_FieldElement_CArrayStruct_Void(onEntityStateUpdate)); + if (res.tag == dojo.ResultSubscription_Tag.ErrSubscription) + { + throw new Exception(res.err.message); + } + + entitySubscription = res._ok; + } + + public void RegisterTokenUpdateEvent(FieldElement[] contractAddresses = null, BigInteger[] tokenIds = null, bool dispatchToMainThread = true) + { + if (contractAddresses == null) contractAddresses = new FieldElement[] { }; + if (tokenIds == null) tokenIds = new BigInteger[] { }; + + var nativeContractAddresses = contractAddresses.Select(c => c.Inner).ToArray(); + var nativeTokenIds = tokenIds.Select(t => + { + var bytes = t.ToByteArray(); + Array.Resize(ref bytes, 32); + return new dojo.U256 { data = bytes.Reverse().ToArray() }; + }).ToArray(); + + dojo.FieldElement* nativeContractAddressesPtr; + fixed (dojo.FieldElement* ptr = nativeContractAddresses) + { + nativeContractAddressesPtr = ptr; + } + + dojo.U256* nativeTokenIdsPtr; + fixed (dojo.U256* ptr = nativeTokenIds) + { + nativeTokenIdsPtr = ptr; + } + + tokenUpdateDispatchToMainThread = dispatchToMainThread; + onTokenUpdate = TokenUpdateCallback; + + dojo.ResultSubscription res = dojo.client_on_token_update(client, nativeContractAddressesPtr, (UIntPtr)nativeContractAddresses.Length, nativeTokenIdsPtr, (UIntPtr)nativeTokenIds.Length, new dojo.FnPtr_Token_Void(onTokenUpdate)); + if (res.tag == dojo.ResultSubscription_Tag.ErrSubscription) + { + throw new Exception(res.err.message); + } + + tokenUpdateSubscription = res._ok; + } + + public void RegisterTokenBalanceUpdateEvent(FieldElement[] contractAddresses = null, FieldElement[] accountAddresses = null, BigInteger[] tokenIds = null, bool dispatchToMainThread = true) + { + if (contractAddresses == null) contractAddresses = new FieldElement[] { }; + if (accountAddresses == null) accountAddresses = new FieldElement[] { }; + if (tokenIds == null) tokenIds = new BigInteger[] { }; + + var nativeContractAddresses = contractAddresses.Select(c => c.Inner).ToArray(); + var nativeAccountAddresses = accountAddresses.Select(a => a.Inner).ToArray(); + var nativeTokenIds = tokenIds.Select(t => + { + var bytes = t.ToByteArray(); + Array.Resize(ref bytes, 32); + return new dojo.U256 { data = bytes.Reverse().ToArray() }; + }).ToArray(); + + dojo.FieldElement* nativeAccountAddressesPtr; + fixed (dojo.FieldElement* ptr = nativeAccountAddresses) + { + nativeAccountAddressesPtr = ptr; + } + + dojo.FieldElement* nativeContractAddressesPtr; + fixed (dojo.FieldElement* ptr = nativeContractAddresses) + { + nativeContractAddressesPtr = ptr; + } + + dojo.U256* nativeTokenIdsPtr; + fixed (dojo.U256* ptr = nativeTokenIds) + { + nativeTokenIdsPtr = ptr; + } + + tokenBalanceUpdateDispatchToMainThread = dispatchToMainThread; + onTokenBalanceUpdate = TokenBalanceUpdateCallback; + + dojo.ResultSubscription res = dojo.client_on_token_balance_update(client, nativeAccountAddressesPtr, (UIntPtr)nativeAccountAddresses.Length, nativeContractAddressesPtr, (UIntPtr)nativeContractAddresses.Length, nativeTokenIdsPtr, (UIntPtr)nativeTokenIds.Length, new dojo.FnPtr_TokenBalance_Void(onTokenBalanceUpdate)); + if (res.tag == dojo.ResultSubscription_Tag.ErrSubscription) + { + throw new Exception(res.err.message); + } + + tokenBalanceUpdateSubscription = res._ok; + } + + public void UpdateEntitySubscription(Clause? clause = null) + { + var nativeClause = clause is null ? new dojo.COptionClause { tag = dojo.COptionClause_Tag.NoneClause } : new dojo.COptionClause { tag = dojo.COptionClause_Tag.SomeClause, some = clause.Value.ToNative() }; + dojo.client_update_entity_subscription(client, entitySubscription, nativeClause); + } + + private void RegisterEventMessageUpdateEvent(Clause? clause = null, bool dispatchToMainThread = true) + { + eventMessageUpdateDispatchToMainThread = dispatchToMainThread; + onEventMessagesUpdate = EventMessageUpdateCallback; + + var nativeClause = clause is null ? new dojo.COptionClause { tag = dojo.COptionClause_Tag.NoneClause } : new dojo.COptionClause { tag = dojo.COptionClause_Tag.SomeClause, some = clause.Value.ToNative() }; + + dojo.ResultSubscription res = dojo.client_on_event_message_update(client, nativeClause, new dojo.FnPtr_FieldElement_CArrayStruct_Void(onEventMessagesUpdate)); + if (res.tag == dojo.ResultSubscription_Tag.ErrSubscription) + { + throw new Exception(res.err.message); + } + + eventMessagesSubscription = res._ok; + } + + public void UpdateEventMessageSubscription(Clause? clause = null) + { + var nativeClause = clause is null ? new dojo.COptionClause { tag = dojo.COptionClause_Tag.NoneClause } : new dojo.COptionClause { tag = dojo.COptionClause_Tag.SomeClause, some = clause.Value.ToNative() }; + dojo.client_update_event_message_subscription(client, eventMessagesSubscription, nativeClause); + } + + public Span PublishMessage(TypedData typedData, FieldElement[] signature) + { + var mappedSignature = signature.Select(s => s.Inner).ToArray(); + dojo.FieldElement* signaturePtr; + fixed (dojo.FieldElement* ptr = mappedSignature) + { + signaturePtr = ptr; + } + + var result = dojo.client_publish_message(client, new CString(JsonConvert.SerializeObject(typedData)), signaturePtr, (UIntPtr)signature.Length); + if (result.tag == dojo.ResultCArrayu8_Tag.ErrCArrayu8) + { + throw new Exception(result.err.message); + } + + return result.ok; } + } } \ No newline at end of file diff --git a/Assets/Dojo/Runtime/Torii/ToriiWasmInterop.cs b/Assets/Dojo/Runtime/Torii/ToriiWasmInterop.cs index a28c5104..c4d1ea7a 100644 --- a/Assets/Dojo/Runtime/Torii/ToriiWasmInterop.cs +++ b/Assets/Dojo/Runtime/Torii/ToriiWasmInterop.cs @@ -14,111 +14,209 @@ namespace Dojo.Torii { - [Serializable] - public struct WasmEntity + [Serializable] + public struct WasmEntity + { + public string hashed_keys; + public Dictionary> models; + } + + [Serializable] + public struct WasmValue + { + public string type; + public string type_name; + public JToken value; + public bool key; + } + + [Serializable] + public struct WasmEnum + { + public string option; + public WasmValue value; + } + + [Serializable] + public struct WasmToken + { + public string contract_address; + public string token_id; + public string name; + public string symbol; + public int decimals; + public string metadata; + } + + [Serializable] + public struct WasmTokenBalance + { + public string balance; + public string account_address; + public string contract_address; + public string token_id; + } + + public class ToriiWasmInterop : MonoBehaviour + { +#if UNITY_IOS + // Stub implementations for non-WebGL platforms + public static void CreateClient(CString toriiUrl, CString relayUrl, CString worldAddress, Action cb) { - public string hashed_keys; - public Dictionary> models; + Debug.LogWarning("CreateClient called on non-WebGL platform."); + cb(IntPtr.Zero); } - [Serializable] - public struct WasmValue + public static void GetTokens(IntPtr clientPtr, CString contractAddresses, CString tokenIds, int limit, CString cursor, Action cb) { - public string type; - public string type_name; - public JToken value; - public bool key; + Debug.LogWarning("GetTokens called on non-WebGL platform."); + cb("{}"); } - [Serializable] - public struct WasmEnum + public static void GetTokenBalances(IntPtr clientPtr, CString contractAddresses, CString accountAddresses, CString tokenIds, int limit, CString cursor, Action cb) { - public string option; - public WasmValue value; + Debug.LogWarning("GetTokenBalances called on non-WebGL platform."); + cb("{}"); } - [Serializable] - public struct WasmToken + public static void OnTokenUpdated(IntPtr clientPtr, CString contractAddresses, CString tokenIds, Action cb, Action subCb) { - public string contract_address; - public string token_id; - public string name; - public string symbol; - public int decimals; - public string metadata; + Debug.LogWarning("OnTokenUpdated called on non-WebGL platform."); + subCb(IntPtr.Zero); } - [Serializable] - public struct WasmTokenBalance + public static void OnTokenBalanceUpdated(IntPtr clientPtr, CString contractAddresses, CString accountAddresses, CString tokenIds, Action cb, Action subCb) { - public string balance; - public string account_address; - public string contract_address; - public string token_id; + Debug.LogWarning("OnTokenBalanceUpdated called on non-WebGL platform."); + subCb(IntPtr.Zero); } - public class ToriiWasmInterop : MonoBehaviour + public static void GetEntities(IntPtr clientPtr, CString query, Action cb) { - // Creates a new client and returns the pointer to it - [DllImport("__Internal")] - public static extern void CreateClient(CString toriiUrl, CString relayUrl, CString worldAddress, Action cb); + Debug.LogWarning("GetEntities called on non-WebGL platform."); + cb("{}"); + } - // Returns an array of all tokens - [DllImport("__Internal")] - public static extern void GetTokens(IntPtr clientPtr, CString contractAddresses, CString tokenIds, int limit, CString cursor, Action cb); + public static void GetEventMessages(IntPtr clientPtr, CString query, Action cb) + { + Debug.LogWarning("GetEventMessages called on non-WebGL platform."); + cb("{}"); + } - // Returns an array of all token balances - [DllImport("__Internal")] - public static extern void GetTokenBalances(IntPtr clientPtr, CString contractAddresses, CString accountAddresses, CString tokenIds, int limit, CString cursor, Action cb); + public static string GetModelValue(IntPtr clientPtr, CString model, CString keys) + { + Debug.LogWarning("GetModelValue called on non-WebGL platform."); + return "{}"; + } - // Returns a dictionary of all of the entities - [DllImport("__Internal")] - public static extern void GetEntities(IntPtr clientPtr, CString query, Action cb); + public static void OnEntityUpdated(IntPtr clientPtr, CString clauses, Action cb, Action subCb) + { + Debug.LogWarning("OnEntityUpdated called on non-WebGL platform."); + } - [DllImport("__Internal")] - public static extern void GetEventMessages(IntPtr clientPtr, CString query, Action cb); + public static void UpdateEntitySubscription(IntPtr clientPtr, IntPtr subPtr, CString clauses) + { + Debug.LogWarning("UpdateEntitySubscription called on non-WebGL platform."); + } - // Get the value of a model for a specific set of keys - [DllImport("__Internal")] - public static extern string GetModelValue(IntPtr clientPtr, CString model, CString keys); + public static void OnEventMessageUpdated(IntPtr clientPtr, CString clause, Action cb, Action subCb) + { + Debug.LogWarning("OnEventMessageUpdated called on non-WebGL platform."); + } - // Calls the callback at [callbackObjectName].[callbackMethodName] on entity updated - [DllImport("__Internal")] - public static extern void OnEntityUpdated(IntPtr clientPtr, CString clause, Action cb, Action subCb); + public static void UpdateEventMessageSubscription(IntPtr clientPtr, IntPtr subPtr, CString clauses) + { + Debug.LogWarning("UpdateEventMessageSubscription called on non-WebGL platform."); + } - [DllImport("__Internal")] - public static extern void UpdateEntitySubscription(IntPtr clientPtr, IntPtr subPtr, CString clause); + public static void AddModelsToSync(IntPtr clientPtr, CString models) + { + Debug.LogWarning("AddModelsToSync called on non-WebGL platform."); + } - // Calls the callback at [callbackObjectName].[callbackMethodName] on event mnessage updated - [DllImport("__Internal")] - public static extern void OnEventMessageUpdated(IntPtr clientPtr, CString clause, Action cb, Action subCb); + public static void RemoveModelsToSync(IntPtr clientPtr, CString models) + { + Debug.LogWarning("RemoveModelsToSync called on non-WebGL platform."); + } - [DllImport("__Internal")] - public static extern void UpdateEventMessageSubscription(IntPtr clientPtr, IntPtr subPtr, CString clause); + public static void OnSyncModelChange(IntPtr clientPtr, CString model, CString callbackObjectName, CString callbackMethodName) + { + Debug.LogWarning("OnSyncModelChange called on non-WebGL platform."); + } - [DllImport("__Internal")] - public static extern void OnTokenUpdated(IntPtr clientPtr, CString contractAddresses, CString tokenIds, Action cb, Action subCb); + public static string EncodeTypedData(CString typedData, CString address) + { + Debug.LogWarning("EncodeTypedData called on non-WebGL platform."); + return "{}"; + } - [DllImport("__Internal")] - public static extern void OnTokenBalanceUpdated(IntPtr clientPtr, CString contractAddresses, CString accountAddresses, CString tokenIds, Action cb, Action subCb); + public static void PublishMessage(IntPtr clientPtr, CString typedData, CString signature, Action cb) + { + Debug.LogWarning("PublishMessage called on non-WebGL platform."); + cb("{}"); + } +#else + // Creates a new client and returns the pointer to it + [DllImport("__Internal")] + public static extern void CreateClient(CString toriiUrl, CString relayUrl, CString worldAddress, Action cb); - // Add models to sync - [DllImport("__Internal")] - public static extern void AddModelsToSync(IntPtr clientPtr, CString models); + // Returns an array of all tokens + [DllImport("__Internal")] + public static extern void GetTokens(IntPtr clientPtr, CString contractAddresses, CString tokenIds, int limit, CString cursor, Action cb); - // Remove models to sync - [DllImport("__Internal")] - public static extern void RemoveModelsToSync(IntPtr clientPtr, CString models); + // Returns an array of all token balances + [DllImport("__Internal")] + public static extern void GetTokenBalances(IntPtr clientPtr, CString contractAddresses, CString accountAddresses, CString tokenIds, int limit, CString cursor, Action cb); - // Calls the callback at [callbackObjectName].[callbackMethodName] on model change - [DllImport("__Internal")] - public static extern void OnSyncModelChange(IntPtr clientPtr, CString model, CString callbackObjectName, CString callbackMethodName); + // Returns a dictionary of all of the entities + [DllImport("__Internal")] + public static extern void GetEntities(IntPtr clientPtr, CString query, Action cb); - [DllImport("__Internal")] - public static extern string EncodeTypedData(CString typedData, CString address); + [DllImport("__Internal")] + public static extern void GetEventMessages(IntPtr clientPtr, CString query, Action cb); + // Get the value of a model for a specific set of keys + [DllImport("__Internal")] + public static extern string GetModelValue(IntPtr clientPtr, CString model, CString keys); - [DllImport("__Internal")] - public static extern void PublishMessage(IntPtr clientPtr, CString typedData, CString signature, Action cb); - } + // Calls the callback at [callbackObjectName].[callbackMethodName] on entity updated + [DllImport("__Internal")] + public static extern void OnEntityUpdated(IntPtr clientPtr, CString clause, Action cb, Action subCb); + + [DllImport("__Internal")] + public static extern void UpdateEntitySubscription(IntPtr clientPtr, IntPtr subPtr, CString clause); + + // Calls the callback at [callbackObjectName].[callbackMethodName] on event mnessage updated + [DllImport("__Internal")] + public static extern void OnEventMessageUpdated(IntPtr clientPtr, CString clause, Action cb, Action subCb); + + [DllImport("__Internal")] + public static extern void UpdateEventMessageSubscription(IntPtr clientPtr, IntPtr subPtr, CString clause); + + [DllImport("__Internal")] + public static extern void OnTokenUpdated(IntPtr clientPtr, CString contractAddresses, CString tokenIds, Action cb, Action subCb); + + [DllImport("__Internal")] + public static extern void OnTokenBalanceUpdated(IntPtr clientPtr, CString contractAddresses, CString accountAddresses, CString tokenIds, Action cb, Action subCb); + + // Add models to sync + [DllImport("__Internal")] + public static extern void AddModelsToSync(IntPtr clientPtr, CString models); + + // Remove models to sync + [DllImport("__Internal")] + public static extern void RemoveModelsToSync(IntPtr clientPtr, CString models); + + // Calls the callback at [callbackObjectName].[callbackMethodName] on model change + [DllImport("__Internal")] + public static extern void OnSyncModelChange(IntPtr clientPtr, CString model, CString callbackObjectName, CString callbackMethodName); + + [DllImport("__Internal")] + public static extern string EncodeTypedData(CString typedData, CString address); + + + [DllImport("__Internal")] + public static extern void PublishMessage(IntPtr clientPtr, CString typedData, CString signature, Action cb); +#endif + } } \ No newline at end of file diff --git a/Assets/Dojo/Runtime/bindings/client/dojo.gen.cs b/Assets/Dojo/Runtime/bindings/client/dojo.gen.cs index f2d770b7..4f0f0122 100644 --- a/Assets/Dojo/Runtime/bindings/client/dojo.gen.cs +++ b/Assets/Dojo/Runtime/bindings/client/dojo.gen.cs @@ -26,6 +26,8 @@ namespace dojo_bindings public static unsafe partial class dojo { private const string LibraryName = "libdojo_c"; + // Uncomment this for iOS build (and comment previous line) + // private const string LibraryName = "__Internal"; #region API