RizzeBattleRoyale/Assets/Editor/PlayersDevTools.cs
2025-10-15 20:28:33 +04:00

206 lines
6.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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