- UI SFX v3: procedurally synthesized one-shots (Tools/synth_ui_sfx.py) wired to buttons, rewards, errors and red dots via UiSfx, gated by the SFX setting. - Five formal enemies (Hornlet, Dashlet, Shellhorn, HornCaptain, GreatHorn): Hunyuan 50k -> 2000-tri XPbr, DGXA TokenRig, Idle/Walk/Attack, nested per type in PrototypeArena; PrototypeBattle.Enemy gains presentation-only Moving/Strikes. - Formal partners for all ten pets in the arena and portraits, including new VineSprite, ThunderLeopard and TideWhale. - Pipeline fixes: reject local TokenRig fallback, drop loose mesh islands, configurable Unity run_script timeout, companion static stage. - Also includes concurrent work from another tool in this working tree (FlameLion, enemy combat FX, challenge mode, home explorer, server updates). - Resources registered in Doc/ResDesc_*.md; verified on isolated :18081. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
75 lines
3.8 KiB
C#
75 lines
3.8 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using HotUpdate.Gameplay;
|
|
using Newtonsoft.Json;
|
|
using UnityEditor;
|
|
using UnityEditor.SceneManagement;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
|
|
/// <summary>Pipeline authoring of the UiSfx prefab: one AudioSource plus the v3 synthesized UI clips in UiSound order.</summary>
|
|
public static class BuildUiSfx
|
|
{
|
|
public const string PrefabPath = "Assets/Bundles/Sound/Prefab/UiSfx.prefab";
|
|
const string ClipFolder = "Assets/Bundles/Sound/SFX/UI/";
|
|
|
|
public static string Build()
|
|
{
|
|
if (EditorApplication.isPlaying) throw new Exception("Build UI SFX in Edit Mode");
|
|
var names = Enum.GetNames(typeof(UiSound));
|
|
var clips = names.Select(n =>
|
|
{
|
|
string path = ClipFolder + "Ui_" + n + ".wav";
|
|
AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
|
|
return AssetDatabase.LoadAssetAtPath<AudioClip>(path) ?? throw new Exception("Missing " + path);
|
|
}).ToArray();
|
|
var longest = clips.OrderByDescending(c => c.length).First();
|
|
if (longest.length > 1f) throw new Exception(longest.name + " is still " + longest.length + "s; import the one-shots first");
|
|
|
|
var original = SceneManager.GetActiveScene();
|
|
var temporary = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Additive);
|
|
try
|
|
{
|
|
SceneManager.SetActiveScene(temporary);
|
|
var root = new GameObject(UiSfx.PrefabName);
|
|
var source = root.AddComponent<AudioSource>();
|
|
source.playOnAwake = false; source.loop = false; source.spatialBlend = 0; source.volume = .8f;
|
|
var player = root.AddComponent<UiSfx>();
|
|
var serialized = new SerializedObject(player);
|
|
serialized.FindProperty("_source").objectReferenceValue = source;
|
|
var list = serialized.FindProperty("_clips"); list.arraySize = clips.Length;
|
|
for (int i = 0; i < clips.Length; i++) list.GetArrayElementAtIndex(i).objectReferenceValue = clips[i];
|
|
serialized.ApplyModifiedPropertiesWithoutUndo();
|
|
PrefabUtility.SaveAsPrefabAsset(root, PrefabPath);
|
|
}
|
|
finally
|
|
{
|
|
SceneManager.SetActiveScene(original);
|
|
EditorSceneManager.CloseScene(temporary, true);
|
|
}
|
|
return Verify();
|
|
}
|
|
|
|
public static string Verify()
|
|
{
|
|
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(PrefabPath) ?? throw new Exception("Missing " + PrefabPath);
|
|
var player = prefab.GetComponent<UiSfx>(); var audio = prefab.GetComponent<AudioSource>();
|
|
if (player == null || player.Source != audio || audio.playOnAwake || audio.loop || audio.spatialBlend != 0) throw new Exception("UiSfx prefab configuration invalid");
|
|
var rows = Enum.GetValues(typeof(UiSound)).Cast<UiSound>().Select(s =>
|
|
{
|
|
var clip = player.Clip(s);
|
|
if (clip == null || clip.name != "Ui_" + s || clip.length > 1f || clip.frequency != 44100) throw new Exception("Bad clip for " + s + ": " + clip?.name);
|
|
return new { sound = s.ToString(), clip = AssetDatabase.GetAssetPath(clip), seconds = Math.Round(clip.length, 3), clip.channels, clip.frequency };
|
|
}).ToArray();
|
|
string report = JsonConvert.SerializeObject(new
|
|
{
|
|
batch = "ui_sfx_v3", prefab = PrefabPath, address = UiSfx.PrefabName, package = "Art", group = "Sound",
|
|
volume = audio.volume, sfxToggle = "PrototypeClientPrefs.Sfx", clips = rows, bundleBuilt = false, verifiedUtc = DateTime.UtcNow.ToString("o")
|
|
}, Formatting.Indented);
|
|
string repo = Directory.GetParent(Application.dataPath).Parent.FullName;
|
|
File.WriteAllText(Path.Combine(repo, "Doc/Design/Sound/UiSfx/playback_assets.json"), report);
|
|
return report;
|
|
}
|
|
}
|