Land Explorer in HomeCamp with boot loading, journal UI, and CDN publish tooling.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -107,6 +107,16 @@ namespace AOT.Editor.YooAssetTools
|
||||
AssetPathToGUIDOptions.OnlyExistingAssets))).ToArray())
|
||||
BundleCollectorSettingData.RemoveCollector(group, collector);
|
||||
|
||||
const string campScene = "Assets/Bundles/Scenes/Town/HomeCamp/HomeCamp.unity";
|
||||
if (string.IsNullOrEmpty(AssetDatabase.AssetPathToGUID(campScene, AssetPathToGUIDOptions.OnlyExistingAssets)))
|
||||
throw new InvalidOperationException("HomeCamp scene is missing: " + campScene);
|
||||
if (!group.Collectors.Any(c => c.CollectPath == campScene))
|
||||
BundleCollectorSettingData.CreateCollector(group, new BundleCollector {
|
||||
CollectPath = campScene, CollectorGUID = AssetDatabase.AssetPathToGUID(campScene),
|
||||
CollectorType = ECollectorType.MainAssetCollector, AddressRuleName = nameof(AddressByFileName),
|
||||
PackRuleName = nameof(PackSeparately), FilterRuleName = nameof(CollectScene), AssetTags = "art"
|
||||
});
|
||||
|
||||
package.CheckConfigError();
|
||||
BundleCollectorSettingData.SaveFile();
|
||||
return "ok scene entries=" + group.Collectors.Count;
|
||||
|
||||
@@ -173,7 +173,7 @@ namespace AOT.Editor.YooAssetTools
|
||||
var prod = VersionJson(packVersion, resVersion, PublicCdnRoot);
|
||||
WriteText(Path.Combine(CdnRoot, Channel, "version.json"), local);
|
||||
WriteText(Path.Combine(CdnRoot, Channel, "version.prod.json"), prod);
|
||||
WriteText(Path.Combine(Application.streamingAssetsPath, "cdn", "version.json"), local);
|
||||
WriteText(Path.Combine(Application.streamingAssetsPath, "cdn", "version.json"), prod);
|
||||
}
|
||||
|
||||
static string VersionJson(string packVersion, string resVersion, string cdnRoot)
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Debug = UnityEngine.Debug;
|
||||
|
||||
namespace AOT.Editor.YooAssetTools
|
||||
{
|
||||
/// <summary>Explicit, incremental publication of the current WebGL resource packages.</summary>
|
||||
public static class CdnPublisher
|
||||
{
|
||||
static bool _busy;
|
||||
static string Repo => Path.GetFullPath(Path.Combine(Application.dataPath, "../.."));
|
||||
static string Config => Path.Combine(Repo, "Tools/cdn_publish.local.json");
|
||||
static string LogPath => Path.Combine(Repo, "Tools/output/cdn_publish/last-unity.log");
|
||||
public static string Status { get; private set; } = "idle";
|
||||
|
||||
[MenuItem("AIGame/CDN/Check SSH Connection")]
|
||||
public static async void CheckSshMenu() => await Guard(() => RunPython("check"));
|
||||
|
||||
[MenuItem("AIGame/CDN/Preview Upload Changes")]
|
||||
public static async void PreviewMenu() => await Guard(() => RunPython("plan --compare"));
|
||||
|
||||
[MenuItem("AIGame/CDN/Upload Staged Resources")]
|
||||
public static async void UploadMenu() => await Guard(() => RunPython("upload"));
|
||||
|
||||
[MenuItem("AIGame/CDN/Build And Upload (Art + HotUpdate)")]
|
||||
public static async void BuildAndUploadMenu() => await Guard(async () => {
|
||||
await RunPython("check");
|
||||
BuildPackages();
|
||||
await RunPython("upload");
|
||||
});
|
||||
|
||||
[MenuItem("AIGame/CDN/Prepare SSH Key")]
|
||||
public static async void PrepareKeyMenu() => await Guard(() => RunPython("init-key"));
|
||||
|
||||
[MenuItem("AIGame/CDN/Open Publish Folder")]
|
||||
public static void OpenPublishFolder()
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(LogPath));
|
||||
EditorUtility.RevealInFinder(Path.GetDirectoryName(LogPath));
|
||||
}
|
||||
|
||||
public static string BuildPackages()
|
||||
{
|
||||
if (EditorApplication.isPlaying || EditorApplication.isCompiling)
|
||||
throw new InvalidOperationException("Stop Play Mode and finish compiling before building CDN resources.");
|
||||
if (EditorUserBuildSettings.activeBuildTarget != BuildTarget.WebGL)
|
||||
throw new InvalidOperationException("CDN packages must be built for WebGL. Select that target first.");
|
||||
Status = "building Art";
|
||||
var art = BuildAndStageArt.BuildConfiguredAndStage();
|
||||
if (!art.StartsWith("ok", StringComparison.Ordinal)) throw new InvalidOperationException(art);
|
||||
Debug.Log("[CDN] " + art);
|
||||
Status = "building HotUpdate";
|
||||
var raw = BuildAndStageHotUpdate.BuildAndStage();
|
||||
if (!raw.StartsWith("ok", StringComparison.Ordinal)) throw new InvalidOperationException(raw);
|
||||
Debug.Log("[CDN] " + raw);
|
||||
Status = "packages staged";
|
||||
return art + " | " + raw;
|
||||
}
|
||||
|
||||
static async Task Guard(Func<Task> action)
|
||||
{
|
||||
if (_busy) { Debug.LogWarning("[CDN] A publish command is already running."); return; }
|
||||
_busy = true;
|
||||
try { await action(); Status = "completed"; Debug.Log("[CDN] Completed. Log: " + LogPath); }
|
||||
catch (Exception error) { Status = "failed"; Debug.LogError("[CDN] " + error.Message); }
|
||||
finally { _busy = false; }
|
||||
}
|
||||
|
||||
static async Task RunPython(string command)
|
||||
{
|
||||
if (!File.Exists(Config))
|
||||
File.Copy(Path.Combine(Repo, "Tools/cdn_publish.example.json"), Config);
|
||||
Status = command;
|
||||
var pending = new ConcurrentQueue<string>();
|
||||
var start = new ProcessStartInfo {
|
||||
FileName = EditorPrefs.GetString("AIGame.CdnPython", "python"),
|
||||
Arguments = "\"" + Path.Combine(Repo, "Tools/publish_cdn.py") + "\" " + command + " --config \"" + Config + "\"",
|
||||
WorkingDirectory = Repo, UseShellExecute = false, CreateNoWindow = true,
|
||||
RedirectStandardOutput = true, RedirectStandardError = true,
|
||||
StandardOutputEncoding = Encoding.UTF8, StandardErrorEncoding = Encoding.UTF8
|
||||
};
|
||||
start.EnvironmentVariables["PYTHONIOENCODING"] = "utf-8";
|
||||
start.EnvironmentVariables["PYTHONUNBUFFERED"] = "1";
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(LogPath));
|
||||
using (var log = new StreamWriter(LogPath, true, new UTF8Encoding(false)))
|
||||
using (var process = new Process { StartInfo = start })
|
||||
{
|
||||
log.WriteLine(DateTime.UtcNow.ToString("o") + " " + command);
|
||||
process.OutputDataReceived += (_, e) => { if (e.Data != null) pending.Enqueue(e.Data); };
|
||||
process.ErrorDataReceived += (_, e) => { if (e.Data != null) pending.Enqueue(e.Data); };
|
||||
process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine();
|
||||
while (!process.HasExited)
|
||||
{
|
||||
while (pending.TryDequeue(out var line)) { Debug.Log("[CDN] " + line); log.WriteLine(line); }
|
||||
log.Flush(); await Task.Delay(150);
|
||||
}
|
||||
process.WaitForExit();
|
||||
while (pending.TryDequeue(out var line)) { Debug.Log("[CDN] " + line); log.WriteLine(line); }
|
||||
if (process.ExitCode != 0) throw new InvalidOperationException("Publish command failed. See " + LogPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fe8f0110cd9a3084eb1da66ea0ee89c2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user