Wallet connection + supabase
6
.vsconfig
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"version": "1.0",
|
||||
"components": [
|
||||
"Microsoft.VisualStudio.Workload.ManagedGame"
|
||||
]
|
||||
}
|
8
Assets/Editor.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d4be753bffbac8d4c99c0d4cdad9d5d2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
54
Assets/Editor/GenerateSupabaseSecretsPrebuild.cs
Normal file
@ -0,0 +1,54 @@
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Build;
|
||||
using UnityEditor.Build.Reporting;
|
||||
using UnityEngine;
|
||||
|
||||
[Serializable] class SupabaseClientSecrets { public string url; public string anonKey; }
|
||||
|
||||
public class GenerateSupabaseSecretsPrebuild : IPreprocessBuildWithReport
|
||||
{
|
||||
public int callbackOrder => 0;
|
||||
|
||||
public void OnPreprocessBuild(BuildReport report)
|
||||
{
|
||||
// 1) read from Cloud Build env (populated from project secrets)
|
||||
var url = Environment.GetEnvironmentVariable("SUPABASE_URL");
|
||||
var anonKey = Environment.GetEnvironmentVariable("SUPABASE_ANON");
|
||||
|
||||
// 2) local dev override (git-ignored)
|
||||
var devPath = Path.Combine(Application.dataPath, "Editor/supabase.secrets.dev.json");
|
||||
if (File.Exists(devPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
var dev = JsonUtility.FromJson<SupabaseClientSecrets>(File.ReadAllText(devPath));
|
||||
if (!string.IsNullOrWhiteSpace(dev.url)) url = dev.url;
|
||||
if (!string.IsNullOrWhiteSpace(dev.anonKey)) anonKey = dev.anonKey;
|
||||
}
|
||||
catch { Debug.LogWarning("Invalid supabase.secrets.dev.json; ignoring."); }
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(url) || string.IsNullOrWhiteSpace(anonKey))
|
||||
throw new BuildFailedException("Missing SUPABASE_URL or SUPABASE_ANON_KEY.");
|
||||
|
||||
var json = JsonUtility.ToJson(new SupabaseClientSecrets { url = url, anonKey = anonKey }, false);
|
||||
|
||||
var resDir = Path.Combine(Application.dataPath, "Resources");
|
||||
Directory.CreateDirectory(resDir);
|
||||
var outPath = Path.Combine(resDir, "SupabaseClientSecrets.json");
|
||||
File.WriteAllText(outPath, json);
|
||||
|
||||
AssetDatabase.ImportAsset(RelativeToProject(outPath));
|
||||
Debug.Log("Embedded SupabaseClientSecrets.json");
|
||||
}
|
||||
|
||||
static string RelativeToProject(string abs)
|
||||
{
|
||||
var root = Application.dataPath[..^"Assets".Length];
|
||||
return abs.Replace(root, "").Replace("\\", "/");
|
||||
}
|
||||
}
|
||||
#endif
|
2
Assets/Editor/GenerateSupabaseSecretsPrebuild.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eaaa4e4797f4ddc46ba77c5cb7cfa543
|
205
Assets/Editor/PlayersDevTools.cs
Normal file
@ -0,0 +1,205 @@
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using System.Text.Json;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Supabase;
|
||||
using Postgrest;
|
||||
using Postgrest.Attributes;
|
||||
using Postgrest.Models;
|
||||
|
||||
#region DB Model
|
||||
|
||||
[Table("players")]
|
||||
public class PlayerRow : BaseModel
|
||||
{
|
||||
[PrimaryKey("wallet_address", false)]
|
||||
[Column("wallet_address")] public string WalletAddress { get; set; }
|
||||
|
||||
[Column("total_kills")] public int TotalKills { get; set; }
|
||||
[Column("average_placement")] public decimal? AveragePlacement { get; set; }
|
||||
[Column("win_percentage")] public decimal? WinPercentage { get; set; }
|
||||
[Column("in_game_currency")] public long InGameCurrency { get; set; }
|
||||
|
||||
// jsonb – we'll send/receive as a plain object map
|
||||
[Column("purchased_items")] public Dictionary<string, object> PurchasedItems { get; set; } = new();
|
||||
|
||||
[Column("updated_at")] public DateTimeOffset? UpdatedAt { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public class PlayersDevTools : EditorWindow
|
||||
{
|
||||
// Inputs
|
||||
string wallet = "dev_wallet_test_1";
|
||||
int totalKills = 3;
|
||||
double avgPlacement = 2.5;
|
||||
double winPct = 55.25;
|
||||
long currency = 1000;
|
||||
string purchasedJson = "{\"starter_pack\":true,\"sword\":\"iron\"}";
|
||||
|
||||
Supabase.Client client;
|
||||
|
||||
[MenuItem("Tools/Supabase/Players Tester")]
|
||||
public static void Open() => GetWindow<PlayersDevTools>("Players Tester");
|
||||
|
||||
async void OnEnable() => await EnsureClient();
|
||||
|
||||
async Task EnsureClient()
|
||||
{
|
||||
if (client != null) return;
|
||||
var s = await SupabaseSecretsLoader.LoadAsync(); // editor dev json or Resources
|
||||
var opts = new SupabaseOptions { AutoRefreshToken = true, AutoConnectRealtime = false, Schema = "public" };
|
||||
client = new Supabase.Client(s.url, s.anonKey, opts);
|
||||
await client.InitializeAsync();
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
EditorGUILayout.LabelField("Upsert / Read / Delete: public.players", EditorStyles.boldLabel);
|
||||
EditorGUILayout.Space();
|
||||
|
||||
wallet = EditorGUILayout.TextField("wallet_address", wallet);
|
||||
totalKills = EditorGUILayout.IntField("total_kills", totalKills);
|
||||
avgPlacement = EditorGUILayout.DoubleField("average_placement", avgPlacement);
|
||||
winPct = EditorGUILayout.DoubleField("win_percentage", winPct);
|
||||
currency = EditorGUILayout.LongField("in_game_currency", currency);
|
||||
purchasedJson = EditorGUILayout.TextField("purchased_items (json)", purchasedJson);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("UPSERT")) _ = UpsertAsync();
|
||||
if (GUILayout.Button("READ")) _ = ReadAsync();
|
||||
if (GUILayout.Button("DELETE")) _ = DeleteAsync();
|
||||
}
|
||||
}
|
||||
|
||||
async Task UpsertAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await EnsureClient();
|
||||
|
||||
var row = new PlayerRow
|
||||
{
|
||||
WalletAddress = wallet,
|
||||
TotalKills = totalKills,
|
||||
AveragePlacement = (decimal)avgPlacement,
|
||||
WinPercentage = (decimal)winPct,
|
||||
InGameCurrency = currency,
|
||||
PurchasedItems = ParseDict(purchasedJson),
|
||||
UpdatedAt = DateTimeOffset.UtcNow
|
||||
};
|
||||
|
||||
// postgrest-csharp 3.5.x – Upsert by PK, no onConflict param
|
||||
var resp = await client.From<PlayerRow>().Upsert(row);
|
||||
var saved = resp.Models.Count > 0 ? resp.Models[0] : row;
|
||||
|
||||
Debug.Log($"✅ UPSERT OK -> wallet={saved.WalletAddress} kills={saved.TotalKills} currency={saved.InGameCurrency}");
|
||||
ShowNotification(new GUIContent("UPSERT OK"));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"UPSERT FAILED: {e.Message}");
|
||||
ShowNotification(new GUIContent("UPSERT FAILED"));
|
||||
}
|
||||
}
|
||||
|
||||
async Task ReadAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await EnsureClient();
|
||||
|
||||
var resp = await client
|
||||
.From<PlayerRow>()
|
||||
.Select("*") // 3.5.x needs a string
|
||||
.Filter("wallet_address", Postgrest.Constants.Operator.Equals, wallet)
|
||||
.Get();
|
||||
|
||||
if (resp.Models.Count == 0)
|
||||
{
|
||||
Debug.LogWarning("No row found.");
|
||||
ShowNotification(new GUIContent("NOT FOUND"));
|
||||
return;
|
||||
}
|
||||
|
||||
var p = resp.Models[0];
|
||||
Debug.Log($"✅ READ -> wallet={p.WalletAddress}, kills={p.TotalKills}, avg={p.AveragePlacement}, win%={p.WinPercentage}, cur={p.InGameCurrency}, items={JsonSerializer.Serialize(p.PurchasedItems)}");
|
||||
ShowNotification(new GUIContent("READ OK"));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"READ FAILED: {e.Message}");
|
||||
ShowNotification(new GUIContent("READ FAILED"));
|
||||
}
|
||||
}
|
||||
|
||||
async Task DeleteAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await EnsureClient();
|
||||
|
||||
await client
|
||||
.From<PlayerRow>()
|
||||
.Filter("wallet_address", Postgrest.Constants.Operator.Equals, wallet)
|
||||
.Delete();
|
||||
|
||||
Debug.Log("✅ DELETE OK");
|
||||
ShowNotification(new GUIContent("DELETE OK"));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"DELETE FAILED: {e.Message}");
|
||||
ShowNotification(new GUIContent("DELETE FAILED"));
|
||||
}
|
||||
}
|
||||
|
||||
// -------- JSON helpers (System.Text.Json) --------
|
||||
static Dictionary<string, object> ParseDict(string json)
|
||||
{
|
||||
var result = new Dictionary<string, object>();
|
||||
if (string.IsNullOrWhiteSpace(json)) return result;
|
||||
|
||||
try
|
||||
{
|
||||
using var doc = JsonDocument.Parse(json);
|
||||
if (doc.RootElement.ValueKind != JsonValueKind.Object) return result;
|
||||
|
||||
foreach (var p in doc.RootElement.EnumerateObject())
|
||||
result[p.Name] = ToPlain(p.Value);
|
||||
}
|
||||
catch { /* ignore -> empty dict */ }
|
||||
return result;
|
||||
}
|
||||
|
||||
static object ToPlain(JsonElement e)
|
||||
{
|
||||
switch (e.ValueKind)
|
||||
{
|
||||
case JsonValueKind.String: return e.GetString();
|
||||
case JsonValueKind.Number:
|
||||
if (e.TryGetInt64(out var l)) return l;
|
||||
if (e.TryGetDouble(out var d)) return d;
|
||||
return e.GetRawText();
|
||||
case JsonValueKind.True: return true;
|
||||
case JsonValueKind.False: return false;
|
||||
case JsonValueKind.Null: return null;
|
||||
case JsonValueKind.Array:
|
||||
var list = new List<object>();
|
||||
foreach (var it in e.EnumerateArray()) list.Add(ToPlain(it));
|
||||
return list;
|
||||
case JsonValueKind.Object:
|
||||
var dict = new Dictionary<string, object>();
|
||||
foreach (var p in e.EnumerateObject()) dict[p.Name] = ToPlain(p.Value);
|
||||
return dict;
|
||||
default: return e.GetRawText();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
2
Assets/Editor/PlayersDevTools.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e00fc484bb422604caed4b0cf9609e65
|
53
Assets/Editor/SupabaseSecretsVerifier.cs
Normal file
@ -0,0 +1,53 @@
|
||||
#if UNITY_EDITOR
|
||||
using System.Threading.Tasks;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
using Supabase;
|
||||
|
||||
public static class SupabaseSecretsVerifier
|
||||
{
|
||||
[MenuItem("Tools/Supabase/Verify Secrets (Editor)")]
|
||||
public static void VerifyMenu() { _ = VerifyAsync(); }
|
||||
|
||||
static string Mask(string s) =>
|
||||
string.IsNullOrEmpty(s) ? "<empty>" :
|
||||
(s.Length <= 8 ? $"***{s[^4..]}" : $"{s[..4]}***{s[^6..]}");
|
||||
|
||||
static async Task VerifyAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 1) Load secrets (dev file in Editor OR Resources if present)
|
||||
var sec = await SupabaseSecretsLoader.LoadAsync();
|
||||
|
||||
// 2) Log masked values
|
||||
Debug.Log($"[Supabase] URL: {sec.url}\nAnon: {Mask(sec.anonKey)}");
|
||||
|
||||
// 3) Try Client init (no network calls needed here)
|
||||
var opts = new SupabaseOptions { AutoConnectRealtime = false, AutoRefreshToken = true };
|
||||
var client = new Client(sec.url, sec.anonKey, opts);
|
||||
await client.InitializeAsync();
|
||||
|
||||
// 4) Optional lightweight API ping (Auth health -> 200 OK)
|
||||
var healthUrl = $"{sec.url.TrimEnd('/')}/auth/v1/health";
|
||||
using var req = UnityWebRequest.Get(healthUrl);
|
||||
req.SetRequestHeader("apikey", sec.anonKey);
|
||||
await req.SendWebRequest();
|
||||
|
||||
var ok = req.result == UnityWebRequest.Result.Success && req.responseCode == 200;
|
||||
var msg = ok ? "✅ Secrets OK: Editor can init Supabase and reach /auth/v1/health."
|
||||
: $"⚠️ Init OK but health probe returned {req.responseCode} ({req.error}). " +
|
||||
"This can be blocked by firewall; init still proves secrets are loaded.";
|
||||
|
||||
Debug.Log(msg);
|
||||
EditorUtility.DisplayDialog("Supabase Secrets", msg + $"\n\nHost: {new System.Uri(sec.url).Host}\nAnon: {Mask(sec.anonKey)}", "OK");
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.LogError($"❌ Supabase secrets verification failed: {ex.Message}");
|
||||
EditorUtility.DisplayDialog("Supabase Secrets", "❌ Verification failed:\n" + ex.Message, "OK");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
2
Assets/Editor/SupabaseSecretsVerifier.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c3a3724e5f6cb2e45a163af4ede0050f
|
1
Assets/Editor/supabase.secrets.dev.json
Normal file
@ -0,0 +1 @@
|
||||
{"url":"https://ouhzztijvgrvjpdvgido.supabase.co","anonKey":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im91aHp6dGlqdmdydmpwZHZnaWRvIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjAxNjQzNzUsImV4cCI6MjA3NTc0MDM3NX0.60JLI7OIAZRiqNg0SOHPPORMkCcspHvFD7LwETRwUDE"}
|
7
Assets/Editor/supabase.secrets.dev.json.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b0912cbe91eaaa4c866ee4da239a044
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
47
Assets/PlayerWalletAddress.cs
Normal file
@ -0,0 +1,47 @@
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
namespace TPSBR
|
||||
{
|
||||
|
||||
public class PlayerWalletAddress : MonoBehaviour
|
||||
{
|
||||
string firstFourChars = "";
|
||||
string lastFourChars = "";
|
||||
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
||||
void Start()
|
||||
{
|
||||
if (PlayerPrefs.HasKey("WALLET_ADDRESS"))
|
||||
{
|
||||
GetTruncatedString();
|
||||
this.GetComponent<TextMeshProUGUI>().text = firstFourChars + "......" + lastFourChars;
|
||||
}
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
public void GetTruncatedString()
|
||||
{
|
||||
string originalString = PlayerPrefs.GetString("WALLET_ADDRESS");
|
||||
|
||||
if (originalString.Length >= 4)
|
||||
{
|
||||
firstFourChars = originalString.Substring(0, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
firstFourChars = originalString; // Or handle as needed if shorter
|
||||
}
|
||||
if (originalString.Length >= 4)
|
||||
{
|
||||
lastFourChars = originalString.Substring(originalString.Length - 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
lastFourChars = originalString; // Or handle as needed if shorter
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
2
Assets/PlayerWalletAddress.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1f3d1b1bb90e0a1468f1bba7758e40ad
|
1
Assets/Resources/SupabaseClientSecrets.json
Normal file
@ -0,0 +1 @@
|
||||
{"url":"https://ouhzztijvgrvjpdvgido.supabase.co","anonKey":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im91aHp6dGlqdmdydmpwZHZnaWRvIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjAxNjQzNzUsImV4cCI6MjA3NTc0MDM3NX0.60JLI7OIAZRiqNg0SOHPPORMkCcspHvFD7LwETRwUDE"}
|
7
Assets/Resources/SupabaseClientSecrets.json.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0f7224fac46612a4b9d9a07e54761e97
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
35
Assets/Resources/WalletConnectConnectionProvider.asset
Normal file
@ -0,0 +1,35 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 582efc0fde77aab43a77ee4237ba305a, type: 3}
|
||||
m_Name: WalletConnectConnectionProvider
|
||||
m_EditorClassIdentifier:
|
||||
<ProjectId>k__BackingField: 0b840bb98f4fea8ce4647bc0b0de86a0
|
||||
<ProjectName>k__BackingField: BRSol
|
||||
<AutoRenewSession>k__BackingField: 1
|
||||
<BaseContext>k__BackingField: unity-game
|
||||
<Metadata>k__BackingField:
|
||||
Name:
|
||||
Description:
|
||||
Url:
|
||||
Icons: []
|
||||
Redirect:
|
||||
Native:
|
||||
Universal:
|
||||
VerifyUrl:
|
||||
<StoragePath>k__BackingField: wallet-connect/
|
||||
<OverrideRegistryUri>k__BackingField:
|
||||
handlerPrefab: {fileID: 5250797134093199901, guid: 0c7c312ad6c521f4b8346ed8e9d7c664, type: 3}
|
||||
enabledWallets: []
|
||||
disabledWallets: []
|
||||
<LogLevel>k__BackingField: 1
|
||||
<WalletLocationOption>k__BackingField: 0
|
||||
<ConnectButtonRow>k__BackingField: {fileID: 8599114313589093787, guid: 4591cfadb2bf9824da90ebf4005728a8, type: 3}
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4cff9744a34ebe64b8bb75767a8b96cd
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
BIN
Assets/Scenes/6547356-middle.png
Normal file
After Width: | Height: | Size: 67 KiB |
156
Assets/Scenes/6547356-middle.png.meta
Normal file
@ -0,0 +1,156 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2aa4e0d266612134984241a04bbb34db
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 2
|
||||
mipBias: 0
|
||||
wrapU: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 4
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: iOS
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Android
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: WindowsStoreApps
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
customData:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
19
Assets/Scripts/AppKitConfigInstaller.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace TPSBR
|
||||
{
|
||||
public class AppKitConfigInstaller : MonoBehaviour
|
||||
{
|
||||
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
||||
void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
2
Assets/Scripts/AppKitConfigInstaller.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1a9c92c8d28c4e44a99a8f4d42c4b64a
|
439
Assets/Scripts/AppKitMetadataInjector.cs
Normal file
@ -0,0 +1,439 @@
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using Reown.AppKit.Unity;
|
||||
using Reown.AppKit.Unity.Model;
|
||||
using System;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
[DefaultExecutionOrder(1000)]
|
||||
public class AppKitMetadataInjector : MonoBehaviour
|
||||
{
|
||||
[Header("WalletConnect Cloud Project ID")]
|
||||
[SerializeField] private string projectId = "0b840bb98f4fea8ce4647bc0b0de86a0";
|
||||
|
||||
[Header("Branding")]
|
||||
[SerializeField] private string appName = "BR Game";
|
||||
[SerializeField] private string appDescription = "Public PC build (QR connect via phone)";
|
||||
[SerializeField] private string appUrl = "https://example.com";
|
||||
[SerializeField] private string appIconUrl = "https://walletconnect.com/meta/favicon.ico";
|
||||
|
||||
[Header("Chains (first one becomes default)")]
|
||||
[SerializeField] private bool useEthereum = true; // eip155:1
|
||||
[SerializeField] private bool usePolygon = true; // eip155:137
|
||||
[SerializeField] private bool useBase = true; // eip155:8453
|
||||
|
||||
private bool _initialized;
|
||||
private string _defaultChainId = "eip155:1";
|
||||
|
||||
private IEnumerator Start()
|
||||
{
|
||||
|
||||
// Wait until the prefab set AppKit.Instance
|
||||
while (AppKit.Instance == null) yield return null;
|
||||
|
||||
// Build metadata + config
|
||||
var md = new Metadata(appName, appDescription, appUrl, appIconUrl);
|
||||
var cfg = new AppKitConfig(projectId, md)
|
||||
{
|
||||
enableEmail = false,
|
||||
enableOnramp = false,
|
||||
enableCoinbaseWallet = false,
|
||||
connectViewWalletsCountDesktop = 2,
|
||||
connectViewWalletsCountMobile = 3,
|
||||
};
|
||||
|
||||
// Build supported chains list (order matters: first = default)
|
||||
EnableDesktopWallets(cfg);
|
||||
var chains = new System.Collections.Generic.List<Chain>();
|
||||
if (useEthereum) chains.Add(ChainConstants.Chains.Ethereum);
|
||||
if (usePolygon) chains.Add(ChainConstants.Chains.Polygon);
|
||||
if (useBase) chains.Add(ChainConstants.Chains.Base);
|
||||
if (chains.Count == 0) chains.Add(ChainConstants.Chains.Ethereum);
|
||||
|
||||
cfg.supportedChains = chains.ToArray();
|
||||
_defaultChainId = cfg.supportedChains[0].ChainId; // remember default
|
||||
|
||||
// Set AppKit.Config via private setter (reflection) BEFORE init
|
||||
var cfgProp = typeof(AppKit).GetProperty("Config",
|
||||
BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
|
||||
cfgProp.SetValue(null, cfg);
|
||||
|
||||
// Initialize (supports InitializeAsync(cfg) / Initialize(cfg) / no-arg)
|
||||
yield return InitializeAppKit(cfg);
|
||||
|
||||
// Select default chain if API exists (some builds require this)
|
||||
var selectChain = typeof(AppKit).GetMethod("SelectChain",
|
||||
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
if (selectChain != null)
|
||||
selectChain.Invoke(null, new object[] { _defaultChainId });
|
||||
|
||||
_initialized = true;
|
||||
Debug.Log($"✅ AppKit initialized. Default chain: {_defaultChainId}");
|
||||
AppKit.ConnectorController.AccountConnected += OnWalletConnected;
|
||||
|
||||
}
|
||||
|
||||
// Button hook
|
||||
public void OnWalletConnectButton()
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
StartCoroutine(OpenAfterReady());
|
||||
return;
|
||||
}
|
||||
//AppKit.OpenModal(ViewType.Connect); // shows QR
|
||||
//AppKit.ConnectorController.AccountConnected += OnWalletConnected;
|
||||
OpenQrModal();
|
||||
}
|
||||
public void OnBrowserExtensionButton()
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
StartCoroutine(ConnectDesktopAfterReady());
|
||||
return;
|
||||
}
|
||||
|
||||
TriggerDesktopConnect();
|
||||
}
|
||||
|
||||
// Waits until initialized; doesn't re-init
|
||||
private IEnumerator OpenAfterReady()
|
||||
{
|
||||
yield return WaitForInitialization();
|
||||
OpenQrModal();
|
||||
}
|
||||
|
||||
private IEnumerator ConnectDesktopAfterReady()
|
||||
{
|
||||
yield return WaitForInitialization();
|
||||
TriggerDesktopConnect();
|
||||
}
|
||||
|
||||
private IEnumerator WaitForInitialization()
|
||||
{
|
||||
var isInitProp = typeof(AppKit).GetProperty("IsInitialized",
|
||||
BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
|
||||
|
||||
while (isInitProp != null && !(bool)isInitProp.GetValue(null))
|
||||
yield return null;
|
||||
yield break;
|
||||
}
|
||||
|
||||
private void OpenQrModal()
|
||||
{
|
||||
AppKit.OpenModal(ViewType.Connect);
|
||||
AppKit.ConnectorController.AccountConnected += OnWalletConnected;
|
||||
}
|
||||
|
||||
private void TriggerDesktopConnect()
|
||||
{
|
||||
var controller = AppKit.ConnectorController;
|
||||
if (controller == null)
|
||||
{
|
||||
Debug.LogWarning("AppKit ConnectorController unavailable for desktop connection.");
|
||||
return;
|
||||
}
|
||||
|
||||
var controllerType = controller.GetType();
|
||||
var methods = controllerType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
|
||||
foreach (var method in methods)
|
||||
{
|
||||
if (method.Name != "ConnectAsync") continue;
|
||||
|
||||
var parameters = method.GetParameters();
|
||||
if (parameters.Length == 0) continue;
|
||||
|
||||
var args = new object[parameters.Length];
|
||||
var success = true;
|
||||
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
var paramType = parameters[i].ParameterType;
|
||||
|
||||
if (paramType.IsEnum && paramType.Name.Contains("ConnectMethod"))
|
||||
{
|
||||
try
|
||||
{
|
||||
args[i] = Enum.Parse(paramType, "Desktop", true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (paramType.Name.Contains("ConnectParams"))
|
||||
{
|
||||
args[i] = Activator.CreateInstance(paramType);
|
||||
}
|
||||
else if (paramType.FullName == typeof(System.Threading.CancellationToken).FullName)
|
||||
{
|
||||
args[i] = default(System.Threading.CancellationToken);
|
||||
}
|
||||
else if (paramType.IsValueType)
|
||||
{
|
||||
args[i] = Activator.CreateInstance(paramType);
|
||||
}
|
||||
else
|
||||
{
|
||||
args[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) continue;
|
||||
|
||||
var result = method.Invoke(controller, args);
|
||||
if (result is Task task)
|
||||
{
|
||||
StartCoroutine(WaitForTask(task));
|
||||
}
|
||||
|
||||
AppKit.ConnectorController.AccountConnected += OnWalletConnected;
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.LogWarning("Unable to locate desktop ConnectAsync overload; falling back to QR modal.");
|
||||
OpenQrModal();
|
||||
}
|
||||
|
||||
private IEnumerator WaitForTask(Task task)
|
||||
{
|
||||
while (task != null && !task.IsCompleted)
|
||||
yield return null;
|
||||
|
||||
yield break;
|
||||
}
|
||||
|
||||
private IEnumerator InitializeAppKit(AppKitConfig cfg)
|
||||
{
|
||||
var isInitProp = typeof(AppKit).GetProperty("IsInitialized",
|
||||
BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
|
||||
if (isInitProp != null && (bool)isInitProp.GetValue(null)) yield break;
|
||||
|
||||
var flags = BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public;
|
||||
|
||||
var initAsync = typeof(AppKit).GetMethod("InitializeAsync", flags);
|
||||
if (initAsync != null)
|
||||
{
|
||||
var ps = initAsync.GetParameters();
|
||||
var result = ps.Length == 1
|
||||
? initAsync.Invoke(null, new object[] { cfg })
|
||||
: initAsync.Invoke(null, null);
|
||||
|
||||
if (result is Task t)
|
||||
while (!t.IsCompleted) yield return null;
|
||||
|
||||
yield break;
|
||||
}
|
||||
|
||||
var init = typeof(AppKit).GetMethod("Initialize", flags);
|
||||
if (init != null)
|
||||
{
|
||||
var ps = init.GetParameters();
|
||||
var result = ps.Length == 1
|
||||
? init.Invoke(null, new object[] { cfg })
|
||||
: init.Invoke(null, null);
|
||||
|
||||
if (result is Task t)
|
||||
while (!t.IsCompleted) yield return null;
|
||||
|
||||
yield break;
|
||||
}
|
||||
|
||||
// If neither exists, rely on prefab auto-init
|
||||
yield return null;
|
||||
}
|
||||
|
||||
private void OnWalletConnected(object sender, Reown.AppKit.Unity.Connector.AccountConnectedEventArgs e)
|
||||
{
|
||||
Debug.Log("✅ Wallet connected!");
|
||||
Debug.Log($"Address: {e.Account.Address}");
|
||||
PlayerPrefs.SetString("WALLET_ADDRESS", e.Account.Address);
|
||||
PlayerLoginOrSignup();
|
||||
SceneManager.LoadScene(1);
|
||||
|
||||
}
|
||||
private void EnableDesktopWallets(AppKitConfig cfg)
|
||||
{
|
||||
TrySetConfigBoolean(cfg, "enableEIP6963", true);
|
||||
TrySetConfigBoolean(cfg, "enableInjected", true);
|
||||
TrySetConfigBoolean(cfg, "enableDesktop", true);
|
||||
TrySetConfigBoolean(cfg, "enableDesktopWallets", true);
|
||||
TrySetConfigBoolean(cfg, "enableInjectedWallets", true);
|
||||
}
|
||||
|
||||
private void TrySetConfigBoolean(AppKitConfig cfg, string memberName, bool value)
|
||||
{
|
||||
var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
||||
var type = cfg.GetType();
|
||||
|
||||
var prop = type.GetProperty(memberName, flags);
|
||||
if (prop != null && prop.CanWrite && prop.PropertyType == typeof(bool))
|
||||
{
|
||||
prop.SetValue(cfg, value);
|
||||
return;
|
||||
}
|
||||
|
||||
var field = type.GetField(memberName, flags);
|
||||
if (field != null && field.FieldType == typeof(bool))
|
||||
{
|
||||
field.SetValue(cfg, value);
|
||||
}
|
||||
}
|
||||
public async void PlayerLoginOrSignup()
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
var rec = await GameDb.WalletConnectedAsync(PlayerPrefs.GetString("WALLET_ADDRESS"));
|
||||
Debug.Log($"[Runtime] ✅ Ensured player: {rec.WalletAddress} kills={rec.TotalKills} currency={rec.InGameCurrency}");
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError($"[Runtime] ❌ Ensure failed: {e.Message}");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
[ContextMenu("AddKill")]
|
||||
public async void AddKill()
|
||||
{
|
||||
try
|
||||
{
|
||||
var rec = await GameDb.AddKillAsync(PlayerPrefs.GetString("WALLET_ADDRESS"));
|
||||
Debug.Log($"[Runtime] ✅ Ensured player: {rec.WalletAddress} kills={rec.TotalKills} currency={rec.InGameCurrency}");
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError($"[Runtime] ❌ Ensure failed: {e.Message}");
|
||||
}
|
||||
}
|
||||
[ContextMenu("AddCurrency")]
|
||||
|
||||
public async void AddCurrency()
|
||||
{
|
||||
try
|
||||
{
|
||||
var rec = await GameDb.AddCurrencyAsync(PlayerPrefs.GetString("WALLET_ADDRESS"),100);
|
||||
Debug.Log($"[Runtime] ✅ Ensured player: {rec.WalletAddress} kills={rec.TotalKills} currency={rec.InGameCurrency}");
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError($"[Runtime] ❌ Ensure failed: {e.Message}");
|
||||
}
|
||||
}
|
||||
[ContextMenu("GetCurrency")]
|
||||
|
||||
public async void GetCurrency()
|
||||
{
|
||||
try
|
||||
{
|
||||
var rec = await GameDb.GetCurrencyAsync(PlayerPrefs.GetString("WALLET_ADDRESS"));
|
||||
Debug.Log(rec.ToString());
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError($"[Runtime] ❌ Ensure failed: {e.Message}");
|
||||
}
|
||||
}
|
||||
[ContextMenu("GetInventory")]
|
||||
|
||||
public async void GetPurchasedItem()
|
||||
{
|
||||
try
|
||||
{
|
||||
var rec = await GameDb.GetPurchasedItemsJsonAsync(PlayerPrefs.GetString("WALLET_ADDRESS"));
|
||||
Debug.Log(rec.ToString());
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError($"[Runtime] ❌ Ensure failed: {e.Message}");
|
||||
}
|
||||
}
|
||||
[ContextMenu("AddGamesPlayed")]
|
||||
|
||||
public async void AddGamesPlayed()
|
||||
{
|
||||
try
|
||||
{
|
||||
var rec = await GameDb.IncGamesPlayedAsync(PlayerPrefs.GetString("WALLET_ADDRESS"));
|
||||
Debug.Log(rec.ToString());
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError($"[Runtime] ❌ Ensure failed: {e.Message}");
|
||||
}
|
||||
}
|
||||
[ContextMenu("GetplayerData")]
|
||||
|
||||
public async void PlayerDataAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var rec = await GameDb.GetPlayerAsync(PlayerPrefs.GetString("WALLET_ADDRESS"));
|
||||
Debug.Log(rec.ToString());
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError($"[Runtime] ❌ Ensure failed: {e.Message}");
|
||||
}
|
||||
|
||||
}
|
||||
[ContextMenu("Placement")]
|
||||
|
||||
public async void PlayerPlacement()
|
||||
{
|
||||
try
|
||||
{
|
||||
var rec = await GameDb.SendGameWinAsync(PlayerPrefs.GetString("WALLET_ADDRESS"),1);
|
||||
Debug.Log(rec.ToString());
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError($"[Runtime] ❌ Ensure failed: {e.Message}");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
[ContextMenu("ItemBought")]
|
||||
|
||||
public async void AddPurchaseItem()
|
||||
{
|
||||
try
|
||||
{
|
||||
var rec = await GameDb.AddPurchasedItemAsync(PlayerPrefs.GetString("WALLET_ADDRESS"), "ChadGuy");
|
||||
Debug.Log(rec.ToString());
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError($"[Runtime] ❌ Ensure failed: {e.Message}");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
[ContextMenu("CheckName")]
|
||||
|
||||
public async void OnWalletConnected(string wallet) // call this from your wallet SDK
|
||||
{
|
||||
try
|
||||
{
|
||||
// makes sure the row exists (display_name = "" on first create)
|
||||
await GameDb.GetPlayerNameAsync(wallet);
|
||||
Debug.Log($"Player ensured for {wallet}");
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
}
|
||||
}
|
||||
public void LoginAsGuest()
|
||||
{
|
||||
|
||||
SceneManager.LoadScene(1);
|
||||
|
||||
}
|
||||
}
|
||||
|
2
Assets/Scripts/AppKitMetadataInjector.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ea6984f3d743ff64da14b7927db196c6
|
8
Assets/Scripts/Config.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3c7fc92f5bf6c4c4593d42bbb81c5642
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
16
Assets/Scripts/Config/SupabaseSecretsLoader.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
[System.Serializable] public class SupabaseClientSecrets { public string url; public string anonKey; }
|
||||
|
||||
public static class SupabaseSecretsLoader
|
||||
{
|
||||
public static async Task<SupabaseClientSecrets> LoadAsync()
|
||||
{
|
||||
var ta = Resources.Load<TextAsset>("SupabaseClientSecrets");
|
||||
if (ta == null || string.IsNullOrWhiteSpace(ta.text))
|
||||
throw new System.Exception("SupabaseClientSecrets.json missing. Did prebuild run?");
|
||||
await Task.Yield();
|
||||
return JsonUtility.FromJson<SupabaseClientSecrets>(ta.text);
|
||||
}
|
||||
}
|
2
Assets/Scripts/Config/SupabaseSecretsLoader.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6bbc9308b37c47c43b5ceea25619377e
|
8
Assets/Scripts/ConnectWalletButton.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using UnityEngine;
|
||||
using Reown.AppKit.Unity;
|
||||
using Reown.AppKit.Unity.Model;
|
||||
|
||||
public class AppKitConfigInstaller : MonoBehaviour
|
||||
{
|
||||
|
||||
}
|
2
Assets/Scripts/ConnectWalletButton.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f094ac8197426c44c9248e777c8c3fcd
|
287
Assets/Scripts/GameDb.cs
Normal file
@ -0,0 +1,287 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Supabase;
|
||||
using Postgrest;
|
||||
using Game.Data;
|
||||
using UnityEngine; // for PlayerPrefs
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
public static class GameDb
|
||||
{
|
||||
private static Supabase.Client _client;
|
||||
private const string PrefsWalletKey = "WALLET_ADDRESS";
|
||||
private const string PrefsName = "DISPLAY_NAME";
|
||||
public static async Task InitAsync()
|
||||
{
|
||||
if (_client != null) return;
|
||||
var s = await SupabaseSecretsLoader.LoadAsync();
|
||||
var opts = new SupabaseOptions { AutoConnectRealtime = false, AutoRefreshToken = true, Schema = "public" };
|
||||
_client = new Supabase.Client(s.url, s.anonKey, opts);
|
||||
await _client.InitializeAsync();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// WalletConnected: check if exists, create if missing, store in PlayerPrefs
|
||||
// ------------------------------------------------------------
|
||||
//public static async Task<PlayerRecord> WalletConnectedAsync(string walletAddress)
|
||||
//{
|
||||
// if (string.IsNullOrWhiteSpace(walletAddress))
|
||||
// throw new ArgumentException("walletAddress cannot be empty.");
|
||||
|
||||
// await InitAsync();
|
||||
|
||||
// // exists?
|
||||
// var existing = await _client.From<PlayerRecord>()
|
||||
// .Select("*")
|
||||
// .Filter("wallet_address", Postgrest.Constants.Operator.Equals, walletAddress)
|
||||
// .Get();
|
||||
|
||||
// PlayerRecord result;
|
||||
// if (existing.Models.Count > 0)
|
||||
// {
|
||||
// result = existing.Models[0];
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // insert minimal row (DB supplies defaults & computed columns)
|
||||
// var insert = await _client.From<PlayerRecord>().Insert(new PlayerRecord { WalletAddress = walletAddress });
|
||||
// result = insert.Models.Count > 0 ? insert.Models[0] : new PlayerRecord { WalletAddress = walletAddress };
|
||||
// }
|
||||
|
||||
// // "login success": save wallet locally
|
||||
// PlayerPrefs.SetString(PrefsWalletKey, walletAddress);
|
||||
// PlayerPrefs.Save();
|
||||
|
||||
// return result;
|
||||
//}
|
||||
public static async Task<PlayerRecord> WalletConnectedAsync(string walletAddress)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(walletAddress))
|
||||
throw new ArgumentException("walletAddress cannot be empty.");
|
||||
|
||||
await InitAsync();
|
||||
|
||||
// Atomic, safe, and won’t try to write generated columns.
|
||||
var rows = await _client.Rpc<List<PlayerRecord>>("ensure_player", new { p_wallet = walletAddress });
|
||||
var player = rows != null && rows.Count > 0 ? rows[0] : null;
|
||||
|
||||
if (player == null)
|
||||
throw new Exception("ensure_player RPC returned no row.");
|
||||
|
||||
PlayerPrefs.SetString("WALLET_ADDRESS", walletAddress);
|
||||
PlayerPrefs.Save();
|
||||
return player;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// AddKill (+1 by default) -- uses RPC for atomic increment
|
||||
// ------------------------------------------------------------
|
||||
public static async Task<PlayerRecord> AddKillAsync(string walletAddress, int delta = 1)
|
||||
{
|
||||
await InitAsync();
|
||||
var payload = new { p_wallet = walletAddress, p_delta = delta };
|
||||
|
||||
// SQL returns SETOF players → deserialize to a list/array and take first
|
||||
var rows = await _client.Rpc<List<PlayerRecord>>("add_kills", payload);
|
||||
return rows != null && rows.Count > 0 ? rows[0] : null;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Call Supabase-side method to add currency (RPC)
|
||||
// ------------------------------------------------------------
|
||||
public static async Task<PlayerRecord> AddCurrencyAsync(string walletAddress, long delta)
|
||||
{
|
||||
await InitAsync();
|
||||
var payload = new { p_wallet = walletAddress, p_delta = delta };
|
||||
|
||||
var rows = await _client.Rpc<List<PlayerRecord>>("add_currency", payload);
|
||||
return rows != null && rows.Count > 0 ? rows[0] : null;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Get currency for player
|
||||
// ------------------------------------------------------------
|
||||
public static async Task<long> GetCurrencyAsync(string walletAddress)
|
||||
{
|
||||
await InitAsync();
|
||||
var resp = await _client.From<PlayerRecord>()
|
||||
.Select("in_game_currency")
|
||||
.Filter("wallet_address", Postgrest.Constants.Operator.Equals, walletAddress)
|
||||
.Get();
|
||||
|
||||
return resp.Models.Count > 0 ? resp.Models[0].InGameCurrency : 0L;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Get JSON for bought items
|
||||
// ------------------------------------------------------------
|
||||
public static async Task<string> GetPurchasedItemsJsonAsync(string walletAddress)
|
||||
{
|
||||
await InitAsync();
|
||||
var resp = await _client.From<PlayerRecord>()
|
||||
.Select("purchased_items")
|
||||
.Filter("wallet_address", Postgrest.Constants.Operator.Equals, walletAddress)
|
||||
.Get();
|
||||
|
||||
if (resp.Models.Count == 0) return "{}";
|
||||
var dict = resp.Models[0].PurchasedItems ?? new Dictionary<string, object>();
|
||||
return JsonSerializer.Serialize(dict);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Edit JSON for bought items (replace with provided JSON)
|
||||
// ------------------------------------------------------------
|
||||
public static async Task<PlayerRecord> SetPurchasedItemsJsonAsync(string walletAddress, string json)
|
||||
{
|
||||
await InitAsync();
|
||||
var rows = await _client.Rpc<List<PlayerRecord>>(
|
||||
"set_purchased_items",
|
||||
new { p_wallet = walletAddress, p_items = System.Text.Json.JsonDocument.Parse(json).RootElement }
|
||||
);
|
||||
return rows != null && rows.Count > 0 ? rows[0] : null;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// +1 games played / +1 games won (RPCs)
|
||||
// ------------------------------------------------------------
|
||||
public static async Task<PlayerRecord> IncGamesPlayedAsync(string walletAddress)
|
||||
{
|
||||
await InitAsync();
|
||||
var rows = await _client.Rpc<List<PlayerRecord>>("inc_games_played", new { p_wallet = walletAddress });
|
||||
return rows != null && rows.Count > 0 ? rows[0] : null;
|
||||
}
|
||||
|
||||
public static async Task<PlayerRecord> IncGamesWonAsync(string walletAddress)
|
||||
{
|
||||
await InitAsync();
|
||||
var rows = await _client.Rpc<List<PlayerRecord>>("inc_games_won", new { p_wallet = walletAddress });
|
||||
return rows != null && rows.Count > 0 ? rows[0] : null;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Get Player data (full record)
|
||||
// ------------------------------------------------------------
|
||||
public static async Task<PlayerRecord> GetPlayerAsync(string walletAddress)
|
||||
{
|
||||
await InitAsync();
|
||||
var resp = await _client.From<PlayerRecord>()
|
||||
.Select("*")
|
||||
.Filter("wallet_address", Postgrest.Constants.Operator.Equals, walletAddress)
|
||||
.Get();
|
||||
|
||||
return resp.Models.Count > 0 ? resp.Models[0] : null;
|
||||
}
|
||||
public static async Task<PlayerRecord> SendGameWinAsync(
|
||||
string walletAddress, int placement)
|
||||
{
|
||||
await InitAsync();
|
||||
var payload = new
|
||||
{
|
||||
p_wallet = walletAddress,
|
||||
p_placement = placement
|
||||
};
|
||||
var rows = await _client.Rpc<List<PlayerRecord>>("record_game_win", payload);
|
||||
return rows != null && rows.Count > 0 ? rows[0] : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add/overwrite one entry in purchased_items: key -> value (value default true).
|
||||
/// </summary>
|
||||
public static async Task<PlayerRecord> AddPurchasedItemAsync(string walletAddress, string key, object value = null)
|
||||
{
|
||||
await InitAsync();
|
||||
|
||||
// Fallback: serialize -> parse -> take RootElement
|
||||
JsonElement jsonb = value == null
|
||||
? JsonDocument.Parse("true").RootElement
|
||||
: JsonDocument.Parse(JsonSerializer.Serialize(value)).RootElement;
|
||||
|
||||
var payload = new { p_wallet = walletAddress, p_key = key, p_value = jsonb };
|
||||
|
||||
var rows = await _client.Rpc<List<PlayerRecord>>("add_purchased_item", payload);
|
||||
return rows != null && rows.Count > 0 ? rows[0] : null;
|
||||
}
|
||||
static string SanitizeName(string name)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name)) return null;
|
||||
name = name.Trim();
|
||||
// allow letters, numbers, space, underscore, dash; clamp length 3..24
|
||||
name = Regex.Replace(name, @"[^A-Za-z0-9 _\-]", "");
|
||||
if (name.Length < 3) return null;
|
||||
if (name.Length > 24) name = name.Substring(0, 24);
|
||||
return name;
|
||||
}
|
||||
|
||||
// -------- GETTER --------
|
||||
public static async Task<string> GetPlayerNameAsync(string walletAddress)
|
||||
{
|
||||
await InitAsync();
|
||||
var resp = await _client.From<PlayerRecord>()
|
||||
.Select("display_name")
|
||||
.Filter("wallet_address", Postgrest.Constants.Operator.Equals, walletAddress)
|
||||
.Get();
|
||||
|
||||
var name = resp.Models.Count > 0 ? resp.Models[0].DisplayName ?? "" : "";
|
||||
// cache (optional)
|
||||
PlayerPrefs.SetString(PrefsName, name);
|
||||
PlayerPrefs.Save();
|
||||
return name;
|
||||
}
|
||||
|
||||
// -------- CHECK EMPTY (DB) --------
|
||||
public static async Task<bool> IsNameEmptyAsync(string walletAddress)
|
||||
{
|
||||
var name = await GetPlayerNameAsync(walletAddress);
|
||||
return string.IsNullOrEmpty(name);
|
||||
}
|
||||
|
||||
// -------- SETTER: only if empty (safe path) --------
|
||||
// Calls your SQL function: set_name_if_empty(p_wallet, p_name)
|
||||
public static async Task<PlayerRecord> SetNameIfEmptyAsync(string walletAddress, string proposedName)
|
||||
{
|
||||
await InitAsync();
|
||||
|
||||
var clean = SanitizeName(proposedName);
|
||||
if (string.IsNullOrEmpty(clean))
|
||||
throw new ArgumentException("Invalid name. Use 3–24 chars: letters, numbers, space, _ or -.");
|
||||
|
||||
// RPC returns the player row (whether it updated or not)
|
||||
var rows = await _client.Rpc<List<PlayerRecord>>(
|
||||
"set_name_if_empty",
|
||||
new { p_wallet = walletAddress, p_name = clean }
|
||||
);
|
||||
|
||||
var player = rows != null && rows.Count > 0 ? rows[0] : null;
|
||||
if (player == null) throw new Exception("set_name_if_empty returned no row.");
|
||||
|
||||
PlayerPrefs.SetString(PrefsName, player.DisplayName ?? "");
|
||||
PlayerPrefs.Save();
|
||||
return player;
|
||||
}
|
||||
|
||||
// -------- SETTER: force update (optional, for rename UI) --------
|
||||
public static async Task<PlayerRecord> SetNameAsync(string walletAddress, string newName)
|
||||
{
|
||||
await InitAsync();
|
||||
|
||||
var clean = SanitizeName(newName);
|
||||
if (string.IsNullOrEmpty(clean))
|
||||
throw new ArgumentException("Invalid name. Use 3–24 chars: letters, numbers, space, _ or -.");
|
||||
|
||||
// RPC returns the row; no SDK .Set() nonsense, no risk of overwriting other fields
|
||||
var rows = await _client.Rpc<List<PlayerRecord>>(
|
||||
"set_name",
|
||||
new { p_wallet = walletAddress, p_name = clean }
|
||||
);
|
||||
|
||||
var rec = rows != null && rows.Count > 0 ? rows[0] : null;
|
||||
if (rec == null) throw new Exception("Name update failed.");
|
||||
|
||||
PlayerPrefs.SetString("DISPLAY_NAME", rec.DisplayName ?? "");
|
||||
PlayerPrefs.Save();
|
||||
return rec;
|
||||
}
|
||||
|
||||
}
|
2
Assets/Scripts/GameDb.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 92ed5ec56fc6e9c4398ff98996359355
|
26
Assets/Scripts/PlayerRecord.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Postgrest.Attributes;
|
||||
using Postgrest.Models;
|
||||
|
||||
namespace Game.Data
|
||||
{
|
||||
[Table("players")]
|
||||
public class PlayerRecord : BaseModel
|
||||
{
|
||||
[PrimaryKey("wallet_address", false)]
|
||||
[Column("wallet_address")] public string WalletAddress { get; set; }
|
||||
[Column("display_name")] public string DisplayName { get; set; }
|
||||
[Column("total_kills")] public int TotalKills { get; set; }
|
||||
[Column("in_game_currency")] public long InGameCurrency { get; set; }
|
||||
|
||||
[Column("purchased_items")] public Dictionary<string, object> PurchasedItems { get; set; } = new();
|
||||
|
||||
// server-computed or trigger-updated fields (read-only from client)
|
||||
[Column("average_placement")] public decimal AveragePlacement { get; set; }
|
||||
[Column("win_percentage")] public decimal WinPercentage { get; set; }
|
||||
[Column("games_played")] public int GamesPlayed { get; set; }
|
||||
[Column("games_won")] public int GamesWon { get; set; }
|
||||
[Column("updated_at")] public DateTimeOffset? UpdatedAt { get; set; }
|
||||
}
|
||||
}
|
2
Assets/Scripts/PlayerRecord.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f09b0f00fb687a44dbb2753ea4086cb9
|
29
Assets/Scripts/PlayerRuntimeTest.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using UnityEngine;
|
||||
using Game.Data;
|
||||
|
||||
public class PlayerRuntimeTest : MonoBehaviour
|
||||
{
|
||||
[Header("Fake wallet for test (replace with your wallet connect result)")]
|
||||
public string walletAddress = "runtime_wallet_test_1";
|
||||
|
||||
[ContextMenu("Ensure Player Now")]
|
||||
//public async void EnsureNow()
|
||||
//{
|
||||
// try
|
||||
// {
|
||||
// var rec = await GameDb.EnsurePlayerAsync(walletAddress);
|
||||
// Debug.Log($"[Runtime] ✅ Ensured player: {rec.WalletAddress} kills={rec.TotalKills} currency={rec.InGameCurrency}");
|
||||
// }
|
||||
// catch (System.Exception e)
|
||||
// {
|
||||
// Debug.LogError($"[Runtime] ❌ Ensure failed: {e.Message}");
|
||||
// }
|
||||
//}
|
||||
|
||||
// Optional: auto-run at Start
|
||||
private void Start()
|
||||
{
|
||||
// Comment this if you only want the context menu / UI button
|
||||
// EnsureNow();
|
||||
}
|
||||
}
|
2
Assets/Scripts/PlayerRuntimeTest.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 58bc03d613f30f14cb36ef5bf5768bb1
|
@ -11,15 +11,20 @@ public class SupabaseEmailAuth : MonoBehaviour
|
||||
|
||||
private async void Start()
|
||||
{
|
||||
var options = new SupabaseOptions
|
||||
{
|
||||
AutoRefreshToken = true,
|
||||
AutoConnectRealtime = false
|
||||
};
|
||||
//var options = new SupabaseOptions
|
||||
//{
|
||||
// AutoRefreshToken = true,
|
||||
// AutoConnectRealtime = false
|
||||
//};
|
||||
|
||||
client = new Client(supabaseUrl, supabaseAnonKey, options);
|
||||
await client.InitializeAsync();
|
||||
Debug.Log("Supabase initialized");
|
||||
//client = new Client(supabaseUrl, supabaseAnonKey, options);
|
||||
//await client.InitializeAsync();
|
||||
//Debug.Log("Supabase initialized");
|
||||
var s = await SupabaseSecretsLoader.LoadAsync();
|
||||
if (string.IsNullOrWhiteSpace(s.url) || string.IsNullOrWhiteSpace(s.anonKey))
|
||||
Debug.LogError("Supabase secrets NOT embedded.");
|
||||
else
|
||||
Debug.Log($"Supabase URL OK: {new System.Uri(s.url).Host} (anon present: {s.anonKey.Length > 20})");
|
||||
}
|
||||
|
||||
public async Task SignUp(string email, string password)
|
||||
|
16
Assets/Scripts/SupabaseBootstrap.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using Supabase;
|
||||
using UnityEngine;
|
||||
|
||||
public class SupabaseBootstrap : MonoBehaviour
|
||||
{
|
||||
public static Client Client { get; private set; }
|
||||
|
||||
async void Awake()
|
||||
{
|
||||
var s = await SupabaseSecretsLoader.LoadAsync();
|
||||
var opts = new SupabaseOptions { AutoConnectRealtime = false, AutoRefreshToken = true };
|
||||
Client = new Client(s.url, s.anonKey, opts);
|
||||
await Client.InitializeAsync();
|
||||
Debug.Log("Supabase initialized from secrets.");
|
||||
}
|
||||
}
|
2
Assets/Scripts/SupabaseBootstrap.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a4dea48775d5ed44863c4e2a666486c
|
83
Assets/Scripts/WalletAddressDisplay.cs
Normal file
@ -0,0 +1,83 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using Reown.AppKit.Unity;
|
||||
using TMPro;
|
||||
public class WalletAddressDisplay : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private TextMeshProUGUI addressText; // or TMP_Text
|
||||
[SerializeField] private Button copyButton; // optional
|
||||
|
||||
private string _fullAddress = "";
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (copyButton != null) copyButton.onClick.AddListener(CopyToClipboard);
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
UpdateLabel(); // show current state immediately
|
||||
|
||||
// Subscribe to connection events from the static ConnectorController
|
||||
if (AppKit.ConnectorController != null)
|
||||
{
|
||||
AppKit.ConnectorController.AccountConnected += OnAccountConnected;
|
||||
AppKit.ConnectorController.AccountDisconnected += OnAccountDisconnected;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (AppKit.ConnectorController != null)
|
||||
{
|
||||
AppKit.ConnectorController.AccountConnected -= OnAccountConnected;
|
||||
AppKit.ConnectorController.AccountDisconnected -= OnAccountDisconnected;
|
||||
}
|
||||
|
||||
if (copyButton != null) copyButton.onClick.RemoveListener(CopyToClipboard);
|
||||
}
|
||||
|
||||
private void OnAccountConnected(object _, Reown.AppKit.Unity.Connector.AccountConnectedEventArgs __)
|
||||
{
|
||||
UpdateLabel();
|
||||
}
|
||||
|
||||
private void OnAccountDisconnected(object _, Reown.AppKit.Unity.Connector.AccountDisconnectedEventArgs __)
|
||||
{
|
||||
_fullAddress = "";
|
||||
SetText("Not connected");
|
||||
}
|
||||
|
||||
private void UpdateLabel()
|
||||
{
|
||||
var controller = AppKit.ConnectorController;
|
||||
|
||||
if (controller != null && controller.Account != null)
|
||||
{
|
||||
_fullAddress = controller.Account.Address;
|
||||
SetText(Shorten(_fullAddress));
|
||||
}
|
||||
else
|
||||
{
|
||||
SetText("Not connected");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void CopyToClipboard()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_fullAddress))
|
||||
GUIUtility.systemCopyBuffer = _fullAddress;
|
||||
}
|
||||
|
||||
private static string Shorten(string addr)
|
||||
{
|
||||
if (string.IsNullOrEmpty(addr) || addr.Length < 12) return addr;
|
||||
return addr[..6] + "..." + addr[^4..];
|
||||
}
|
||||
|
||||
private void SetText(string s)
|
||||
{
|
||||
if (addressText != null) addressText.text = s;
|
||||
}
|
||||
}
|
2
Assets/Scripts/WalletAddressDisplay.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b815ce1848c896947bf57fb1a8bf9475
|
167
Assets/SupabasePlayers.cs
Normal file
@ -0,0 +1,167 @@
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Threading.Tasks;
|
||||
//using Supabase;
|
||||
//using Postgrest;
|
||||
//using Postgrest.Attributes;
|
||||
//using Postgrest.Models;
|
||||
|
||||
//#region Model
|
||||
|
||||
//[Table("players")]
|
||||
//public class PlayerRow : BaseModel
|
||||
//{
|
||||
// //[PrimaryKey("wallet_address", false)]
|
||||
// //[Column("wallet_address")]
|
||||
// //public string WalletAddress { get; set; }
|
||||
|
||||
// //[Column("total_kills")]
|
||||
// //public int TotalKills { get; set; }
|
||||
|
||||
// //[Column("average_placement")]
|
||||
// //public decimal? AveragePlacement { get; set; }
|
||||
|
||||
// //[Column("win_percentage")]
|
||||
// //public decimal? WinPercentage { get; set; }
|
||||
|
||||
// //[Column("in_game_currency")]
|
||||
// //public long InGameCurrency { get; set; }
|
||||
|
||||
// //[Column("purchased_items")]
|
||||
// //public Dictionary<string, object> PurchasedItems { get; set; } = new();
|
||||
|
||||
// //[Column("updated_at")]
|
||||
// //public DateTimeOffset? UpdatedAt { get; set; }
|
||||
//}
|
||||
|
||||
//#endregion
|
||||
|
||||
////public static class SupabasePlayers
|
||||
////{
|
||||
//// // TODO: set these
|
||||
//// public static string SupabaseUrl = "https://YOUR-PROJECT.supabase.co";
|
||||
//// public static string SupabaseAnonKey = "YOUR-ANON-KEY";
|
||||
|
||||
//// private static Client _client;
|
||||
|
||||
//// public static async Task InitAsync()
|
||||
//// {
|
||||
//// if (_client != null) return;
|
||||
|
||||
//// var options = new SupabaseOptions
|
||||
//// {
|
||||
//// AutoConnectRealtime = false,
|
||||
//// Schema = "public"
|
||||
//// };
|
||||
|
||||
//// _client = new Client(SupabaseUrl, SupabaseAnonKey, options);
|
||||
//// await _client.InitializeAsync();
|
||||
//// }
|
||||
|
||||
//// // ---------- CREATE (or get existing via UPSERT on PK) ----------
|
||||
//// public static async Task<PlayerRow> CreateIfMissingAsync(
|
||||
//// string walletAddress,
|
||||
//// int totalKills = 0,
|
||||
//// decimal? averagePlacement = null,
|
||||
//// decimal? winPercentage = null,
|
||||
//// long inGameCurrency = 0,
|
||||
//// Dictionary<string, object> purchasedItems = null)
|
||||
//// {
|
||||
//// await InitAsync();
|
||||
|
||||
//// var row = new PlayerRow
|
||||
//// {
|
||||
//// WalletAddress = walletAddress,
|
||||
//// TotalKills = totalKills,
|
||||
//// AveragePlacement = averagePlacement,
|
||||
//// WinPercentage = winPercentage,
|
||||
//// InGameCurrency = inGameCurrency,
|
||||
//// PurchasedItems = purchasedItems ?? new Dictionary<string, object>(),
|
||||
//// UpdatedAt = DateTimeOffset.UtcNow
|
||||
//// };
|
||||
|
||||
//// var resp = await _client
|
||||
//// .From<PlayerRow>()
|
||||
//// .Upsert(row); // upsert by PK
|
||||
|
||||
//// return resp.Models.Count > 0 ? resp.Models[0] : row;
|
||||
//// }
|
||||
|
||||
//// // ---------- READ ----------
|
||||
//// public static async Task<PlayerRow> GetAsync(string walletAddress)
|
||||
//// {
|
||||
//// await InitAsync();
|
||||
|
||||
//// var resp = await _client
|
||||
//// .From<PlayerRow>()
|
||||
//// .Select("*") // 3.5.x requires a string
|
||||
//// .Filter("wallet_address", Postgrest.Constants.Operator.Equals, walletAddress)
|
||||
//// .Get();
|
||||
|
||||
//// return resp.Models.Count > 0 ? resp.Models[0] : null;
|
||||
//// }
|
||||
|
||||
//// // ---------- PATCH ----------
|
||||
//// public static async Task<PlayerRow> PatchAsync(
|
||||
//// string walletAddress,
|
||||
//// int? totalKills = null,
|
||||
//// decimal? averagePlacement = null,
|
||||
//// decimal? winPercentage = null,
|
||||
//// long? inGameCurrency = null,
|
||||
//// Dictionary<string, object> purchasedItems = null)
|
||||
//// {
|
||||
//// await InitAsync();
|
||||
|
||||
//// var updateResp = await _client
|
||||
//// .From<PlayerRow>()
|
||||
//// .Filter("wallet_address", Postgrest.Constants.Operator.Equals, walletAddress)
|
||||
//// .Set(p =>
|
||||
//// {
|
||||
//// var dict = new Dictionary<object, object>();
|
||||
|
||||
//// if (totalKills.HasValue) dict["total_kills"] = totalKills.Value;
|
||||
//// if (averagePlacement.HasValue) dict["average_placement"] = averagePlacement.Value;
|
||||
//// if (winPercentage.HasValue) dict["win_percentage"] = winPercentage.Value;
|
||||
//// if (inGameCurrency.HasValue) dict["in_game_currency"] = inGameCurrency.Value;
|
||||
//// if (purchasedItems != null) dict["purchased_items"] = purchasedItems;
|
||||
|
||||
//// dict["updated_at"] = DateTimeOffset.UtcNow;
|
||||
//// return dict;
|
||||
//// })
|
||||
//// .Update();
|
||||
|
||||
//// return updateResp.Models.Count > 0
|
||||
//// ? updateResp.Models[0]
|
||||
//// : await GetAsync(walletAddress);
|
||||
//// }
|
||||
|
||||
//// // ---------- REPLACE (full row) ----------
|
||||
//// public static async Task<PlayerRow> ReplaceAsync(PlayerRow fullRow)
|
||||
//// {
|
||||
//// await InitAsync();
|
||||
|
||||
//// if (string.IsNullOrWhiteSpace(fullRow.WalletAddress))
|
||||
//// throw new ArgumentException("WalletAddress (PK) is required.");
|
||||
|
||||
//// fullRow.UpdatedAt = DateTimeOffset.UtcNow;
|
||||
|
||||
//// var resp = await _client
|
||||
//// .From<PlayerRow>()
|
||||
//// .Upsert(fullRow); // upsert by PK
|
||||
|
||||
//// return resp.Models.Count > 0 ? resp.Models[0] : fullRow;
|
||||
//// }
|
||||
|
||||
//// // ---------- DELETE ----------
|
||||
//// public static async Task<bool> DeleteAsync(string walletAddress)
|
||||
//// {
|
||||
//// await InitAsync();
|
||||
|
||||
//// await _client
|
||||
//// .From<PlayerRow>()
|
||||
//// .Filter("wallet_address", Postgrest.Constants.Operator.Equals, walletAddress)
|
||||
//// .Delete();
|
||||
|
||||
//// return true; // PostgREST usually returns empty body on delete
|
||||
//// }
|
||||
////}
|
2
Assets/SupabasePlayers.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 69ffe49890f7675448fbe768edb72f7d
|
@ -33,26 +33,26 @@ MonoBehaviour:
|
||||
m_Settings:
|
||||
m_SettingsList:
|
||||
m_List:
|
||||
- rid: 1051813860904534127
|
||||
- rid: 3263039602809372672
|
||||
- rid: 3067256451524460819
|
||||
- rid: 1051813860904534128
|
||||
- rid: 3263039602809372673
|
||||
- rid: 3067256451524460821
|
||||
- rid: 1051813860904534129
|
||||
- rid: 3263039602809372674
|
||||
- rid: 3067256451524460823
|
||||
- rid: 3067256451524460824
|
||||
- rid: 1051813860904534130
|
||||
- rid: 3263039602809372675
|
||||
- rid: 3067256451524460826
|
||||
- rid: 3067256451524460827
|
||||
- rid: 3067256451524460828
|
||||
- rid: 1051813860904534131
|
||||
- rid: 3263039602809372676
|
||||
- rid: 3067256451524460830
|
||||
- rid: 1051813860904534132
|
||||
- rid: 1051813860904534133
|
||||
- rid: 1051813860904534134
|
||||
- rid: 1051813860904534135
|
||||
- rid: 3263039602809372677
|
||||
- rid: 3263039602809372678
|
||||
- rid: 3263039602809372679
|
||||
- rid: 3263039602809372680
|
||||
- rid: 3067256451524460835
|
||||
- rid: 1051813860904534136
|
||||
- rid: 1051813860904534137
|
||||
- rid: 3263039602809372681
|
||||
- rid: 3263039602809372682
|
||||
- rid: 3067256451524460838
|
||||
m_RuntimeSettings:
|
||||
m_List:
|
||||
@ -96,109 +96,6 @@ MonoBehaviour:
|
||||
references:
|
||||
version: 2
|
||||
RefIds:
|
||||
- rid: 1051813860904534127
|
||||
type: {class: UniversalRenderPipelineEditorShaders, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
m_AutodeskInteractive: {fileID: 4800000, guid: 0e9d5a909a1f7e84882a534d0d11e49f, type: 3}
|
||||
m_AutodeskInteractiveTransparent: {fileID: 4800000, guid: 5c81372d981403744adbdda4433c9c11, type: 3}
|
||||
m_AutodeskInteractiveMasked: {fileID: 4800000, guid: 80aa867ac363ac043847b06ad71604cd, type: 3}
|
||||
m_TerrainDetailLit: {fileID: 4800000, guid: f6783ab646d374f94b199774402a5144, type: 3}
|
||||
m_TerrainDetailGrassBillboard: {fileID: 4800000, guid: 29868e73b638e48ca99a19ea58c48d90, type: 3}
|
||||
m_TerrainDetailGrass: {fileID: 4800000, guid: e507fdfead5ca47e8b9a768b51c291a1, type: 3}
|
||||
m_DefaultSpeedTree7Shader: {fileID: 4800000, guid: 0f4122b9a743b744abe2fb6a0a88868b, type: 3}
|
||||
m_DefaultSpeedTree8Shader: {fileID: -6465566751694194690, guid: 9920c1f1781549a46ba081a2a15a16ec, type: 3}
|
||||
m_DefaultSpeedTree9Shader: {fileID: -6465566751694194690, guid: cbd3e1cc4ae141c42a30e33b4d666a61, type: 3}
|
||||
- rid: 1051813860904534128
|
||||
type: {class: Renderer2DResources, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
m_Version: 0
|
||||
m_LightShader: {fileID: 4800000, guid: 3f6c848ca3d7bca4bbe846546ac701a1, type: 3}
|
||||
m_ProjectedShadowShader: {fileID: 4800000, guid: ce09d4a80b88c5a4eb9768fab4f1ee00, type: 3}
|
||||
m_SpriteShadowShader: {fileID: 4800000, guid: 44fc62292b65ab04eabcf310e799ccf6, type: 3}
|
||||
m_SpriteUnshadowShader: {fileID: 4800000, guid: de02b375720b5c445afe83cd483bedf3, type: 3}
|
||||
m_GeometryShadowShader: {fileID: 4800000, guid: 19349a0f9a7ed4c48a27445bcf92e5e1, type: 3}
|
||||
m_GeometryUnshadowShader: {fileID: 4800000, guid: 77774d9009bb81447b048c907d4c6273, type: 3}
|
||||
m_FallOffLookup: {fileID: 2800000, guid: 5688ab254e4c0634f8d6c8e0792331ca, type: 3}
|
||||
m_CopyDepthPS: {fileID: 4800000, guid: d6dae50ee9e1bfa4db75f19f99355220, type: 3}
|
||||
m_DefaultLitMaterial: {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2}
|
||||
m_DefaultUnlitMaterial: {fileID: 2100000, guid: 9dfc825aed78fcd4ba02077103263b40, type: 2}
|
||||
m_DefaultMaskMaterial: {fileID: 2100000, guid: 15d0c3709176029428a0da2f8cecf0b5, type: 2}
|
||||
- rid: 1051813860904534129
|
||||
type: {class: UniversalRenderPipelineEditorMaterials, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
m_DefaultMaterial: {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2}
|
||||
m_DefaultParticleMaterial: {fileID: 2100000, guid: e823cd5b5d27c0f4b8256e7c12ee3e6d, type: 2}
|
||||
m_DefaultLineMaterial: {fileID: 2100000, guid: e823cd5b5d27c0f4b8256e7c12ee3e6d, type: 2}
|
||||
m_DefaultTerrainMaterial: {fileID: 2100000, guid: 594ea882c5a793440b60ff72d896021e, type: 2}
|
||||
m_DefaultDecalMaterial: {fileID: 2100000, guid: 31d0dcc6f2dd4e4408d18036a2c93862, type: 2}
|
||||
- rid: 1051813860904534130
|
||||
type: {class: URPShaderStrippingSetting, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
m_Version: 0
|
||||
m_StripUnusedPostProcessingVariants: 0
|
||||
m_StripUnusedVariants: 1
|
||||
m_StripScreenCoordOverrideVariants: 1
|
||||
- rid: 1051813860904534131
|
||||
type: {class: GPUResidentDrawerResources, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.GPUDriven.Runtime}
|
||||
data:
|
||||
m_Version: 0
|
||||
m_InstanceDataBufferCopyKernels: {fileID: 7200000, guid: f984aeb540ded8b4fbb8a2047ab5b2e2, type: 3}
|
||||
m_InstanceDataBufferUploadKernels: {fileID: 7200000, guid: 53864816eb00f2343b60e1a2c5a262ef, type: 3}
|
||||
m_TransformUpdaterKernels: {fileID: 7200000, guid: 2a567b9b2733f8d47a700c3c85bed75b, type: 3}
|
||||
m_WindDataUpdaterKernels: {fileID: 7200000, guid: fde76746e4fd0ed418c224f6b4084114, type: 3}
|
||||
m_OccluderDepthPyramidKernels: {fileID: 7200000, guid: 08b2b5fb307b0d249860612774a987da, type: 3}
|
||||
m_InstanceOcclusionCullingKernels: {fileID: 7200000, guid: f6d223acabc2f974795a5a7864b50e6c, type: 3}
|
||||
m_OcclusionCullingDebugKernels: {fileID: 7200000, guid: b23e766bcf50ca4438ef186b174557df, type: 3}
|
||||
m_DebugOcclusionTestPS: {fileID: 4800000, guid: d3f0849180c2d0944bc71060693df100, type: 3}
|
||||
m_DebugOccluderPS: {fileID: 4800000, guid: b3c92426a88625841ab15ca6a7917248, type: 3}
|
||||
- rid: 1051813860904534132
|
||||
type: {class: ProbeVolumeRuntimeResources, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime}
|
||||
data:
|
||||
m_Version: 1
|
||||
probeVolumeBlendStatesCS: {fileID: 7200000, guid: a3f7b8c99de28a94684cb1daebeccf5d, type: 3}
|
||||
probeVolumeUploadDataCS: {fileID: 7200000, guid: 0951de5992461754fa73650732c4954c, type: 3}
|
||||
probeVolumeUploadDataL2CS: {fileID: 7200000, guid: 6196f34ed825db14b81fb3eb0ea8d931, type: 3}
|
||||
- rid: 1051813860904534133
|
||||
type: {class: IncludeAdditionalRPAssets, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime}
|
||||
data:
|
||||
m_version: 0
|
||||
m_IncludeReferencedInScenes: 0
|
||||
m_IncludeAssetsByLabel: 0
|
||||
m_LabelToInclude:
|
||||
- rid: 1051813860904534134
|
||||
type: {class: ProbeVolumeBakingResources, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime}
|
||||
data:
|
||||
m_Version: 1
|
||||
dilationShader: {fileID: 7200000, guid: 6bb382f7de370af41b775f54182e491d, type: 3}
|
||||
subdivideSceneCS: {fileID: 7200000, guid: bb86f1f0af829fd45b2ebddda1245c22, type: 3}
|
||||
voxelizeSceneShader: {fileID: 4800000, guid: c8b6a681c7b4e2e4785ffab093907f9e, type: 3}
|
||||
traceVirtualOffsetCS: {fileID: -6772857160820960102, guid: ff2cbab5da58bf04d82c5f34037ed123, type: 3}
|
||||
traceVirtualOffsetRT: {fileID: -5126288278712620388, guid: ff2cbab5da58bf04d82c5f34037ed123, type: 3}
|
||||
skyOcclusionCS: {fileID: -6772857160820960102, guid: 5a2a534753fbdb44e96c3c78b5a6999d, type: 3}
|
||||
skyOcclusionRT: {fileID: -5126288278712620388, guid: 5a2a534753fbdb44e96c3c78b5a6999d, type: 3}
|
||||
renderingLayerCS: {fileID: -6772857160820960102, guid: 94a070d33e408384bafc1dea4a565df9, type: 3}
|
||||
renderingLayerRT: {fileID: -5126288278712620388, guid: 94a070d33e408384bafc1dea4a565df9, type: 3}
|
||||
- rid: 1051813860904534135
|
||||
type: {class: STP/RuntimeResources, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime}
|
||||
data:
|
||||
m_setupCS: {fileID: 7200000, guid: 33be2e9a5506b2843bdb2bdff9cad5e1, type: 3}
|
||||
m_preTaaCS: {fileID: 7200000, guid: a679dba8ec4d9ce45884a270b0e22dda, type: 3}
|
||||
m_taaCS: {fileID: 7200000, guid: 3923900e2b41b5e47bc25bfdcbcdc9e6, type: 3}
|
||||
- rid: 1051813860904534136
|
||||
type: {class: ProbeVolumeDebugResources, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime}
|
||||
data:
|
||||
m_Version: 1
|
||||
probeVolumeDebugShader: {fileID: 4800000, guid: 3b21275fd12d65f49babb5286f040f2d, type: 3}
|
||||
probeVolumeFragmentationDebugShader: {fileID: 4800000, guid: 3a80877c579b9144ebdcc6d923bca303, type: 3}
|
||||
probeVolumeSamplingDebugShader: {fileID: 4800000, guid: bf54e6528c79a224e96346799064c393, type: 3}
|
||||
probeVolumeOffsetDebugShader: {fileID: 4800000, guid: db8bd7436dc2c5f4c92655307d198381, type: 3}
|
||||
probeSamplingDebugMesh: {fileID: -3555484719484374845, guid: 20be25aac4e22ee49a7db76fb3df6de2, type: 3}
|
||||
numbersDisplayTex: {fileID: 2800000, guid: 73fe53b428c5b3440b7e87ee830b608a, type: 3}
|
||||
- rid: 1051813860904534137
|
||||
type: {class: ProbeVolumeGlobalSettings, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime}
|
||||
data:
|
||||
m_Version: 1
|
||||
m_ProbeVolumeDisableStreamingAssets: 0
|
||||
- rid: 3067256451524460819
|
||||
type: {class: UniversalRenderPipelineRuntimeShaders, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
@ -263,3 +160,106 @@ MonoBehaviour:
|
||||
m_ExportShaderVariants: 1
|
||||
m_ShaderVariantLogLevel: 0
|
||||
m_StripRuntimeDebugShaders: 1
|
||||
- rid: 3263039602809372672
|
||||
type: {class: UniversalRenderPipelineEditorShaders, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
m_AutodeskInteractive: {fileID: 4800000, guid: 0e9d5a909a1f7e84882a534d0d11e49f, type: 3}
|
||||
m_AutodeskInteractiveTransparent: {fileID: 4800000, guid: 5c81372d981403744adbdda4433c9c11, type: 3}
|
||||
m_AutodeskInteractiveMasked: {fileID: 4800000, guid: 80aa867ac363ac043847b06ad71604cd, type: 3}
|
||||
m_TerrainDetailLit: {fileID: 4800000, guid: f6783ab646d374f94b199774402a5144, type: 3}
|
||||
m_TerrainDetailGrassBillboard: {fileID: 4800000, guid: 29868e73b638e48ca99a19ea58c48d90, type: 3}
|
||||
m_TerrainDetailGrass: {fileID: 4800000, guid: e507fdfead5ca47e8b9a768b51c291a1, type: 3}
|
||||
m_DefaultSpeedTree7Shader: {fileID: 4800000, guid: 0f4122b9a743b744abe2fb6a0a88868b, type: 3}
|
||||
m_DefaultSpeedTree8Shader: {fileID: -6465566751694194690, guid: 9920c1f1781549a46ba081a2a15a16ec, type: 3}
|
||||
m_DefaultSpeedTree9Shader: {fileID: -6465566751694194690, guid: cbd3e1cc4ae141c42a30e33b4d666a61, type: 3}
|
||||
- rid: 3263039602809372673
|
||||
type: {class: Renderer2DResources, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
m_Version: 0
|
||||
m_LightShader: {fileID: 4800000, guid: 3f6c848ca3d7bca4bbe846546ac701a1, type: 3}
|
||||
m_ProjectedShadowShader: {fileID: 4800000, guid: ce09d4a80b88c5a4eb9768fab4f1ee00, type: 3}
|
||||
m_SpriteShadowShader: {fileID: 4800000, guid: 44fc62292b65ab04eabcf310e799ccf6, type: 3}
|
||||
m_SpriteUnshadowShader: {fileID: 4800000, guid: de02b375720b5c445afe83cd483bedf3, type: 3}
|
||||
m_GeometryShadowShader: {fileID: 4800000, guid: 19349a0f9a7ed4c48a27445bcf92e5e1, type: 3}
|
||||
m_GeometryUnshadowShader: {fileID: 4800000, guid: 77774d9009bb81447b048c907d4c6273, type: 3}
|
||||
m_FallOffLookup: {fileID: 2800000, guid: 5688ab254e4c0634f8d6c8e0792331ca, type: 3}
|
||||
m_CopyDepthPS: {fileID: 4800000, guid: d6dae50ee9e1bfa4db75f19f99355220, type: 3}
|
||||
m_DefaultLitMaterial: {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2}
|
||||
m_DefaultUnlitMaterial: {fileID: 2100000, guid: 9dfc825aed78fcd4ba02077103263b40, type: 2}
|
||||
m_DefaultMaskMaterial: {fileID: 2100000, guid: 15d0c3709176029428a0da2f8cecf0b5, type: 2}
|
||||
- rid: 3263039602809372674
|
||||
type: {class: UniversalRenderPipelineEditorMaterials, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
m_DefaultMaterial: {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2}
|
||||
m_DefaultParticleMaterial: {fileID: 2100000, guid: e823cd5b5d27c0f4b8256e7c12ee3e6d, type: 2}
|
||||
m_DefaultLineMaterial: {fileID: 2100000, guid: e823cd5b5d27c0f4b8256e7c12ee3e6d, type: 2}
|
||||
m_DefaultTerrainMaterial: {fileID: 2100000, guid: 594ea882c5a793440b60ff72d896021e, type: 2}
|
||||
m_DefaultDecalMaterial: {fileID: 2100000, guid: 31d0dcc6f2dd4e4408d18036a2c93862, type: 2}
|
||||
- rid: 3263039602809372675
|
||||
type: {class: URPShaderStrippingSetting, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
m_Version: 0
|
||||
m_StripUnusedPostProcessingVariants: 0
|
||||
m_StripUnusedVariants: 1
|
||||
m_StripScreenCoordOverrideVariants: 1
|
||||
- rid: 3263039602809372676
|
||||
type: {class: GPUResidentDrawerResources, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.GPUDriven.Runtime}
|
||||
data:
|
||||
m_Version: 0
|
||||
m_InstanceDataBufferCopyKernels: {fileID: 7200000, guid: f984aeb540ded8b4fbb8a2047ab5b2e2, type: 3}
|
||||
m_InstanceDataBufferUploadKernels: {fileID: 7200000, guid: 53864816eb00f2343b60e1a2c5a262ef, type: 3}
|
||||
m_TransformUpdaterKernels: {fileID: 7200000, guid: 2a567b9b2733f8d47a700c3c85bed75b, type: 3}
|
||||
m_WindDataUpdaterKernels: {fileID: 7200000, guid: fde76746e4fd0ed418c224f6b4084114, type: 3}
|
||||
m_OccluderDepthPyramidKernels: {fileID: 7200000, guid: 08b2b5fb307b0d249860612774a987da, type: 3}
|
||||
m_InstanceOcclusionCullingKernels: {fileID: 7200000, guid: f6d223acabc2f974795a5a7864b50e6c, type: 3}
|
||||
m_OcclusionCullingDebugKernels: {fileID: 7200000, guid: b23e766bcf50ca4438ef186b174557df, type: 3}
|
||||
m_DebugOcclusionTestPS: {fileID: 4800000, guid: d3f0849180c2d0944bc71060693df100, type: 3}
|
||||
m_DebugOccluderPS: {fileID: 4800000, guid: b3c92426a88625841ab15ca6a7917248, type: 3}
|
||||
- rid: 3263039602809372677
|
||||
type: {class: ProbeVolumeRuntimeResources, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime}
|
||||
data:
|
||||
m_Version: 1
|
||||
probeVolumeBlendStatesCS: {fileID: 7200000, guid: a3f7b8c99de28a94684cb1daebeccf5d, type: 3}
|
||||
probeVolumeUploadDataCS: {fileID: 7200000, guid: 0951de5992461754fa73650732c4954c, type: 3}
|
||||
probeVolumeUploadDataL2CS: {fileID: 7200000, guid: 6196f34ed825db14b81fb3eb0ea8d931, type: 3}
|
||||
- rid: 3263039602809372678
|
||||
type: {class: IncludeAdditionalRPAssets, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime}
|
||||
data:
|
||||
m_version: 0
|
||||
m_IncludeReferencedInScenes: 0
|
||||
m_IncludeAssetsByLabel: 0
|
||||
m_LabelToInclude:
|
||||
- rid: 3263039602809372679
|
||||
type: {class: ProbeVolumeBakingResources, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime}
|
||||
data:
|
||||
m_Version: 1
|
||||
dilationShader: {fileID: 7200000, guid: 6bb382f7de370af41b775f54182e491d, type: 3}
|
||||
subdivideSceneCS: {fileID: 7200000, guid: bb86f1f0af829fd45b2ebddda1245c22, type: 3}
|
||||
voxelizeSceneShader: {fileID: 4800000, guid: c8b6a681c7b4e2e4785ffab093907f9e, type: 3}
|
||||
traceVirtualOffsetCS: {fileID: -6772857160820960102, guid: ff2cbab5da58bf04d82c5f34037ed123, type: 3}
|
||||
traceVirtualOffsetRT: {fileID: -5126288278712620388, guid: ff2cbab5da58bf04d82c5f34037ed123, type: 3}
|
||||
skyOcclusionCS: {fileID: -6772857160820960102, guid: 5a2a534753fbdb44e96c3c78b5a6999d, type: 3}
|
||||
skyOcclusionRT: {fileID: -5126288278712620388, guid: 5a2a534753fbdb44e96c3c78b5a6999d, type: 3}
|
||||
renderingLayerCS: {fileID: -6772857160820960102, guid: 94a070d33e408384bafc1dea4a565df9, type: 3}
|
||||
renderingLayerRT: {fileID: -5126288278712620388, guid: 94a070d33e408384bafc1dea4a565df9, type: 3}
|
||||
- rid: 3263039602809372680
|
||||
type: {class: STP/RuntimeResources, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime}
|
||||
data:
|
||||
m_setupCS: {fileID: 7200000, guid: 33be2e9a5506b2843bdb2bdff9cad5e1, type: 3}
|
||||
m_preTaaCS: {fileID: 7200000, guid: a679dba8ec4d9ce45884a270b0e22dda, type: 3}
|
||||
m_taaCS: {fileID: 7200000, guid: 3923900e2b41b5e47bc25bfdcbcdc9e6, type: 3}
|
||||
- rid: 3263039602809372681
|
||||
type: {class: ProbeVolumeDebugResources, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime}
|
||||
data:
|
||||
m_Version: 1
|
||||
probeVolumeDebugShader: {fileID: 4800000, guid: 3b21275fd12d65f49babb5286f040f2d, type: 3}
|
||||
probeVolumeFragmentationDebugShader: {fileID: 4800000, guid: 3a80877c579b9144ebdcc6d923bca303, type: 3}
|
||||
probeVolumeSamplingDebugShader: {fileID: 4800000, guid: bf54e6528c79a224e96346799064c393, type: 3}
|
||||
probeVolumeOffsetDebugShader: {fileID: 4800000, guid: db8bd7436dc2c5f4c92655307d198381, type: 3}
|
||||
probeSamplingDebugMesh: {fileID: -3555484719484374845, guid: 20be25aac4e22ee49a7db76fb3df6de2, type: 3}
|
||||
numbersDisplayTex: {fileID: 2800000, guid: 73fe53b428c5b3440b7e87ee830b608a, type: 3}
|
||||
- rid: 3263039602809372682
|
||||
type: {class: ProbeVolumeGlobalSettings, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime}
|
||||
data:
|
||||
m_Version: 1
|
||||
m_ProbeVolumeDisableStreamingAssets: 0
|
||||
|
2371
Assets/TPSBR/Scenes/Wallet.unity
Normal file
7
Assets/TPSBR/Scenes/Wallet.unity.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5622920d4cb64fb45abadeb06d20725d
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,3 +1,5 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
@ -17,9 +19,9 @@ namespace TPSBR.UI
|
||||
[SerializeField]
|
||||
private AudioSetup _openSound;
|
||||
|
||||
// UIView INTERFACE
|
||||
|
||||
protected override void OnInitialize()
|
||||
// UIView INTERFACE
|
||||
private bool _hasReportedStats;
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
base.OnInitialize();
|
||||
|
||||
@ -48,21 +50,59 @@ namespace TPSBR.UI
|
||||
_winnerGroup.SetActive(false);
|
||||
}
|
||||
|
||||
PlaySound(_openSound);
|
||||
PlaySound(_openSound);
|
||||
if (_hasReportedStats == false)
|
||||
{
|
||||
_ = ReportGameCompletedAsync();
|
||||
}
|
||||
Global.Networking.StopGameOnDisconnect();
|
||||
}
|
||||
private async Task ReportGameCompletedAsync()
|
||||
{
|
||||
_hasReportedStats = true;
|
||||
|
||||
Global.Networking.StopGameOnDisconnect();
|
||||
}
|
||||
try
|
||||
{
|
||||
if (!PlayerPrefs.HasKey("WALLET_ADDRESS"))
|
||||
return;
|
||||
|
||||
protected override void OnDeinitialize()
|
||||
{
|
||||
_restartButton.onClick.RemoveListener(OnRestartButton);
|
||||
var wallet = PlayerPrefs.GetString("WALLET_ADDRESS");
|
||||
if (string.IsNullOrWhiteSpace(wallet))
|
||||
return;
|
||||
|
||||
base.OnDeinitialize();
|
||||
}
|
||||
var localPlayer = Context.NetworkGame.GetPlayer(Context.LocalPlayerRef);
|
||||
if (localPlayer == null)
|
||||
return;
|
||||
|
||||
// PRIVATE MEMBERS
|
||||
await GameDb.IncGamesPlayedAsync(wallet);
|
||||
|
||||
private PlayerStatistics GetWinner()
|
||||
int placement = localPlayer.Statistics.Position;
|
||||
if (placement > 0)
|
||||
{
|
||||
await GameDb.SendGameWinAsync(wallet, placement);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("[Supabase] Skipped reporting placement because it was not set.");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"[Supabase] Failed to report game completion: {ex.Message}");
|
||||
}
|
||||
}
|
||||
protected override void OnDeinitialize()
|
||||
{
|
||||
_restartButton.onClick.RemoveListener(OnRestartButton);
|
||||
|
||||
_hasReportedStats = false;
|
||||
|
||||
base.OnDeinitialize();
|
||||
}
|
||||
|
||||
// PRIVATE MEMBERS
|
||||
|
||||
private PlayerStatistics GetWinner()
|
||||
{
|
||||
foreach (var player in Context.NetworkGame.ActivePlayers)
|
||||
{
|
||||
|
@ -1,7 +1,8 @@
|
||||
using UnityEngine;
|
||||
using Fusion;
|
||||
using TMPro;
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
namespace TPSBR.UI
|
||||
{
|
||||
public class UIGameplayView : UIView
|
||||
@ -195,19 +196,55 @@ namespace TPSBR.UI
|
||||
Sound = _playerDeathSound,
|
||||
});
|
||||
}
|
||||
else if (killData.KillerRef == Context.ObservedPlayerRef)
|
||||
{
|
||||
bool eliminated = killerPlayer != null ? killerPlayer.Statistics.IsEliminated : false;
|
||||
//else if (killData.KillerRef == Context.ObservedPlayerRef)
|
||||
//{
|
||||
// bool eliminated = killerPlayer != null ? killerPlayer.Statistics.IsEliminated : false;
|
||||
|
||||
_events.ShowEvent(new GameplayEventData
|
||||
{
|
||||
Name = eliminated == true ? "ENEMY ELIMINATED" : "ENEMY KILLED",
|
||||
Description = victimPlayer != null ? victimPlayer.Nickname : "",
|
||||
Color = _enemyKilledColor,
|
||||
Sound = _enemyKilledSound,
|
||||
});
|
||||
}
|
||||
}
|
||||
// _events.ShowEvent(new GameplayEventData
|
||||
// {
|
||||
// Name = eliminated == true ? "ENEMY ELIMINATED" : "ENEMY KILLED",
|
||||
// Description = victimPlayer != null ? victimPlayer.Nickname : "",
|
||||
// Color = _enemyKilledColor,
|
||||
// Sound = _enemyKilledSound,
|
||||
// });
|
||||
//}
|
||||
else if (killData.KillerRef == Context.ObservedPlayerRef)
|
||||
{
|
||||
bool eliminated = killerPlayer != null ? killerPlayer.Statistics.IsEliminated : false;
|
||||
|
||||
_events.ShowEvent(new GameplayEventData
|
||||
{
|
||||
Name = eliminated == true ? "ENEMY ELIMINATED" : "ENEMY KILLED",
|
||||
Description = victimPlayer != null ? victimPlayer.Nickname : "",
|
||||
Color = _enemyKilledColor,
|
||||
Sound = _enemyKilledSound,
|
||||
});
|
||||
}
|
||||
|
||||
if (killData.KillerRef == Context.LocalPlayerRef)
|
||||
{
|
||||
_ = ReportKillAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ReportKillAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (PlayerPrefs.HasKey("WALLET_ADDRESS") == false)
|
||||
return;
|
||||
|
||||
var wallet = PlayerPrefs.GetString("WALLET_ADDRESS");
|
||||
if (string.IsNullOrWhiteSpace(wallet) == true)
|
||||
return;
|
||||
|
||||
await GameDb.AddKillAsync(wallet);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"[Supabase] Failed to report kill: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPlayerEliminated(PlayerRef playerRef)
|
||||
{
|
||||
|
@ -1,3 +1,5 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace TPSBR.UI
|
||||
{
|
||||
public class MenuUI : SceneUI
|
||||
@ -10,12 +12,13 @@ namespace TPSBR.UI
|
||||
|
||||
Context.Input.RequestCursorVisibility(true, ECursorStateSource.Menu);
|
||||
|
||||
if (Context.PlayerData.Nickname.HasValue() == false)
|
||||
{
|
||||
var changeNicknameView = Open<UIChangeNicknameView>();
|
||||
changeNicknameView.SetData("ENTER NICKNAME", true);
|
||||
}
|
||||
}
|
||||
OnWalletConnected(PlayerPrefs.GetString("WALLET_ADDRESS"));
|
||||
//if (Context.PlayerData.Nickname.HasValue() == false)
|
||||
//{
|
||||
// var changeNicknameView = Open<UIChangeNicknameView>();
|
||||
// changeNicknameView.SetData("ENTER NICKNAME", true);
|
||||
//}
|
||||
}
|
||||
|
||||
protected override void OnDeinitializeInternal()
|
||||
{
|
||||
@ -47,5 +50,32 @@ namespace TPSBR.UI
|
||||
Global.Networking.ClearErrorStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
public async void OnWalletConnected(string wallet) // call this from your wallet SDK
|
||||
{
|
||||
try
|
||||
{
|
||||
// makes sure the row exists (display_name = "" on first create)
|
||||
string playername= await GameDb.GetPlayerNameAsync(wallet);
|
||||
if (playername == "")
|
||||
{
|
||||
|
||||
var changeNicknameView = Open<UIChangeNicknameView>();
|
||||
changeNicknameView.SetData("ENTER NICKNAME", true);
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.PlayerData.Nickname = playername.ToString();
|
||||
Debug.Log($"Player ensured for {wallet}");
|
||||
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
using UnityEngine.Windows;
|
||||
|
||||
namespace TPSBR.UI
|
||||
{
|
||||
@ -43,14 +44,15 @@ namespace TPSBR.UI
|
||||
protected override void OnOpen()
|
||||
{
|
||||
base.OnOpen();
|
||||
|
||||
string currentNickname = Context.PlayerData.Nickname;
|
||||
GetName();
|
||||
string currentNickname = Context.PlayerData.Nickname;
|
||||
if (currentNickname.HasValue() == false)
|
||||
{
|
||||
_name.text = "Player" + Random.Range(10000, 100000);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
_name.text = Context.PlayerData.Nickname;
|
||||
}
|
||||
}
|
||||
@ -67,8 +69,23 @@ namespace TPSBR.UI
|
||||
private void OnConfirmButton()
|
||||
{
|
||||
Context.PlayerData.Nickname = _name.text;
|
||||
|
||||
Close();
|
||||
SetName(PlayerPrefs.GetString("WALLET_ADDRESS"),Context.PlayerData.Nickname.ToString());
|
||||
Close();
|
||||
}
|
||||
}
|
||||
public async void SetName(string walletaddress,string playername)
|
||||
{
|
||||
Debug.Log("Setting name for wallet address" + walletaddress.ToString());
|
||||
var rec = await GameDb.SetNameIfEmptyAsync(walletaddress, playername);
|
||||
|
||||
|
||||
}
|
||||
public async void GetName()
|
||||
{
|
||||
var playername= await GameDb.GetPlayerNameAsync(PlayerPrefs.GetString("WALLET_ADDRESS"));
|
||||
Context.PlayerData.Nickname = playername;
|
||||
_name.text = playername;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
BIN
Assets/UI/6547356-middle-removebg-preview.png
Normal file
After Width: | Height: | Size: 103 KiB |
156
Assets/UI/6547356-middle-removebg-preview.png.meta
Normal file
@ -0,0 +1,156 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1f9eec5f79cc6034f81f7a1eea6afb3d
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 2
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 4
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: iOS
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Android
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: WindowsStoreApps
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
customData:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
BIN
Assets/UI/6547356-middle.png
Normal file
After Width: | Height: | Size: 67 KiB |
156
Assets/UI/6547356-middle.png.meta
Normal file
@ -0,0 +1,156 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b7331575412f0084bb3b5f12872eb763
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 2
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 4
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: iOS
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Android
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: WindowsStoreApps
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
customData:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
42
Assets/WalletConnectController.cs
Normal file
@ -0,0 +1,42 @@
|
||||
using Reown.AppKit.Unity;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
public class WalletConnectController : MonoBehaviour
|
||||
{
|
||||
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
||||
public async void Start()
|
||||
{
|
||||
var config = new AppKitConfig();
|
||||
await AppKit.InitializeAsync(config);
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
public async Task ResumeSession()
|
||||
{
|
||||
// Try to resume account connection from the last session
|
||||
var resumed = await AppKit.ConnectorController.TryResumeSessionAsync();
|
||||
|
||||
if (resumed)
|
||||
{
|
||||
// Continue to the game
|
||||
ShowWalletConnected();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Connect account
|
||||
AppKit.AccountConnected += (_, e) => ShowWalletConnected();
|
||||
AppKit.OpenModal();
|
||||
}
|
||||
}
|
||||
public void ShowWalletConnected()
|
||||
{
|
||||
Debug.Log("Connected");
|
||||
}
|
||||
}
|
||||
|
2
Assets/WalletConnectController.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7caa00906f77d4e44a62da79d4795981
|
BIN
Packages/Newtonsoft.Json.13.0.3/.signature.p7s
vendored
Normal file
20
Packages/Newtonsoft.Json.13.0.3/LICENSE.md
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2007 James Newton-King
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
BIN
Packages/Newtonsoft.Json.13.0.3/Newtonsoft.Json.13.0.3.nupkg
vendored
Normal file
71
Packages/Newtonsoft.Json.13.0.3/README.md
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
#  Json.NET
|
||||
|
||||
[](https://www.nuget.org/packages/Newtonsoft.Json/)
|
||||
[](https://dev.azure.com/jamesnk/Public/_build/latest?definitionId=8)
|
||||
|
||||
Json.NET is a popular high-performance JSON framework for .NET
|
||||
|
||||
## Serialize JSON
|
||||
|
||||
```csharp
|
||||
Product product = new Product();
|
||||
product.Name = "Apple";
|
||||
product.Expiry = new DateTime(2008, 12, 28);
|
||||
product.Sizes = new string[] { "Small" };
|
||||
|
||||
string json = JsonConvert.SerializeObject(product);
|
||||
// {
|
||||
// "Name": "Apple",
|
||||
// "Expiry": "2008-12-28T00:00:00",
|
||||
// "Sizes": [
|
||||
// "Small"
|
||||
// ]
|
||||
// }
|
||||
```
|
||||
|
||||
## Deserialize JSON
|
||||
|
||||
```csharp
|
||||
string json = @"{
|
||||
'Name': 'Bad Boys',
|
||||
'ReleaseDate': '1995-4-7T00:00:00',
|
||||
'Genres': [
|
||||
'Action',
|
||||
'Comedy'
|
||||
]
|
||||
}";
|
||||
|
||||
Movie m = JsonConvert.DeserializeObject<Movie>(json);
|
||||
|
||||
string name = m.Name;
|
||||
// Bad Boys
|
||||
```
|
||||
|
||||
## LINQ to JSON
|
||||
|
||||
```csharp
|
||||
JArray array = new JArray();
|
||||
array.Add("Manual text");
|
||||
array.Add(new DateTime(2000, 5, 23));
|
||||
|
||||
JObject o = new JObject();
|
||||
o["MyArray"] = array;
|
||||
|
||||
string json = o.ToString();
|
||||
// {
|
||||
// "MyArray": [
|
||||
// "Manual text",
|
||||
// "2000-05-23T00:00:00"
|
||||
// ]
|
||||
// }
|
||||
```
|
||||
|
||||
## Links
|
||||
|
||||
- [Homepage](https://www.newtonsoft.com/json)
|
||||
- [Documentation](https://www.newtonsoft.com/json/help)
|
||||
- [NuGet Package](https://www.nuget.org/packages/Newtonsoft.Json)
|
||||
- [Release Notes](https://github.com/JamesNK/Newtonsoft.Json/releases)
|
||||
- [Contributing Guidelines](https://github.com/JamesNK/Newtonsoft.Json/blob/master/CONTRIBUTING.md)
|
||||
- [License](https://github.com/JamesNK/Newtonsoft.Json/blob/master/LICENSE.md)
|
||||
- [Stack Overflow](https://stackoverflow.com/questions/tagged/json.net)
|
BIN
Packages/Newtonsoft.Json.13.0.3/lib/net20/Newtonsoft.Json.dll
vendored
Normal file
10393
Packages/Newtonsoft.Json.13.0.3/lib/net20/Newtonsoft.Json.xml
vendored
Normal file
BIN
Packages/Newtonsoft.Json.13.0.3/lib/net35/Newtonsoft.Json.dll
vendored
Normal file
9541
Packages/Newtonsoft.Json.13.0.3/lib/net35/Newtonsoft.Json.xml
vendored
Normal file
BIN
Packages/Newtonsoft.Json.13.0.3/lib/net40/Newtonsoft.Json.dll
vendored
Normal file
9741
Packages/Newtonsoft.Json.13.0.3/lib/net40/Newtonsoft.Json.xml
vendored
Normal file
BIN
Packages/Newtonsoft.Json.13.0.3/lib/net45/Newtonsoft.Json.dll
vendored
Normal file
11363
Packages/Newtonsoft.Json.13.0.3/lib/net45/Newtonsoft.Json.xml
vendored
Normal file
BIN
Packages/Newtonsoft.Json.13.0.3/lib/net6.0/Newtonsoft.Json.dll
vendored
Normal file
11325
Packages/Newtonsoft.Json.13.0.3/lib/net6.0/Newtonsoft.Json.xml
vendored
Normal file
BIN
Packages/Newtonsoft.Json.13.0.3/lib/netstandard1.0/Newtonsoft.Json.dll
vendored
Normal file
11051
Packages/Newtonsoft.Json.13.0.3/lib/netstandard1.0/Newtonsoft.Json.xml
vendored
Normal file
BIN
Packages/Newtonsoft.Json.13.0.3/lib/netstandard1.3/Newtonsoft.Json.dll
vendored
Normal file
11173
Packages/Newtonsoft.Json.13.0.3/lib/netstandard1.3/Newtonsoft.Json.xml
vendored
Normal file
BIN
Packages/Newtonsoft.Json.13.0.3/lib/netstandard2.0/Newtonsoft.Json.dll
vendored
Normal file
11338
Packages/Newtonsoft.Json.13.0.3/lib/netstandard2.0/Newtonsoft.Json.xml
vendored
Normal file
BIN
Packages/Newtonsoft.Json.13.0.3/packageIcon.png
vendored
Normal file
After Width: | Height: | Size: 8.7 KiB |
BIN
Packages/Supabase.Core.1.0.0/.signature.p7s
vendored
Normal file
26
Packages/Supabase.Core.1.0.0/README.md
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
<p align="center">
|
||||
<img width="300" src=".github/supabase-core.png"/>
|
||||
</p>
|
||||
<p align="center">
|
||||
<img src="https://github.com/supabase-community/core-csharp/workflows/Build%20And%20Test/badge.svg"/>
|
||||
<a href="https://www.nuget.org/packages/supabase-core/">
|
||||
<img src="https://img.shields.io/nuget/vpre/supabase-core"/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
This repo contains shared resources for the [supabase-csharp](https://github.com/supabase-community/supabase-csharp)
|
||||
repo and its dependent libraries.
|
||||
|
||||
## Package made possible through the efforts of:
|
||||
|
||||
Join the ranks! See a problem? Help fix it!
|
||||
|
||||
<a href="https://github.com/supabase-community/core-csharp/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=supabase-community/core-csharp" />
|
||||
</a>
|
||||
|
||||
Made with [contrib.rocks](https://contrib.rocks/preview?repo=supabase-community%core-csharp).
|
||||
|
||||
## Contributing
|
||||
|
||||
We are more than happy to have contributions! Please submit a PR.
|
BIN
Packages/Supabase.Core.1.0.0/Supabase.Core.1.0.0.nupkg
vendored
Normal file
BIN
Packages/Supabase.Core.1.0.0/icon.png
vendored
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
Packages/Supabase.Core.1.0.0/lib/netstandard2.0/Supabase.Core.dll
vendored
Normal file
114
Packages/Supabase.Core.1.0.0/lib/netstandard2.0/Supabase.Core.xml
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
<?xml version="1.0"?>
|
||||
<doc>
|
||||
<assembly>
|
||||
<name>Supabase.Core</name>
|
||||
</assembly>
|
||||
<members>
|
||||
<member name="T:Supabase.Core.Attributes.MapToAttribute">
|
||||
<summary>
|
||||
Used internally to add a string value to a C# field.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Supabase.Core.Attributes.MapToAttribute.Mapping">
|
||||
<summary>
|
||||
The externally specified target value.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Supabase.Core.Attributes.MapToAttribute.Formatter">
|
||||
<summary>
|
||||
A formatter to be passed into the <see cref="M:System.String.ToString" /> method.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:Supabase.Core.Attributes.MapToAttribute.#ctor(System.String,System.String)">
|
||||
<summary>
|
||||
Creates a Mapping to be used internally.
|
||||
|
||||
For example, specifying an Enum that has a different string value elsewhere.
|
||||
</summary>
|
||||
<param name="mapping"></param>
|
||||
<param name="formatter"></param>
|
||||
</member>
|
||||
<member name="T:Supabase.Core.Extensions.DictionaryExtensions">
|
||||
<summary>
|
||||
Extensions for the `Dictionary` Classes
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:Supabase.Core.Extensions.DictionaryExtensions.MergeLeft``3(``0,System.Collections.Generic.IDictionary{``1,``2}[])">
|
||||
<summary>
|
||||
Merges two dictionaries, allowing overwrite priorities leftward.
|
||||
|
||||
Works in C#3/VS2008:
|
||||
Returns a new dictionary of this ... others merged leftward.
|
||||
Keeps the type of 'this', which must be default-instantiable.
|
||||
Example:
|
||||
result = map.MergeLeft(other1, other2, ...)
|
||||
From: https://stackoverflow.com/a/2679857/3629438
|
||||
</summary>
|
||||
<param name="me"></param>
|
||||
<param name="others"></param>
|
||||
<typeparam name="T"></typeparam>
|
||||
<typeparam name="K"></typeparam>
|
||||
<typeparam name="V"></typeparam>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:Supabase.Core.Helpers">
|
||||
<summary>
|
||||
Shortcut Methods, mostly focused on getting attributes from class properties and enums.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:Supabase.Core.Helpers.GetPropertyValue``1(System.Object,System.String)">
|
||||
<summary>
|
||||
Returns the current value from a given class property
|
||||
</summary>
|
||||
<param name="obj"></param>
|
||||
<param name="propName"></param>
|
||||
<typeparam name="T"></typeparam>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:Supabase.Core.Helpers.GetCustomAttribute``1(System.Object)">
|
||||
<summary>
|
||||
Returns a cast Custom Attribute from a given object.
|
||||
</summary>
|
||||
<param name="obj"></param>
|
||||
<typeparam name="T"></typeparam>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:Supabase.Core.Helpers.GetCustomAttribute``1(System.Type)">
|
||||
<summary>
|
||||
Returns a cast Custom Attribute from a given type.
|
||||
</summary>
|
||||
<param name="type"></param>
|
||||
<typeparam name="T"></typeparam>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:Supabase.Core.Helpers.GetMappedToAttr(System.Enum)">
|
||||
<summary>
|
||||
Shortcut method for accessing a `MapTo` attribute, combined with an Enum.
|
||||
</summary>
|
||||
<param name="obj"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:Supabase.Core.Interfaces.IGettableHeaders">
|
||||
<summary>
|
||||
Used for classes that need to retrieve `Headers` externally.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Supabase.Core.Interfaces.IGettableHeaders.GetHeaders">
|
||||
<summary>
|
||||
An executable `Func` that returns a dictionary of headers to be appended onto a request.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:Supabase.Core.Util">
|
||||
<summary>
|
||||
A shared utilities class
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:Supabase.Core.Util.GetAssemblyVersion(System.Type)">
|
||||
<summary>
|
||||
Returns the Current Assembly version - this is usually appended into the headers of each request.
|
||||
</summary>
|
||||
<param name="clientType"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
</members>
|
||||
</doc>
|
BIN
Packages/Supabase.Postgrest.4.1.0/.signature.p7s
vendored
Normal file
362
Packages/Supabase.Postgrest.4.1.0/README.md
vendored
Normal file
@ -0,0 +1,362 @@
|
||||
<p align="center">
|
||||
<img width="300" src=".github/logo.png"/>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://github.com/supabase/postgrest-csharp/workflows/Build%20And%20Test/badge.svg"/>
|
||||
<a href="https://www.nuget.org/packages/Supabase.Postgrest/">
|
||||
<img src="https://img.shields.io/nuget/vpre/Supabase.Postgrest"/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
## [Notice]: v4.0.0 renames this package from `postgrest-csharp` to `Supabase.Postgrest`. Which includes changing the namespace from `Postgrest` to `Supabase.Postgrest`.
|
||||
|
||||
## Now supporting (many) LINQ expressions!
|
||||
|
||||
```c#
|
||||
await client.Table<Movie>()
|
||||
.Select(x => new object[] { x.Id, x.Name, x.Tags, x.ReleaseDate })
|
||||
.Where(x => x.Tags.Contains("Action") || x.Tags.Contains("Adventure"))
|
||||
.Order(x => x.ReleaseDate, Ordering.Descending)
|
||||
.Get();
|
||||
|
||||
await client.Table<Movie>()
|
||||
.Set(x => x.WatchedAt, DateTime.Now)
|
||||
.Where(x => x.Id == "11111-22222-33333-44444")
|
||||
// Or .Filter(x => x.Id, Operator.Equals, "11111-22222-33333-44444")
|
||||
.Update();
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Documentation can be found [here](https://supabase-community.github.io/postgrest-csharp/api/Postgrest.html).
|
||||
|
||||
Postgrest-csharp is written primarily as a helper library
|
||||
for [supabase/supabase-csharp](https://github.com/supabase/supabase-csharp), however, it should be easy enough to use
|
||||
outside of the supabase ecosystem.
|
||||
|
||||
The bulk of this library is a translation and c-sharp-ification of
|
||||
the [supabase/postgrest-js](https://github.com/supabase/postgrest-js) library.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Postgrest-csharp is _heavily_ dependent on Models deriving from `BaseModel`. To interact with the API, one must have the
|
||||
associated
|
||||
model specified.
|
||||
|
||||
To use this library on the Supabase Hosted service but separately from the `supabase-csharp`, you'll need to specify
|
||||
your url and public key like so:
|
||||
|
||||
```c#
|
||||
var auth = new Supabase.Gotrue.Client(new ClientOptions<Session>
|
||||
{
|
||||
Url = "https://PROJECT_ID.supabase.co/auth/v1",
|
||||
Headers = new Dictionary<string, string>
|
||||
{
|
||||
{ "apikey", SUPABASE_PUBLIC_KEY },
|
||||
{ "Authorization", $"Bearer {SUPABASE_USER_TOKEN}" }
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
Leverage `Table`,`PrimaryKey`, and `Column` attributes to specify names of classes/properties that are different from
|
||||
their C# Versions.
|
||||
|
||||
```c#
|
||||
[Table("messages")]
|
||||
public class Message : BaseModel
|
||||
{
|
||||
[PrimaryKey("id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Column("username")]
|
||||
public string UserName { get; set; }
|
||||
|
||||
[Column("channel_id")]
|
||||
public int ChannelId { get; set; }
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is Message message &&
|
||||
Id == message.Id;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(Id);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Utilizing the client is then just a matter of instantiating it and specifying the Model one is working with.
|
||||
|
||||
```c#
|
||||
void Initialize()
|
||||
{
|
||||
var client = new Client("http://localhost:3000");
|
||||
|
||||
// Get All Messages
|
||||
var response = await client.Table<Message>().Get();
|
||||
List<Message> models = response.Models;
|
||||
|
||||
// Insert
|
||||
var newMessage = new Message { UserName = "acupofjose", ChannelId = 1 };
|
||||
await client.Table<Message>().Insert();
|
||||
|
||||
// Update
|
||||
var model = response.Models.First();
|
||||
model.UserName = "elrhomariyounes";
|
||||
await model.Update();
|
||||
|
||||
// Delete
|
||||
await response.Models.Last().Delete();
|
||||
}
|
||||
```
|
||||
|
||||
## Foreign Keys, Join Tables, and Relationships
|
||||
|
||||
The Postgrest server does introspection on relationships between tables and supports returning query data from
|
||||
tables with these included. **Foreign key constrains are required for postgrest to detect these relationships.**
|
||||
|
||||
This library implements the attribute, `Reference` to specify on a model when a relationship should be included in a
|
||||
query.
|
||||
|
||||
- [One-to-one Relationships](https://postgrest.org/en/stable/api.html#one-to-one-relationships): One-to-one
|
||||
relationships are detected if there’s an unique constraint on a foreign key.
|
||||
- [One-to-many Relationships](https://postgrest.org/en/stable/api.html#one-to-many-relationships): The inverse
|
||||
one-to-many relationship between two tables is detected based on the foreign key reference.
|
||||
- [Many-to-many Relationships](https://postgrest.org/en/stable/api.html#many-to-many-relationships): Many-to-many
|
||||
relationships are detected based on the join table. The join table must contain foreign keys to other two tables and
|
||||
they must be part of its composite key.
|
||||
|
||||
Given the following schema:
|
||||
|
||||

|
||||
|
||||
We can define the following models:
|
||||
|
||||
```c#
|
||||
[Table("movie")]
|
||||
public class Movie : BaseModel
|
||||
{
|
||||
[PrimaryKey("id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Column("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Reference(typeof(Person))]
|
||||
public List<Person> Persons { get; set; }
|
||||
|
||||
[Column("created_at")]
|
||||
public DateTime CreatedAt { get; set; }
|
||||
}
|
||||
|
||||
[Table("person")]
|
||||
public class Person : BaseModel
|
||||
{
|
||||
[PrimaryKey("id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Column("first_name")]
|
||||
public string FirstName { get; set; }
|
||||
|
||||
[Column("last_name")]
|
||||
public string LastName { get; set; }
|
||||
|
||||
[Reference(typeof(Profile))]
|
||||
public Profile Profile { get; set; }
|
||||
|
||||
[Column("created_at")]
|
||||
public DateTime CreatedAt { get; set; }
|
||||
}
|
||||
|
||||
[Table("profile")]
|
||||
public class Profile : BaseModel
|
||||
{
|
||||
[Column("email")]
|
||||
public string Email { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
**Note that each related model should inherit `BaseModel` and specify its `Table` and `Column` attributes as usual.**
|
||||
|
||||
The `Reference` Attribute by default will include the referenced model in all GET queries on the table (this can be
|
||||
disabled
|
||||
in its constructor).
|
||||
|
||||
As such, a query on the `Movie` model (given the above) would return something like:
|
||||
|
||||
```js
|
||||
[
|
||||
{
|
||||
id: 1,
|
||||
created_at: "2022-08-20T00:29:45.400188",
|
||||
name: "Top Gun: Maverick",
|
||||
person: [
|
||||
{
|
||||
id: 1,
|
||||
created_at: "2022-08-20T00:30:02.120528",
|
||||
first_name: "Tom",
|
||||
last_name: "Cruise",
|
||||
profile: {
|
||||
profile_id: 1,
|
||||
email: "tom.cruise@supabase.io",
|
||||
created_at: "2022-08-20T00:30:33.72443"
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
created_at: "2022-08-20T00:30:33.72443",
|
||||
first_name: "Bob",
|
||||
last_name: "Saggett",
|
||||
profile: {
|
||||
profile_id: 3,
|
||||
email: "bob.saggett@supabase.io",
|
||||
created_at: "2022-08-20T00:30:33.72443"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
// ...
|
||||
]
|
||||
```
|
||||
|
||||
### Circular References
|
||||
|
||||
Circular relations can be added between models, however, circular relations should only be parsed one level deep for
|
||||
models. For example, given the
|
||||
models [here](https://github.com/supabase-community/postgrest-csharp/blob/master/PostgrestTests/Models/LinkedModels.cs),
|
||||
a raw response would look like the following (note that the `Person` object returns the root `Movie` and
|
||||
the `Person->Profile` returns its root `Person` object).
|
||||
|
||||
If desired, this can be avoided by making specific join models that do not have the circular references.
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "68722a22-6a6b-4410-a955-b4eb8ca7953f",
|
||||
"created_at": "0001-01-01T05:51:00",
|
||||
"name": "Supabase in Action",
|
||||
"person": [
|
||||
{
|
||||
"id": "6aa849d8-dd09-4932-bc6f-6fe3b585e87f",
|
||||
"first_name": "John",
|
||||
"last_name": "Doe",
|
||||
"created_at": "0001-01-01T05:51:00",
|
||||
"movie": [
|
||||
{
|
||||
"id": "68722a22-6a6b-4410-a955-b4eb8ca7953f",
|
||||
"name": "Supabase in Action",
|
||||
"created_at": "0001-01-01T05:51:00"
|
||||
}
|
||||
],
|
||||
"profile": {
|
||||
"person_id": "6aa849d8-dd09-4932-bc6f-6fe3b585e87f",
|
||||
"email": "john.doe@email.com",
|
||||
"created_at": "0001-01-01T05:51:00",
|
||||
"person": {
|
||||
"id": "6aa849d8-dd09-4932-bc6f-6fe3b585e87f",
|
||||
"first_name": "John",
|
||||
"last_name": "Doe",
|
||||
"created_at": "0001-01-01T05:51:00"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "07abc67f-bf7d-4865-b2c0-76013dc2811f",
|
||||
"first_name": "Jane",
|
||||
"last_name": "Buck",
|
||||
"created_at": "0001-01-01T05:51:00",
|
||||
"movie": [
|
||||
{
|
||||
"id": "68722a22-6a6b-4410-a955-b4eb8ca7953f",
|
||||
"name": "Supabase in Action",
|
||||
"created_at": "0001-01-01T05:51:00"
|
||||
}
|
||||
],
|
||||
"profile": {
|
||||
"person_id": "07abc67f-bf7d-4865-b2c0-76013dc2811f",
|
||||
"email": "jane.buck@email.com",
|
||||
"created_at": "0001-01-01T05:51:00",
|
||||
"person": {
|
||||
"id": "07abc67f-bf7d-4865-b2c0-76013dc2811f",
|
||||
"first_name": "Jane",
|
||||
"last_name": "Buck",
|
||||
"created_at": "0001-01-01T05:51:00"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Top Level Filtering
|
||||
|
||||
**By default** relations expect to be used as top level filters on a query. If following the models above, this would
|
||||
mean that a `Movie` with no `Person` relations on it would not return on a query **unless** the `Relation`
|
||||
has `useInnerJoin` set to `false`:
|
||||
|
||||
The following model would return any movie, even if there are no `Person` models associated with it:
|
||||
|
||||
```c#
|
||||
[Table("movie")]
|
||||
public class Movie : BaseModel
|
||||
{
|
||||
[PrimaryKey("id")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[Column("name")]
|
||||
public string? Name { get; set; }
|
||||
|
||||
[Reference(typeof(Person), useInnerJoin: false)]
|
||||
public List<Person> People { get; set; } = new();
|
||||
}
|
||||
```
|
||||
|
||||
**Further Notes**:
|
||||
|
||||
- Postgrest _does not support nested inserts or upserts_. Relational keys on models will be ignored when attempting to
|
||||
insert or upsert on a root model.
|
||||
- The `Relation` attribute uses reflection to only select the attributes specified on the Class Model (i.e.
|
||||
the `Profile` model has a property only for `email`, only the property will be requested in the query).
|
||||
|
||||
## Status
|
||||
|
||||
- [x] Connects to PostgREST Server
|
||||
- [x] Authentication
|
||||
- [x] Basic Query Features
|
||||
- [x] CRUD
|
||||
- [x] Single
|
||||
- [x] Range (to & from)
|
||||
- [x] Limit
|
||||
- [x] Limit w/ Foreign Key
|
||||
- [x] Offset
|
||||
- [x] Offset w/ Foreign Key
|
||||
- [x] Advanced Query Features
|
||||
- [x] Filters
|
||||
- [x] Ordering
|
||||
- [ ] Custom Serializers
|
||||
- [ ] [Postgres Range](https://www.postgresql.org/docs/9.3/rangetypes.html)
|
||||
- [x] `int4range`, `int8range`
|
||||
- [ ] `numrange`
|
||||
- [ ] `tsrange`, `tstzrange`, `daterange`
|
||||
- [x] Models
|
||||
- [x] `BaseModel` to derive from
|
||||
- [x] Coercion of data into Models
|
||||
- [x] Unit Testing
|
||||
- [x] Nuget Package and Release
|
||||
|
||||
## Package made possible through the efforts of:
|
||||
|
||||
| <img src="https://github.com/acupofjose.png" width="150" height="150"> | <img src="https://github.com/elrhomariyounes.png" width="150" height="150"> |
|
||||
|:----------------------------------------------------------------------:|:---------------------------------------------------------------------------:|
|
||||
| [acupofjose](https://github.com/acupofjose) | [elrhomariyounes](https://github.com/elrhomariyounes) |
|
||||
|
||||
## Contributing
|
||||
|
||||
We are more than happy to have contributions! Please submit a PR.
|
BIN
Packages/Supabase.Postgrest.4.1.0/Supabase.Postgrest.4.1.0.nupkg
vendored
Normal file
BIN
Packages/Supabase.Postgrest.4.1.0/icon.png
vendored
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
Packages/Supabase.Postgrest.4.1.0/lib/netstandard2.0/Supabase.Postgrest.dll
vendored
Normal file
1885
Packages/Supabase.Postgrest.4.1.0/lib/netstandard2.0/Supabase.Postgrest.xml
vendored
Normal file
BIN
Packages/Supabase.Realtime.7.2.0/.signature.p7s
vendored
Normal file
294
Packages/Supabase.Realtime.7.2.0/README.md
vendored
Normal file
@ -0,0 +1,294 @@
|
||||
# Supabase.Realtime
|
||||
|
||||
[](https://github.com/supabase-community/realtime-csharp/actions/workflows/build-and-test.yml)
|
||||
[](https://www.nuget.org/packages/Supabase.Realtime/)
|
||||
|
||||
## [Notice]: v7.0.0 renames this package from `realtime-csharp` to `Supabase.Realtime`. The depreciation notice has been set in NuGet. The API remains the same.
|
||||
|
||||
|
||||
## BREAKING CHANGES MOVING FROM v5.x.x to v6.x.x
|
||||
|
||||
- The realtime client now takes a "fail-fast" approach. On establishing an initial connection, client will throw
|
||||
a `RealtimeException` in `ConnectAsync()` if the socket server is unreachable. After an initial connection has been
|
||||
established, the **client will continue attempting reconnections indefinitely until disconnected.**
|
||||
- [Major, New] C# `EventHandlers` have been changed to `delegates`. This should allow for cleaner event data access over
|
||||
the previous subclassed `EventArgs` setup. Events are scoped accordingly. For example, the `RealtimeSocket` error
|
||||
handlers will receive events regarding socket connectivity; whereas the `RealtimeChannel` error handlers will receive
|
||||
events according to `Channel` joining/leaving/etc. This is implemented with the following methods prefixed by (
|
||||
Add/Remove/Clear):
|
||||
- `RealtimeBroadcast.AddBroadcastEventHandler`
|
||||
- `RealtimePresence.AddPresenceEventHandler`
|
||||
- `RealtimeSocket.AddStateChangedHandler`
|
||||
- `RealtimeSocket.AddMessageReceivedHandler`
|
||||
- `RealtimeSocket.AddHeartbeatHandler`
|
||||
- `RealtimeSocket.AddErrorHandler`
|
||||
- `RealtimeClient.AddDebugHandler`
|
||||
- `RealtimeClient.AddStateChangedHandler`
|
||||
- `RealtimeChannel.AddPostgresChangeHandler`
|
||||
- `RealtimeChannel.AddMessageReceivedHandler`
|
||||
- `RealtimeChannel.AddErrorHandler`
|
||||
- `Push.AddMessageReceivedHandler`
|
||||
- [Major, new] `ClientOptions.Logger` has been removed in favor of `Client.AddDebugHandler()` which allows for
|
||||
implementing custom logging solutions if desired.
|
||||
- A simple logger can be set up with the following:
|
||||
```c#
|
||||
client.AddDebugHandler((sender, message, exception) => Debug.WriteLine(message));
|
||||
```
|
||||
- [Major] `Connect()` has been marked `Obsolete` in favor of `ConnectAsync()`
|
||||
- Custom reconnection logic has been removed in favor of using the built-in logic from `Websocket.Client@4.6.1`.
|
||||
- Exceptions that are handled within this library have been marked as `RealtimeException`s.
|
||||
- The local, docker-composed test suite has been brought back (as opposed to remotely testing on live supabase servers)
|
||||
to test against.
|
||||
- Comments have been added throughout the entire codebase and an `XML` file is now generated on build.
|
||||
|
||||
---
|
||||
|
||||
**See realtime-csharp in action [here](https://multiplayer-csharp.azurewebsites.net/).**
|
||||
|
||||
`realtime-csharp` is written as a client library for [supabase/realtime](https://github.com/supabase/realtime).
|
||||
|
||||
Documentation can be
|
||||
found [here](https://supabase-community.github.io/realtime-csharp/api/Supabase.Realtime.Client.html).
|
||||
|
||||
The bulk of this library is a translation and c-sharp-ification of
|
||||
the [supabase/realtime-js](https://github.com/supabase/realtime-js) library.
|
||||
|
||||
**The Websocket-sharp implementation that Realtime-csharp is dependent on does _not_ support TLS1.3**
|
||||
|
||||
## Getting Started
|
||||
|
||||
Care was had to make this API as _easy<sup>tm</sup>_ to interact with as possible. `Connect()` and `Subscribe()`
|
||||
have `await`-able signatures
|
||||
which allow Users to be assured that a connection exists prior to interacting with it.
|
||||
|
||||
```c#
|
||||
var endpoint = "ws://realtime-dev.localhost:4000/socket";
|
||||
client = new Client(endpoint);
|
||||
|
||||
await client.ConnectAsync();
|
||||
|
||||
// Shorthand for registering a postgres_changes subscription
|
||||
var channel = client.Channel("realtime", "public", "todos");
|
||||
|
||||
// Listen to Updates
|
||||
channel.AddPostgresChangeHandler(ListenType.Updates, (_, change) =>
|
||||
{
|
||||
var model = change.Model<Todo>();
|
||||
var oldModel = change.OldModel<Todo>();
|
||||
});
|
||||
await channel.Subscribe();
|
||||
```
|
||||
|
||||
Leveraging `Postgrest.BaseModel`s, one ought to be able to coerce SocketResponse Records into their associated models by
|
||||
calling:
|
||||
|
||||
```c#
|
||||
// ...
|
||||
var channel = client.Channel("realtime", "public", "users");
|
||||
|
||||
channel.AddPostgresChangeHandler(ListenType.Inserts, (_, change) =>
|
||||
{
|
||||
var model = change.Model<Todo>();
|
||||
});
|
||||
|
||||
await channel.Subscribe();
|
||||
```
|
||||
|
||||
## Broadcast
|
||||
|
||||
"Broadcast follows the publish-subscribe pattern where a client publishes messages to a channel with a unique
|
||||
identifier. For example, a user could send a message to a channel with id room-1.
|
||||
|
||||
Other clients can elect to receive the message in real-time by subscribing to the channel with id room-1. If these
|
||||
clients are online and subscribed then they will receive the message.
|
||||
|
||||
Broadcast works by connecting your client to the nearest Realtime server, which will communicate with other servers to
|
||||
relay messages to other clients.
|
||||
|
||||
A common use-case is sharing a user's cursor position with other clients in an online game."
|
||||
|
||||
[Find more information here](https://supabase.com/docs/guides/realtime#broadcast)
|
||||
|
||||
**Given the following model (`CursorBroadcast`):**
|
||||
|
||||
```c#
|
||||
class MouseBroadcast : BaseBroadcast<MouseStatus> { }
|
||||
class MouseStatus
|
||||
{
|
||||
[JsonProperty("mouseX")]
|
||||
public float MouseX { get; set; }
|
||||
|
||||
[JsonProperty("mouseY")]
|
||||
public float MouseY { get; set; }
|
||||
|
||||
[JsonProperty("userId")]
|
||||
public string UserId { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
**Listen for typed broadcast events**:
|
||||
|
||||
```c#
|
||||
var channel = supabase.Realtime.Channel("cursor");
|
||||
|
||||
var broadcast = channel.Register<MouseBroadcast>(false, true);
|
||||
broadcast.AddBroadcastEventHandler((sender, _) =>
|
||||
{
|
||||
// Retrieved typed model.
|
||||
var state = broadcast.Current();
|
||||
|
||||
Debug.WriteLine($"{state.Payload}: {state.Payload.MouseX}:{state.Payload.MouseY}");
|
||||
});
|
||||
await channel.Subscribe();
|
||||
```
|
||||
|
||||
**Broadcast an event**:
|
||||
|
||||
```c#
|
||||
var channel = supabase.Realtime.Channel("cursor");
|
||||
var data = new CursorBroadcast { Event = "cursor", Payload = new MouseStatus { MouseX = 123, MouseY = 456 } };
|
||||
channel.Send(ChannelType.Broadcast, data);
|
||||
```
|
||||
|
||||
## Presence
|
||||
|
||||
"Presence utilizes an in-memory conflict-free replicated data type (CRDT) to track and synchronize shared state in an
|
||||
eventually consistent manner. It computes the difference between existing state and new state changes and sends the
|
||||
necessary updates to clients via Broadcast.
|
||||
|
||||
When a new client subscribes to a channel, it will immediately receive the channel's latest state in a single message
|
||||
instead of waiting for all other clients to send their individual states.
|
||||
|
||||
Clients are free to come-and-go as they please, and as long as they are all subscribed to the same channel then they
|
||||
will all have the same Presence state as each other.
|
||||
|
||||
The neat thing about Presence is that if a client is suddenly disconnected (for example, they go offline), their state
|
||||
will be automatically removed from the shared state. If you've ever tried to build an “I'm online” feature which handles
|
||||
unexpected disconnects, you'll appreciate how useful this is."
|
||||
|
||||
[Find more information here](https://supabase.com/docs/guides/realtime#presence)
|
||||
|
||||
**Given the following model: (`UserPresence`)**
|
||||
|
||||
```c#
|
||||
class UserPresence: BasePresence
|
||||
{
|
||||
[JsonProperty("lastSeen")]
|
||||
public DateTime LastSeen { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
**Listen for typed presence events**:
|
||||
|
||||
```c#
|
||||
var presenceId = Guid.NewGuid().ToString();
|
||||
|
||||
var channel = supabase.Realtime.Channel("last-seen");
|
||||
var presence = channel.Register<UserPresence>(presenceId);
|
||||
|
||||
presence.AddPresenceEventHandler(EventType.Sync, (sender, type) =>
|
||||
{
|
||||
foreach (var state in presence.CurrentState)
|
||||
{
|
||||
var userId = state.Key;
|
||||
var lastSeen = state.Value.First().LastSeen;
|
||||
Debug.WriteLine($"{userId}: {lastSeen}");
|
||||
}
|
||||
});
|
||||
await channel.Subscribe();
|
||||
```
|
||||
|
||||
**Track a user presence event**:
|
||||
|
||||
```c#
|
||||
var presenceId = Guid.NewGuid().ToString();
|
||||
var channel = supabase.Realtime.Channel("last-seen");
|
||||
|
||||
var presence = channel.Register<UserPresence>(presenceId);
|
||||
presence.Track(new UserPresence { LastSeen = DateTime.Now });
|
||||
```
|
||||
|
||||
## Postgres Changes
|
||||
|
||||
"Postgres Changes enable you to listen to database changes and have them broadcast to authorized clients based
|
||||
on [Row Level Security (RLS)](https://supabase.com/docs/guides/auth/row-level-security) policies.
|
||||
|
||||
This works by Realtime polling your database's logical replication slot for changes, passing those changes to
|
||||
the [apply_rls](https://github.com/supabase/walrus#reading-wal) SQL function to determine which clients have permission,
|
||||
and then using Broadcast to send those changes to clients.
|
||||
|
||||
Realtime requires a publication called `supabase_realtime` to determine which tables to poll. You must add tables to
|
||||
this publication prior to clients subscribing to channels that want to listen for database changes.
|
||||
|
||||
We strongly encourage you to enable RLS on your database tables and have RLS policies in place to prevent unauthorized
|
||||
parties from accessing your data."
|
||||
|
||||
[Find More Information here](https://supabase.com/docs/guides/realtime#postgres-changes)
|
||||
|
||||
**Using the new `Register` method:**
|
||||
|
||||
```c#
|
||||
var channel = supabase.Realtime.Channel("public-users");
|
||||
channel.Register(new PostgresChangesOptions("public", "users"));
|
||||
channel.AddPostgresChangeHandler(ListenType.All, (sender, change) =>
|
||||
{
|
||||
switch (change.Event)
|
||||
{
|
||||
case EventType.Insert:
|
||||
// User has been created
|
||||
break;
|
||||
case EventType.Update:
|
||||
// User has been updated
|
||||
break;
|
||||
case EventType.Delete:
|
||||
// User has been deleted
|
||||
break;
|
||||
}
|
||||
});
|
||||
await channel.Subscribe();
|
||||
```
|
||||
|
||||
## Status
|
||||
|
||||
- [x] Client Connects to Websocket
|
||||
- [x] Socket Event Handlers
|
||||
- [x] Open
|
||||
- [x] Close - when channel is explicitly closed by server or by calling `Channel.Unsubscribe()`
|
||||
- [x] Error
|
||||
- [x] Realtime Event Handlers
|
||||
- [x] `INSERT`
|
||||
- [x] `UPDATE`
|
||||
- [x] `DELETE`
|
||||
- [x] `*`
|
||||
- [x] Join channels of format:
|
||||
- [x] `{database}`
|
||||
- [x] `{database}:{schema}`
|
||||
- [x] `{database}:{schema}:{table}`
|
||||
- [x] `{database}:{schema}:{table}:{col}.eq.{val}`
|
||||
- [x] Responses supply a Generically Typed Model derived from `BaseModel`
|
||||
- [x] Ability to remove subscription to Realtime Events
|
||||
- [x] Ability to disconnect from socket.
|
||||
- [x] Socket reconnects when possible
|
||||
- [x] Unit Tests
|
||||
- [x] Documentation
|
||||
- [x] Nuget Release
|
||||
|
||||
## Package made possible through the efforts of:
|
||||
|
||||
Join the ranks! See a problem? Help fix it!
|
||||
|
||||
<a href="https://github.com/supabase-community/realtime-csharp/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=supabase-community/realtime-csharp" />
|
||||
</a>
|
||||
|
||||
Made with [contrib.rocks](https://contrib.rocks/preview?repo=supabase-community%2Frealtime-csharp).
|
||||
|
||||
## Contributing
|
||||
|
||||
We are more than happy to have contributions! Please submit a PR.
|
||||
|
||||
## Testing
|
||||
|
||||
Note that the latest versions of `supabase/realtime` expect to be able to access a subdomain matching the tenant. For
|
||||
the case of testing, this means that `realtime-dev.localhost:4000` should be available. To have tests run locally,
|
||||
please add a hosts entry on your system for: `127.0.0.1 realtime-dev.localhost`
|
BIN
Packages/Supabase.Realtime.7.2.0/Supabase.Realtime.7.2.0.nupkg
vendored
Normal file
BIN
Packages/Supabase.Realtime.7.2.0/icon.png
vendored
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
Packages/Supabase.Realtime.7.2.0/lib/netstandard2.0/Supabase.Realtime.dll
vendored
Normal file
2741
Packages/Supabase.Realtime.7.2.0/lib/netstandard2.0/Supabase.Realtime.xml
vendored
Normal file
BIN
Packages/Supabase.Realtime.7.2.0/lib/netstandard2.1/Supabase.Realtime.dll
vendored
Normal file
2741
Packages/Supabase.Realtime.7.2.0/lib/netstandard2.1/Supabase.Realtime.xml
vendored
Normal file
BIN
Packages/System.Reactive.5.0.0/.signature.p7s
vendored
Normal file
BIN
Packages/System.Reactive.5.0.0/System.Reactive.5.0.0.nupkg
vendored
Normal file
0
Packages/System.Reactive.5.0.0/build/net5.0/_._
vendored
Normal file
BIN
Packages/System.Reactive.5.0.0/build/netcoreapp3.1/System.Reactive.dll
vendored
Normal file
12
Packages/System.Reactive.5.0.0/build/netcoreapp3.1/System.Reactive.targets
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<UseWindowsRxVersion Condition="'$(UseWpf)' == 'true' OR '$(UseWindowsForms)' == 'true'" >true</UseWindowsRxVersion>
|
||||
<UseWindowsRxVersion Condition="'$(UseWindowsRxVersion)' == '' " >false</UseWindowsRxVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Condition="'$(UseWindowsRxVersion)' == 'true' " Include="$(MSBuildThisFileDirectory)..\..\build\netcoreapp3.1\System.Reactive.dll" />
|
||||
<Reference Condition="'$(UseWindowsRxVersion)' != 'true' " Include="$(MSBuildThisFileDirectory)..\..\lib\netstandard2.0\System.Reactive.dll" />
|
||||
|
||||
<FrameworkReference Include="Microsoft.WindowsDesktop.App" Condition="'$(UseWindowsRxVersion)' == 'true' and !@(FrameworkReference->AnyHaveMetadataValue('Identity', 'Microsoft.WindowsDesktop.App'))" />
|
||||
</ItemGroup>
|
||||
</Project>
|