Add AIServer, character art pipeline, and Art package boot integration.
Bring in MaleExplorer assets/shaders, model tooling and Hunyuan updates, plus boot/YooAsset Art package support. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 297292b243665ee45b0e0f266b016347
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,296 @@
|
||||
#if UNITY_EDITOR
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using YooAsset.Editor;
|
||||
|
||||
/// <summary>
|
||||
/// M3:角色目录约定 Assets/Bundles/Characters/{ActorName}/ + Art 包收集。
|
||||
/// </summary>
|
||||
public static class SetupM3Character
|
||||
{
|
||||
public const string ActorName = "MaleExplorer";
|
||||
public const string ActorRoot = "Assets/Bundles/Characters/" + ActorName;
|
||||
const string FbxPath = ActorRoot + "/" + ActorName + ".fbx";
|
||||
const string BasePath = ActorRoot + "/" + ActorName + "_base.png";
|
||||
const string MixPath = ActorRoot + "/" + ActorName + "_mix.png";
|
||||
const string ColorPath = ActorRoot + "/" + ActorName + "_color.png";
|
||||
const string NormalPath = ActorRoot + "/" + ActorName + "_normal.png";
|
||||
const string AoPath = ActorRoot + "/" + ActorName + "_ao.png";
|
||||
const string MetallicPath = ActorRoot + "/" + ActorName + "_metallic.png";
|
||||
const string RoughnessPath = ActorRoot + "/" + ActorName + "_roughness.png";
|
||||
const string ConceptPath = ActorRoot + "/concept.png";
|
||||
const string MatPath = ActorRoot + "/" + ActorName + ".mat";
|
||||
const string PrefabPath = ActorRoot + "/" + ActorName + ".prefab";
|
||||
const string ArtPackage = "Art";
|
||||
const string XPbrShaderName = "Test/XPbr";
|
||||
|
||||
[MenuItem("AIGame/M3/Setup Character Prefab + Art Collector")]
|
||||
public static string SetupAll()
|
||||
{
|
||||
AssetDatabase.Refresh();
|
||||
var a = EnsureTextureImports();
|
||||
var b = EnsureMaterialAndPrefab();
|
||||
var c = EnsureArtCollector();
|
||||
CleanupLegacyLayout();
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
return $"ok textures={a} prefab={b} art={c}";
|
||||
}
|
||||
|
||||
public static string EnsureTextureImports()
|
||||
{
|
||||
var paths = new[] { BasePath, MixPath, ColorPath, NormalPath, AoPath, MetallicPath, RoughnessPath, ConceptPath };
|
||||
var ok = 0;
|
||||
foreach (var path in paths)
|
||||
{
|
||||
if (!File.Exists(path)) continue;
|
||||
var importer = AssetImporter.GetAtPath(path) as TextureImporter;
|
||||
if (importer == null) continue;
|
||||
var isMix = path == MixPath;
|
||||
var isNormal = path == NormalPath;
|
||||
var isData = path == MetallicPath || path == RoughnessPath || path == AoPath || isMix;
|
||||
importer.textureType = isNormal ? TextureImporterType.NormalMap : TextureImporterType.Default;
|
||||
importer.sRGBTexture = !isNormal && !isData;
|
||||
importer.mipmapEnabled = true;
|
||||
importer.alphaIsTransparency = path == ConceptPath || path == BasePath;
|
||||
importer.SaveAndReimport();
|
||||
ok++;
|
||||
}
|
||||
|
||||
if (File.Exists(FbxPath))
|
||||
{
|
||||
var model = AssetImporter.GetAtPath(FbxPath) as ModelImporter;
|
||||
if (model != null)
|
||||
{
|
||||
// XPbr:保留 externalObjects 材质重映射;无 .mat 时再 None
|
||||
model.materialImportMode = File.Exists(MatPath)
|
||||
? ModelImporterMaterialImportMode.ImportViaMaterialDescription
|
||||
: ModelImporterMaterialImportMode.None;
|
||||
model.meshCompression = ModelImporterMeshCompression.Medium;
|
||||
model.isReadable = false;
|
||||
model.SaveAndReimport();
|
||||
}
|
||||
}
|
||||
|
||||
return $"imported={ok} fbx={(File.Exists(FbxPath) ? "yes" : "no")}";
|
||||
}
|
||||
|
||||
public static string EnsureMaterialAndPrefab()
|
||||
{
|
||||
if (File.Exists(FbxPath) && (File.Exists(BasePath) || File.Exists(ColorPath)))
|
||||
return EnsureMeshPrefab();
|
||||
if (File.Exists(ConceptPath))
|
||||
return EnsureBillboardPrefab();
|
||||
return "missing MaleExplorer mesh/concept under " + ActorRoot;
|
||||
}
|
||||
|
||||
static string EnsureMeshPrefab()
|
||||
{
|
||||
var baseMap = AssetDatabase.LoadAssetAtPath<Texture2D>(BasePath);
|
||||
var mixMap = AssetDatabase.LoadAssetAtPath<Texture2D>(MixPath);
|
||||
var color = baseMap != null ? baseMap : AssetDatabase.LoadAssetAtPath<Texture2D>(ColorPath);
|
||||
if (color == null) return "base/color texture missing";
|
||||
|
||||
var xpbr = Shader.Find(XPbrShaderName);
|
||||
var urpLit = Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard");
|
||||
var useXpbr = xpbr != null && mixMap != null;
|
||||
var shader = useXpbr ? xpbr : urpLit;
|
||||
|
||||
var mat = AssetDatabase.LoadAssetAtPath<Material>(MatPath);
|
||||
if (mat == null)
|
||||
{
|
||||
mat = new Material(shader);
|
||||
AssetDatabase.CreateAsset(mat, MatPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
mat.shader = shader;
|
||||
}
|
||||
|
||||
if (useXpbr)
|
||||
{
|
||||
if (mat.HasProperty("_MainTex")) mat.SetTexture("_MainTex", color);
|
||||
if (mat.HasProperty("_MixTex")) mat.SetTexture("_MixTex", mixMap);
|
||||
if (mat.HasProperty("_BaseColor")) mat.SetColor("_BaseColor", Color.white);
|
||||
if (mat.HasProperty("_Metallic")) mat.SetFloat("_Metallic", 1f);
|
||||
if (mat.HasProperty("_Roughness")) mat.SetFloat("_Roughness", 1f);
|
||||
if (mat.HasProperty("_AO")) mat.SetFloat("_AO", 1f);
|
||||
if (mat.HasProperty("_AlphaTest")) mat.SetFloat("_AlphaTest", 0f);
|
||||
mat.DisableKeyword("_ALPHATEST_ON");
|
||||
}
|
||||
else
|
||||
{
|
||||
var normal = AssetDatabase.LoadAssetAtPath<Texture2D>(NormalPath);
|
||||
var ao = AssetDatabase.LoadAssetAtPath<Texture2D>(AoPath);
|
||||
var metallic = AssetDatabase.LoadAssetAtPath<Texture2D>(MetallicPath);
|
||||
var roughness = AssetDatabase.LoadAssetAtPath<Texture2D>(RoughnessPath);
|
||||
if (mat.HasProperty("_BaseMap")) mat.SetTexture("_BaseMap", color);
|
||||
if (mat.HasProperty("_MainTex")) mat.SetTexture("_MainTex", color);
|
||||
if (mat.HasProperty("_BumpMap") && normal != null)
|
||||
{
|
||||
mat.SetTexture("_BumpMap", normal);
|
||||
mat.EnableKeyword("_NORMALMAP");
|
||||
}
|
||||
if (mat.HasProperty("_OcclusionMap") && ao != null)
|
||||
mat.SetTexture("_OcclusionMap", ao);
|
||||
if (mat.HasProperty("_MetallicGlossMap") && metallic != null)
|
||||
{
|
||||
mat.SetTexture("_MetallicGlossMap", metallic);
|
||||
mat.EnableKeyword("_METALLICSPECGLOSSMAP");
|
||||
}
|
||||
if (mat.HasProperty("_Smoothness") && roughness != null)
|
||||
mat.SetFloat("_Smoothness", 0.45f);
|
||||
if (mat.HasProperty("_BaseColor")) mat.SetColor("_BaseColor", Color.white);
|
||||
}
|
||||
EditorUtility.SetDirty(mat);
|
||||
|
||||
var modelRoot = AssetDatabase.LoadAssetAtPath<GameObject>(FbxPath);
|
||||
if (modelRoot == null) return "fbx not loaded";
|
||||
|
||||
var instance = (GameObject)PrefabUtility.InstantiatePrefab(modelRoot);
|
||||
instance.name = ActorName;
|
||||
foreach (var renderer in instance.GetComponentsInChildren<Renderer>())
|
||||
renderer.sharedMaterial = mat;
|
||||
|
||||
// 落地参考盘
|
||||
var ground = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
|
||||
ground.name = "ShadowDisc";
|
||||
ground.transform.SetParent(instance.transform, false);
|
||||
ground.transform.localPosition = new Vector3(0f, 0.02f, 0f);
|
||||
ground.transform.localScale = new Vector3(0.7f, 0.015f, 0.7f);
|
||||
Object.DestroyImmediate(ground.GetComponent<Collider>());
|
||||
var gMat = new Material(urpLit != null ? urpLit : shader);
|
||||
if (gMat.HasProperty("_BaseColor")) gMat.SetColor("_BaseColor", new Color(0.12f, 0.12f, 0.14f, 1f));
|
||||
if (gMat.HasProperty("_Color")) gMat.color = new Color(0.12f, 0.12f, 0.14f, 1f);
|
||||
ground.GetComponent<MeshRenderer>().sharedMaterial = gMat;
|
||||
ground.GetComponent<MeshRenderer>().shadowCastingMode = ShadowCastingMode.Off;
|
||||
|
||||
// 粗略归一化身高约 1.8m
|
||||
var bounds = new Bounds(instance.transform.position, Vector3.zero);
|
||||
var renderers = instance.GetComponentsInChildren<Renderer>();
|
||||
foreach (var r in renderers)
|
||||
{
|
||||
if (r.name == "ShadowDisc") continue;
|
||||
bounds.Encapsulate(r.bounds);
|
||||
}
|
||||
if (bounds.size.y > 0.01f)
|
||||
{
|
||||
var scale = 1.8f / bounds.size.y;
|
||||
instance.transform.localScale = Vector3.one * scale;
|
||||
}
|
||||
|
||||
PrefabUtility.SaveAsPrefabAsset(instance, PrefabPath);
|
||||
Object.DestroyImmediate(instance);
|
||||
return PrefabPath;
|
||||
}
|
||||
|
||||
static string EnsureBillboardPrefab()
|
||||
{
|
||||
var tex = AssetDatabase.LoadAssetAtPath<Texture2D>(ConceptPath);
|
||||
if (tex == null) return "concept not loaded";
|
||||
|
||||
var shader = Shader.Find("Universal Render Pipeline/Unlit");
|
||||
if (shader == null) shader = Shader.Find("Unlit/Transparent");
|
||||
if (shader == null) shader = Shader.Find("Sprites/Default");
|
||||
|
||||
var mat = AssetDatabase.LoadAssetAtPath<Material>(MatPath);
|
||||
if (mat == null)
|
||||
{
|
||||
mat = new Material(shader);
|
||||
AssetDatabase.CreateAsset(mat, MatPath);
|
||||
}
|
||||
else mat.shader = shader;
|
||||
|
||||
if (mat.HasProperty("_BaseMap")) mat.SetTexture("_BaseMap", tex);
|
||||
if (mat.HasProperty("_MainTex")) mat.SetTexture("_MainTex", tex);
|
||||
if (mat.HasProperty("_BaseColor")) mat.SetColor("_BaseColor", Color.white);
|
||||
if (mat.HasProperty("_Surface")) mat.SetFloat("_Surface", 1f);
|
||||
mat.EnableKeyword("_SURFACE_TYPE_TRANSPARENT");
|
||||
mat.renderQueue = (int)RenderQueue.Transparent;
|
||||
EditorUtility.SetDirty(mat);
|
||||
|
||||
var root = new GameObject(ActorName);
|
||||
root.transform.localScale = new Vector3(1.2f, 2.0f, 1f);
|
||||
var quad = GameObject.CreatePrimitive(PrimitiveType.Quad);
|
||||
quad.name = "Billboard";
|
||||
quad.transform.SetParent(root.transform, false);
|
||||
quad.transform.localPosition = new Vector3(0f, 1.0f, 0f);
|
||||
Object.DestroyImmediate(quad.GetComponent<MeshCollider>());
|
||||
quad.GetComponent<MeshRenderer>().sharedMaterial = mat;
|
||||
PrefabUtility.SaveAsPrefabAsset(root, PrefabPath);
|
||||
Object.DestroyImmediate(root);
|
||||
return PrefabPath + " (billboard fallback)";
|
||||
}
|
||||
|
||||
static void CleanupLegacyLayout()
|
||||
{
|
||||
// 旧 M3 扁平目录,迁移后删除空壳
|
||||
var legacy = new[]
|
||||
{
|
||||
"Assets/Bundles/Characters/Prefabs/MaleExplorer.prefab",
|
||||
"Assets/Bundles/Characters/Textures/male_explorer.png",
|
||||
"Assets/Bundles/Characters/Textures/MaleExplorer_Billboard.mat",
|
||||
};
|
||||
foreach (var path in legacy)
|
||||
{
|
||||
if (File.Exists(path) || AssetDatabase.LoadMainAssetAtPath(path) != null)
|
||||
AssetDatabase.DeleteAsset(path);
|
||||
}
|
||||
}
|
||||
|
||||
public static string EnsureArtCollector()
|
||||
{
|
||||
var setting = BundleCollectorSettingData.Setting;
|
||||
setting.ShowPackageView = true;
|
||||
|
||||
var package = setting.Packages.Find(p => p.PackageName == ArtPackage);
|
||||
if (package == null)
|
||||
package = BundleCollectorSettingData.CreatePackage(ArtPackage);
|
||||
|
||||
package.PackageDesc = "角色/场景美术";
|
||||
package.EnableAddressable = true;
|
||||
package.SupportExtensionless = true;
|
||||
package.AutoCollectShaders = true;
|
||||
package.IgnoreRuleName = nameof(NormalIgnoreRule);
|
||||
BundleCollectorSettingData.ModifyPackage(package);
|
||||
|
||||
var group = package.Groups.Find(g => g.GroupName == "Characters");
|
||||
if (group == null)
|
||||
group = BundleCollectorSettingData.CreateGroup(package, "Characters");
|
||||
group.ActiveRuleName = nameof(EnableGroup);
|
||||
group.AssetTags = "art";
|
||||
BundleCollectorSettingData.ModifyGroup(package, group);
|
||||
|
||||
const string collectPath = "Assets/Bundles/Characters";
|
||||
var collector = group.Collectors.Find(c => c.CollectPath == collectPath);
|
||||
if (collector == null)
|
||||
{
|
||||
collector = new BundleCollector
|
||||
{
|
||||
CollectPath = collectPath,
|
||||
CollectorGUID = AssetDatabase.AssetPathToGUID(collectPath),
|
||||
CollectorType = ECollectorType.MainAssetCollector,
|
||||
AddressRuleName = nameof(AddressByFileName),
|
||||
PackRuleName = nameof(PackDirectory),
|
||||
FilterRuleName = nameof(CollectAll),
|
||||
AssetTags = "art",
|
||||
};
|
||||
BundleCollectorSettingData.CreateCollector(group, collector);
|
||||
}
|
||||
else
|
||||
{
|
||||
collector.CollectorGUID = AssetDatabase.AssetPathToGUID(collectPath);
|
||||
collector.AddressRuleName = nameof(AddressByFileName);
|
||||
collector.PackRuleName = nameof(PackDirectory);
|
||||
collector.FilterRuleName = nameof(CollectAll);
|
||||
BundleCollectorSettingData.ModifyCollector(group, collector);
|
||||
}
|
||||
|
||||
package.CheckConfigError();
|
||||
BundleCollectorSettingData.SaveFile();
|
||||
return $"package={ArtPackage} collect={collectPath} pack=PackDirectory";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 15d1983461c3f204ca40fed18bc55a6f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,122 @@
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using YooAsset;
|
||||
using YooAsset.Editor;
|
||||
|
||||
namespace AOT.Editor.YooAssetTools
|
||||
{
|
||||
/// <summary>
|
||||
/// 构建 Art 包(角色等)并暂存 CDN / StreamingAssets。
|
||||
/// </summary>
|
||||
public static class BuildAndStageArt
|
||||
{
|
||||
public const string PackageName = "Art";
|
||||
public const string AppVersion = "1.0.0";
|
||||
public const string Channel = "wechat";
|
||||
|
||||
static string RepoRoot => Path.GetFullPath(Path.Combine(Application.dataPath, "..", ".."));
|
||||
static string CdnRoot => Path.Combine(RepoRoot, "Tools", "cdn_root");
|
||||
static string ProjectBundlesRoot => BundleBuilderHelper.GetDefaultBuildOutputRoot();
|
||||
|
||||
[MenuItem("AIGame/YooAsset/Build And Stage Art")]
|
||||
public static string BuildAndStage()
|
||||
{
|
||||
SetupM3Character.SetupAll();
|
||||
|
||||
var target = EditorUserBuildSettings.activeBuildTarget;
|
||||
string packageVersion = DateTime.Now.ToString("yyyyMMdd.HHmmss");
|
||||
var buildResult = BuildArtPackage(target, packageVersion);
|
||||
if (!buildResult.Success)
|
||||
return $"fail: {buildResult.ErrorInfo}";
|
||||
|
||||
string packageDir = buildResult.OutputPackageDirectory;
|
||||
string stageDir = Path.Combine(CdnRoot, Channel, AppVersion, PackageName);
|
||||
StageDirectory(packageDir, stageDir);
|
||||
|
||||
// 合并 version.json packages 列表
|
||||
MergeVersionPackages(packageVersion);
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
return $"ok ver={packageVersion} dir={packageDir} stage={stageDir}";
|
||||
}
|
||||
|
||||
static BuildResult BuildArtPackage(BuildTarget target, string packageVersion)
|
||||
{
|
||||
var uniqueBundleName = BundleCollectorSettingData.Setting.UniqueBundleName;
|
||||
var packRuleResult = DefaultBundlePackRule.CreateShadersPackRuleResult();
|
||||
var builtinShaderBundleName = packRuleResult.GetBundleName(PackageName, uniqueBundleName);
|
||||
|
||||
var buildParameters = new ScriptableBuildParameters
|
||||
{
|
||||
BuildOutputRoot = ProjectBundlesRoot,
|
||||
BundledFileRoot = BundleBuilderHelper.GetStreamingAssetsRoot(),
|
||||
BuildPipeline = EBuildPipeline.ScriptableBuildPipeline.ToString(),
|
||||
BuildBundleType = (int)EBundleType.AssetBundle,
|
||||
BuildTarget = target,
|
||||
PackageName = PackageName,
|
||||
PackageVersion = packageVersion,
|
||||
EnableSharePackRule = true,
|
||||
VerifyBuildingResult = true,
|
||||
FileNameStyle = EFileNameStyle.HashName,
|
||||
BundledCopyOption = EBundledCopyOption.ClearAndCopyAll,
|
||||
BundledCopyParams = string.Empty,
|
||||
CompressOption = ECompressOption.LZ4,
|
||||
ClearBuildCacheFiles = false,
|
||||
UseAssetDependencyDB = true,
|
||||
BuiltinShadersBundleName = builtinShaderBundleName,
|
||||
};
|
||||
|
||||
var pipeline = new ScriptableBuildPipeline();
|
||||
return pipeline.Run(buildParameters, true);
|
||||
}
|
||||
|
||||
static void StageDirectory(string src, string dst)
|
||||
{
|
||||
if (Directory.Exists(dst))
|
||||
Directory.Delete(dst, true);
|
||||
Directory.CreateDirectory(dst);
|
||||
foreach (var file in Directory.GetFiles(src, "*", SearchOption.AllDirectories))
|
||||
{
|
||||
var rel = file.Substring(src.Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
||||
var destFile = Path.Combine(dst, rel);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(destFile) ?? dst);
|
||||
File.Copy(file, destFile, true);
|
||||
}
|
||||
}
|
||||
|
||||
static void MergeVersionPackages(string resVersion)
|
||||
{
|
||||
var path = Path.Combine(CdnRoot, Channel, "version.json");
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(path) ?? CdnRoot);
|
||||
var localCdn = $"http://127.0.0.1:8787/{Channel}/{AppVersion}/{BuildAndStageHotUpdate.PackageName}";
|
||||
var json =
|
||||
"{\n" +
|
||||
$" \"appVersionMin\": \"{AppVersion}\",\n" +
|
||||
$" \"appVersionMax\": \"{AppVersion}\",\n" +
|
||||
$" \"resVersion\": \"{resVersion}\",\n" +
|
||||
$" \"cdnRoot\": \"{localCdn}\",\n" +
|
||||
" \"packages\": [ \"DefaultPackage\", \"Art\" ],\n" +
|
||||
" \"forceUpdate\": false,\n" +
|
||||
" \"notice\": \"\"\n" +
|
||||
"}\n";
|
||||
File.WriteAllText(path, json);
|
||||
File.WriteAllText(Path.Combine(Application.streamingAssetsPath, "cdn", "version.json"), json);
|
||||
|
||||
var prod =
|
||||
"{\n" +
|
||||
$" \"appVersionMin\": \"{AppVersion}\",\n" +
|
||||
$" \"appVersionMax\": \"{AppVersion}\",\n" +
|
||||
$" \"resVersion\": \"{resVersion}\",\n" +
|
||||
$" \"cdnRoot\": \"https://www.xworld.ren/{Channel}/{AppVersion}/{BuildAndStageHotUpdate.PackageName}\",\n" +
|
||||
" \"packages\": [ \"DefaultPackage\", \"Art\" ],\n" +
|
||||
" \"forceUpdate\": false,\n" +
|
||||
" \"notice\": \"\"\n" +
|
||||
"}\n";
|
||||
File.WriteAllText(Path.Combine(CdnRoot, Channel, "version.prod.json"), prod);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: db0c7c0cdfa612f47bea89cc1bd02a6e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -3,13 +3,12 @@ using AOT.Boot;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using YooAsset;
|
||||
|
||||
namespace AOT.Editor.YooAssetTools
|
||||
{
|
||||
/// <summary>
|
||||
/// 切换 BootDriver 的 M1 验证模式(Offline / Host / Direct)。
|
||||
/// 切换 BootDriver 的运行模式 / 服务器地址。
|
||||
/// </summary>
|
||||
public static class ConfigureBootPlayMode
|
||||
{
|
||||
@@ -30,6 +29,33 @@ namespace AOT.Editor.YooAssetTools
|
||||
versionUrl: "http://127.0.0.1:8787/wechat/version.json",
|
||||
defaultCdn: "http://127.0.0.1:8787/wechat/1.0.0/DefaultPackage");
|
||||
|
||||
[MenuItem("AIGame/Boot/Server/Production game.xworld.ren")]
|
||||
public static string SetServerProd() => ApplyServer(
|
||||
"https://game.xworld.ren",
|
||||
"wss://game.xworld.ren/ws?pid={pid}&token={token}");
|
||||
|
||||
[MenuItem("AIGame/Boot/Server/Local AIServer :8080")]
|
||||
public static string SetServerLocal() => ApplyServer(
|
||||
"http://127.0.0.1:8080",
|
||||
"ws://127.0.0.1:8080/ws?pid={pid}&token={token}");
|
||||
|
||||
static string ApplyServer(string httpBase, string wsTemplate)
|
||||
{
|
||||
var scene = EditorSceneManager.OpenScene(BootScene, OpenSceneMode.Single);
|
||||
var boot = Object.FindObjectOfType<BootDriver>();
|
||||
if (boot == null)
|
||||
return "fail: BootDriver not found in Boot scene";
|
||||
|
||||
var so = new SerializedObject(boot);
|
||||
var settings = so.FindProperty("settings");
|
||||
settings.FindPropertyRelative("HttpBase").stringValue = httpBase;
|
||||
settings.FindPropertyRelative("WsUrlTemplate").stringValue = wsTemplate;
|
||||
so.ApplyModifiedPropertiesWithoutUndo();
|
||||
EditorSceneManager.MarkSceneDirty(scene);
|
||||
EditorSceneManager.SaveScene(scene);
|
||||
return $"ok http={httpBase} ws={wsTemplate}";
|
||||
}
|
||||
|
||||
static string Apply(EPlayMode playMode, bool editorDirect, string versionUrl = null, string defaultCdn = null)
|
||||
{
|
||||
var scene = EditorSceneManager.OpenScene(BootScene, OpenSceneMode.Single);
|
||||
|
||||
Reference in New Issue
Block a user