using UnityEngine; using UnityEditor; using System.IO; /// /// Pulls project files (scripts, sprites, anything listed) from the AFX /// server into this project. The server publishes manifest.txt with one /// "relative/path size" line per file, relative to the project root. /// Menu: AFX > Sync from Server. Scripts that change trigger a recompile. /// public static class AFXSync { public const string Base = "http://78.110.173.123/afx/"; [MenuItem("AFX/Sync from Server")] public static void Sync() { PlayerSettings.insecureHttpOption = InsecureHttpOption.AlwaysAllowed; string manifest = FetchText(Base + "manifest.txt"); if (manifest == null) { Debug.LogError("AFX sync: could not fetch " + Base + "manifest.txt"); return; } int got = 0, skipped = 0; foreach (var raw in manifest.Split('\n')) { var line = raw.Trim(); if (line.Length == 0 || line.StartsWith("#")) continue; int sp = line.LastIndexOf(' '); string rel = sp > 0 ? line.Substring(0, sp) : line; long size = sp > 0 && long.TryParse(line.Substring(sp + 1), out var sz) ? sz : -1; if (rel.Contains("..") || rel.StartsWith("/")) continue; // keep writes inside the project if (File.Exists(rel) && size >= 0 && new FileInfo(rel).Length == size) { skipped++; continue; } var bytes = FetchBytes(Base + rel); if (bytes == null) { Debug.LogWarning("AFX sync: failed " + rel); continue; } var dir = Path.GetDirectoryName(rel); if (!string.IsNullOrEmpty(dir)) Directory.CreateDirectory(dir); // root files (CLAUDE.md) have no folder File.WriteAllBytes(rel, bytes); if (rel.EndsWith(".png")) { // generated maps depend on the sprite's alpha; drop them so they rebuild string stem = rel.Substring(0, rel.Length - 4); AssetDatabase.DeleteAsset(stem + "_n.png"); AssetDatabase.DeleteAsset(stem + "_ao.png"); } got++; Debug.Log("AFX sync: " + rel + " (" + bytes.Length + " bytes)"); } AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate); if (got > 0) EditorUtility.RequestScriptReload(); // Unity sometimes misses scripts written from outside; make sure new code actually compiles Debug.Log("AFX sync done: " + got + " updated, " + skipped + " unchanged."); } public static string FetchText(string url) { var b = FetchBytes(url); return b == null ? null : System.Text.Encoding.UTF8.GetString(b); } public static byte[] FetchBytes(string url) { using (var req = UnityEngine.Networking.UnityWebRequest.Get(url)) { req.timeout = 30; var op = req.SendWebRequest(); while (!op.isDone) System.Threading.Thread.Sleep(10); if (req.result != UnityEngine.Networking.UnityWebRequest.Result.Success) { Debug.LogWarning("AFX sync: " + url + " -> " + req.error); return null; } return req.downloadHandler.data; } } }