initial commit
This commit is contained in:
232
unity/Assets/Guildlib/Editor/GuildlibSyncWindow.cs
Normal file
232
unity/Assets/Guildlib/Editor/GuildlibSyncWindow.cs
Normal file
@@ -0,0 +1,232 @@
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Guildlib.Runtime;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Guildlib.Editor
|
||||
{
|
||||
public class GuildlibSyncWindow : EditorWindow
|
||||
{
|
||||
GuildlibConfig config;
|
||||
string log = "";
|
||||
bool busy = false;
|
||||
Vector2 scroll;
|
||||
string statusText = "Not connected";
|
||||
bool statusOk = false;
|
||||
|
||||
// Platform / tag filter toggles for pull operations
|
||||
bool filterByPlatform = false;
|
||||
bool filterByTag = false;
|
||||
string platformFilter = "";
|
||||
string tagFilter = "";
|
||||
|
||||
[MenuItem("Window/Guildlib/Sync Panel")]
|
||||
static void Open() => GetWindow<GuildlibSyncWindow>("Guildlib").Show();
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
config = GuildlibConfig.Load();
|
||||
if (config == null)
|
||||
Log("No GuildlibConfig found. Create one via Assets > Create > Guildlib > Config.");
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
EditorGUILayout.Space(6);
|
||||
EditorGUILayout.LabelField("Guildlib Sync Panel", EditorStyles.boldLabel);
|
||||
EditorGUILayout.Space(4);
|
||||
|
||||
config = (GuildlibConfig)EditorGUILayout.ObjectField("Config", config, typeof(GuildlibConfig), false);
|
||||
if (config == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Assign a GuildlibConfig asset.", MessageType.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.LabelField("Server", config.serverUrl, EditorStyles.miniLabel);
|
||||
var style = statusOk ? EditorStyles.boldLabel : EditorStyles.miniLabel;
|
||||
EditorGUILayout.LabelField("Status", statusText, style);
|
||||
|
||||
EditorGUILayout.Space(8);
|
||||
|
||||
// ── Filters ──────────────────────────────────────────────────────
|
||||
EditorGUILayout.LabelField("Pull filters (optional)", EditorStyles.boldLabel);
|
||||
|
||||
filterByPlatform = EditorGUILayout.Toggle("Filter by platform", filterByPlatform);
|
||||
if (filterByPlatform)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
platformFilter = EditorGUILayout.TextField("Platforms (comma-separated)", platformFilter);
|
||||
EditorGUILayout.HelpBox(
|
||||
"Example: pc,ps5\n" +
|
||||
"Valid values: " + string.Join(", ", GuildPlatformRegistry.All),
|
||||
MessageType.Info);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
filterByTag = EditorGUILayout.Toggle("Filter by tag", filterByTag);
|
||||
if (filterByTag)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
tagFilter = EditorGUILayout.TextField("Tags (comma-separated)", tagFilter);
|
||||
EditorGUILayout.HelpBox(
|
||||
"Example: release,base_game\n" +
|
||||
"Valid values: " + string.Join(", ", GuildTagRegistry.All),
|
||||
MessageType.Info);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(8);
|
||||
|
||||
// ── Action buttons ────────────────────────────────────────────────
|
||||
EditorGUI.BeginDisabledGroup(busy);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("Ping Server", GUILayout.Height(28))) RunAsync(PingAsync);
|
||||
if (GUILayout.Button("Pull All Shards", GUILayout.Height(28))) RunAsync(PullAllAsync);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("Export Schema", GUILayout.Height(28))) RunAsync(ExportAsync);
|
||||
if (GUILayout.Button("Upload Schema", GUILayout.Height(28))) RunAsync(UploadAsync);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
EditorGUILayout.Space(8);
|
||||
EditorGUILayout.LabelField("Log", EditorStyles.boldLabel);
|
||||
scroll = EditorGUILayout.BeginScrollView(scroll, GUILayout.Height(240));
|
||||
EditorGUILayout.TextArea(log, GUILayout.ExpandHeight(true));
|
||||
EditorGUILayout.EndScrollView();
|
||||
|
||||
if (GUILayout.Button("Clear", GUILayout.Height(18))) log = "";
|
||||
}
|
||||
|
||||
// ── Handlers ─────────────────────────────────────────────────────────
|
||||
|
||||
async Task PingAsync()
|
||||
{
|
||||
Log("Pinging...");
|
||||
try
|
||||
{
|
||||
using var http = MakeHttp();
|
||||
var json = await http.GetStringAsync($"{config.serverUrl}/health");
|
||||
var data = JsonConvert.DeserializeObject<dynamic>(json);
|
||||
statusOk = true;
|
||||
statusText = $"Online — shards: {string.Join(", ", ((Newtonsoft.Json.Linq.JArray)data.shards) ?? new Newtonsoft.Json.Linq.JArray())}";
|
||||
Log($"OK — {statusText}");
|
||||
}
|
||||
catch (Exception e) { statusOk = false; statusText = "Unreachable"; Log($"FAIL: {e.Message}"); }
|
||||
}
|
||||
|
||||
async Task PullAllAsync()
|
||||
{
|
||||
var platforms = filterByPlatform && !string.IsNullOrWhiteSpace(platformFilter)
|
||||
? new System.Collections.Generic.List<string>(platformFilter.Split(',', StringSplitOptions.RemoveEmptyEntries))
|
||||
: null;
|
||||
var tagList = filterByTag && !string.IsNullOrWhiteSpace(tagFilter)
|
||||
? new System.Collections.Generic.List<string>(tagFilter.Split(',', StringSplitOptions.RemoveEmptyEntries))
|
||||
: null;
|
||||
|
||||
if (platforms != null) Log($"Platform filter: {string.Join(", ", platforms)}");
|
||||
if (tagList != null) Log($"Tag filter: {string.Join(", ", tagList)}");
|
||||
|
||||
// Determine which shards to sync
|
||||
var targets = config.GetSyncTargets();
|
||||
if (targets == null)
|
||||
{
|
||||
// Ask server for all available shards
|
||||
using var http = MakeHttp();
|
||||
var json = await http.GetStringAsync($"{config.serverUrl}/health");
|
||||
var data = JsonConvert.DeserializeObject<dynamic>(json);
|
||||
var arr = (Newtonsoft.Json.Linq.JArray)data.shards;
|
||||
targets = arr?.ToObject<string[]>() ?? Array.Empty<string>();
|
||||
}
|
||||
|
||||
Log($"Pulling {targets.Length} shard(s): {string.Join(", ", targets)}");
|
||||
int totalAdded = 0, totalUpdated = 0, totalSkipped = 0;
|
||||
|
||||
foreach (var shard in targets)
|
||||
{
|
||||
try
|
||||
{
|
||||
var client = new ShardClient(config, shard);
|
||||
var result = await client.PullAsync(platforms, tagList);
|
||||
totalAdded += result.added;
|
||||
totalUpdated += result.updated;
|
||||
totalSkipped += result.skipped;
|
||||
Log($" {shard}: +{result.added} added ~{result.updated} updated {result.skipped} unchanged");
|
||||
}
|
||||
catch (Exception e) { Log($" {shard}: FAIL — {e.Message}"); }
|
||||
}
|
||||
|
||||
Log($"Done — added:{totalAdded} updated:{totalUpdated} skipped:{totalSkipped}");
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
async Task ExportAsync()
|
||||
{
|
||||
Log("Exporting schema...");
|
||||
try
|
||||
{
|
||||
var json = SchemaExporter.Export(config.projectId);
|
||||
var dir = Path.Combine(Application.dataPath, "..", "GuildlibExports");
|
||||
Directory.CreateDirectory(dir);
|
||||
var path = Path.Combine(dir, "schema.json");
|
||||
File.WriteAllText(path, json);
|
||||
Log($"Exported to: {path}");
|
||||
}
|
||||
catch (Exception e) { Log($"FAIL: {e.Message}"); }
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
async Task UploadAsync()
|
||||
{
|
||||
Log("Uploading schema...");
|
||||
try
|
||||
{
|
||||
var json = SchemaExporter.Export(config.projectId);
|
||||
using var http = MakeHttp();
|
||||
var resp = await http.PostAsync(
|
||||
$"{config.serverUrl}/schema",
|
||||
new StringContent(json, Encoding.UTF8, "application/json"));
|
||||
resp.EnsureSuccessStatusCode();
|
||||
Log("Schema uploaded.");
|
||||
}
|
||||
catch (Exception e) { Log($"FAIL: {e.Message}"); }
|
||||
}
|
||||
|
||||
// ── Helpers ───────────────────────────────────────────────────────────
|
||||
|
||||
HttpClient MakeHttp()
|
||||
{
|
||||
var h = new HttpClient();
|
||||
if (!string.IsNullOrEmpty(config.apiKey))
|
||||
h.DefaultRequestHeaders.Add("X-Api-Key", config.apiKey);
|
||||
return h;
|
||||
}
|
||||
|
||||
void Log(string msg)
|
||||
{
|
||||
log = $"[{DateTime.Now:HH:mm:ss}] {msg}\n{log}";
|
||||
Repaint();
|
||||
}
|
||||
|
||||
void RunAsync(Func<Task> fn)
|
||||
{
|
||||
busy = true;
|
||||
fn().ContinueWith(_ =>
|
||||
{
|
||||
busy = false;
|
||||
EditorApplication.delayCall += Repaint;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user