策划项目提交
This commit is contained in:
parent
02a81ee658
commit
45eee6799d
Binary file not shown.
118
Scripts/DR_Generated/DRAmbientData.cs
Normal file
118
Scripts/DR_Generated/DRAmbientData.cs
Normal file
@ -0,0 +1,118 @@
|
||||
// 此文件由 ThriftIntegratedPipeline 自动生成,请勿手动修改
|
||||
// 配置类: AmbientData
|
||||
// 数据类: AmbientDataItem
|
||||
|
||||
using UnityEngine;
|
||||
using Byway.Config;
|
||||
using Byway.Thrift.Data;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace CrazyMaple
|
||||
{
|
||||
/// <summary>
|
||||
/// AmbientData 数据行
|
||||
/// </summary>
|
||||
public class DRAmbientData : DataRowBase
|
||||
{
|
||||
private AmbientDataItem _configData;
|
||||
|
||||
/// <summary>
|
||||
/// 唯一标识
|
||||
/// </summary>
|
||||
public override int Id
|
||||
{
|
||||
get
|
||||
{
|
||||
return _configData?.Id ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// AreaId
|
||||
/// </summary>
|
||||
public int AreaId
|
||||
{
|
||||
get
|
||||
{
|
||||
return _configData?.AreaId ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SoundId
|
||||
/// </summary>
|
||||
public int SoundId
|
||||
{
|
||||
get
|
||||
{
|
||||
return _configData?.SoundId ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从配置加载数据(优先使用传入的配置实例)
|
||||
/// </summary>
|
||||
public void LoadFromConfig(int id, AmbientData config = null)
|
||||
{
|
||||
if (config == null)
|
||||
{
|
||||
config = ConfigManager.Instance.GetConfig<AmbientData>();
|
||||
}
|
||||
|
||||
if (config?.Ambientdatas != null)
|
||||
{
|
||||
config.Ambientdatas.TryGetValue(id, out _configData);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 直接设置配置数据(性能优化:跳过字典查询)
|
||||
/// </summary>
|
||||
public void SetConfigData(AmbientDataItem configData)
|
||||
{
|
||||
_configData = configData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析数据行(优化:使用 userData 传入的配置实例,避免重复调用 GetConfig)
|
||||
/// </summary>
|
||||
public override bool ParseDataRow(string dataRowString, object userData)
|
||||
{
|
||||
int id = 0;
|
||||
if (!int.TryParse(dataRowString, out id))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 性能优化:尝试从 userData 获取配置字典,直接获取 Item
|
||||
if (userData is System.Collections.Generic.Dictionary<string, object> userDataDict)
|
||||
{
|
||||
// 优先尝试从缓存的字典直接获取 Item(最快)
|
||||
if (userDataDict.TryGetValue("ConfigDict", out object dictObj))
|
||||
{
|
||||
var dict = dictObj as System.Collections.Generic.Dictionary<int, AmbientDataItem>;
|
||||
if (dict != null && dict.TryGetValue(id, out var item))
|
||||
{
|
||||
_configData = item;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 备选方案:从配置实例获取
|
||||
if (userDataDict.TryGetValue("ConfigInstance", out object configObj))
|
||||
{
|
||||
var config = configObj as AmbientData;
|
||||
if (config != null)
|
||||
{
|
||||
LoadFromConfig(id, config);
|
||||
return _configData != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 兜底方案:直接查询(最慢)
|
||||
LoadFromConfig(id);
|
||||
return _configData != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Scripts/DR_Generated/DRAmbientData.cs.meta
Normal file
11
Scripts/DR_Generated/DRAmbientData.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 360a87d4662eb9a4793183cb7b7a198c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
515
Scripts/Editor/Design_Tools/BaseDesignToolEditor.cs
Normal file
515
Scripts/Editor/Design_Tools/BaseDesignToolEditor.cs
Normal file
@ -0,0 +1,515 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Debug = UnityEngine.Debug;
|
||||
|
||||
namespace DesignTools
|
||||
{
|
||||
/// <summary>
|
||||
/// 策划工具编辑器基类
|
||||
/// 提供通用的Docs路径管理、Git操作、UI框架等功能
|
||||
/// </summary>
|
||||
public abstract class BaseDesignToolEditor : EditorWindow
|
||||
{
|
||||
#region 常量定义
|
||||
|
||||
/// <summary>
|
||||
/// Design_SubModule相对路径
|
||||
/// </summary>
|
||||
protected const string DESIGN_SUBMODULE_PATH = "Assets/Design_SubModule";
|
||||
|
||||
#endregion
|
||||
|
||||
#region 字段定义
|
||||
|
||||
/// <summary>
|
||||
/// Docs项目根目录路径
|
||||
/// </summary>
|
||||
protected string docsRootPath = "";
|
||||
|
||||
/// <summary>
|
||||
/// 数据是否已加载
|
||||
/// </summary>
|
||||
protected bool isDataLoaded = false;
|
||||
|
||||
/// <summary>
|
||||
/// 滚动位置
|
||||
/// </summary>
|
||||
protected Vector2 scrollPosition;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 抽象方法和虚方法
|
||||
|
||||
/// <summary>
|
||||
/// 获取EditorPrefs保存路径的Key
|
||||
/// 子类需要返回唯一的Key,例如: "ItemConfigEditor_DocsPath"
|
||||
/// </summary>
|
||||
protected abstract string GetDocsPathPrefKey();
|
||||
|
||||
/// <summary>
|
||||
/// 获取工具窗口标题
|
||||
/// </summary>
|
||||
protected abstract string GetWindowTitle();
|
||||
|
||||
/// <summary>
|
||||
/// 加载具体的配置数据
|
||||
/// 在Git检查和更新完成后调用
|
||||
/// </summary>
|
||||
protected abstract void LoadConfigData();
|
||||
|
||||
/// <summary>
|
||||
/// 绘制数据编辑器UI
|
||||
/// 在数据加载完成后调用
|
||||
/// </summary>
|
||||
protected abstract void DrawDataEditor();
|
||||
|
||||
/// <summary>
|
||||
/// 获取工具窗口的最小尺寸
|
||||
/// 默认为 (1000, 600)
|
||||
/// </summary>
|
||||
protected virtual Vector2 GetMinWindowSize()
|
||||
{
|
||||
return new Vector2(1000, 600);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否需要检查Design_SubModule分支
|
||||
/// 默认为true,子类可以覆盖
|
||||
/// </summary>
|
||||
protected virtual bool NeedCheckDesignSubModuleBranch()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取Docs配置路径相对于Docs根目录的路径
|
||||
/// 默认为 "config",子类可以覆盖
|
||||
/// </summary>
|
||||
protected virtual string GetDocsConfigPath()
|
||||
{
|
||||
return "config";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示底部操作按钮(保存、重新加载等)
|
||||
/// 默认为true
|
||||
/// </summary>
|
||||
protected virtual bool ShowBottomButtons()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存数据到Excel
|
||||
/// 子类可以覆盖此方法实现具体的保存逻辑
|
||||
/// </summary>
|
||||
protected virtual void SaveDataToExcel()
|
||||
{
|
||||
EditorUtility.DisplayDialog("提示", "此工具未实现保存功能", "确定");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity生命周期
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
// 读取上次保存的路径
|
||||
string prefKey = GetDocsPathPrefKey();
|
||||
if (EditorPrefs.HasKey(prefKey))
|
||||
{
|
||||
docsRootPath = EditorPrefs.GetString(prefKey);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnGUI()
|
||||
{
|
||||
// 绘制工具栏
|
||||
DrawToolbar();
|
||||
|
||||
EditorGUILayout.Space(5);
|
||||
|
||||
// 绘制Docs路径选择区域
|
||||
DrawDocsPathSelector();
|
||||
|
||||
EditorGUILayout.Space(5);
|
||||
|
||||
// 绘制数据编辑区域或提示信息
|
||||
if (isDataLoaded)
|
||||
{
|
||||
DrawDataEditor();
|
||||
|
||||
// 绘制底部操作按钮
|
||||
if (ShowBottomButtons())
|
||||
{
|
||||
DrawBottomButtons();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.HelpBox("请先选择Docs根目录并加载配置数据", MessageType.Info);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI绘制方法
|
||||
|
||||
/// <summary>
|
||||
/// 绘制工具栏
|
||||
/// </summary>
|
||||
protected virtual void DrawToolbar()
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
|
||||
EditorGUILayout.LabelField(GetWindowTitle(), EditorStyles.boldLabel);
|
||||
GUILayout.FlexibleSpace();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绘制Docs路径选择区域
|
||||
/// </summary>
|
||||
protected virtual void DrawDocsPathSelector()
|
||||
{
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
EditorGUILayout.LabelField("Docs项目根目录", EditorStyles.boldLabel);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
docsRootPath = EditorGUILayout.TextField("路径", docsRootPath);
|
||||
if (GUILayout.Button("选择文件夹", GUILayout.Width(100)))
|
||||
{
|
||||
SelectDocsPath();
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (GUILayout.Button("加载配置数据", GUILayout.Height(30)))
|
||||
{
|
||||
LoadData();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绘制底部操作按钮
|
||||
/// </summary>
|
||||
protected virtual void DrawBottomButtons()
|
||||
{
|
||||
EditorGUILayout.Space(5);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
if (GUILayout.Button("保存到Excel", GUILayout.Height(30), GUILayout.Width(150)))
|
||||
{
|
||||
SaveDataToExcel();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("重新加载", GUILayout.Height(30), GUILayout.Width(150)))
|
||||
{
|
||||
LoadData();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 路径选择和数据加载
|
||||
|
||||
/// <summary>
|
||||
/// 选择Docs路径
|
||||
/// </summary>
|
||||
protected virtual void SelectDocsPath()
|
||||
{
|
||||
string selectedPath = EditorUtility.OpenFolderPanel("选择Docs项目根目录", "", "");
|
||||
if (!string.IsNullOrEmpty(selectedPath))
|
||||
{
|
||||
docsRootPath = selectedPath;
|
||||
EditorPrefs.SetString(GetDocsPathPrefKey(), docsRootPath);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载数据(最终方法,不可覆盖)
|
||||
/// </summary>
|
||||
protected void LoadData()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 1. 校验路径
|
||||
if (!ValidateDocsPath())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 检查Docs是否为Git仓库并更新
|
||||
if (!CheckAndUpdateDocsRepository())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 检查Design_SubModule分支(如果需要)
|
||||
if (NeedCheckDesignSubModuleBranch())
|
||||
{
|
||||
if (!CheckAndSwitchDesignSubModuleBranch())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 调用子类的具体加载逻辑
|
||||
LoadConfigData();
|
||||
|
||||
// 5. 设置数据加载完成标志
|
||||
isDataLoaded = true;
|
||||
|
||||
// 6. 显示成功提示
|
||||
EditorUtility.DisplayDialog("成功", "配置数据加载成功!", "确定");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
EditorUtility.DisplayDialog("错误", $"加载数据失败: {e.Message}\n{e.StackTrace}", "确定");
|
||||
isDataLoaded = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 校验Docs路径
|
||||
/// </summary>
|
||||
protected virtual bool ValidateDocsPath()
|
||||
{
|
||||
if (string.IsNullOrEmpty(docsRootPath) || !Directory.Exists(docsRootPath))
|
||||
{
|
||||
EditorUtility.DisplayDialog("错误", "请选择有效的Docs根目录", "确定");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Git操作方法
|
||||
|
||||
/// <summary>
|
||||
/// 执行Git命令
|
||||
/// </summary>
|
||||
/// <param name="workingDirectory">工作目录</param>
|
||||
/// <param name="arguments">Git命令参数</param>
|
||||
/// <param name="success">是否执行成功</param>
|
||||
/// <returns>命令输出或错误信息</returns>
|
||||
protected string ExecuteGitCommand(string workingDirectory, string arguments, out bool success)
|
||||
{
|
||||
try
|
||||
{
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = "git",
|
||||
Arguments = arguments,
|
||||
WorkingDirectory = workingDirectory,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
using (Process process = Process.Start(startInfo))
|
||||
{
|
||||
string output = process.StandardOutput.ReadToEnd();
|
||||
string error = process.StandardError.ReadToEnd();
|
||||
process.WaitForExit();
|
||||
|
||||
success = process.ExitCode == 0;
|
||||
return success ? output : error;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
success = false;
|
||||
return $"执行Git命令失败: {e.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查并更新Docs仓库
|
||||
/// </summary>
|
||||
protected virtual bool CheckAndUpdateDocsRepository()
|
||||
{
|
||||
// 1. 检查是否为Git仓库
|
||||
string gitPath = Path.Combine(docsRootPath, ".git");
|
||||
if (!Directory.Exists(gitPath))
|
||||
{
|
||||
EditorUtility.DisplayDialog("错误",
|
||||
$"Docs目录不是Git仓库\n路径: {docsRootPath}\n\n请确保Docs项目已正确克隆",
|
||||
"确定");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 执行Git Fetch
|
||||
EditorUtility.DisplayProgressBar("检查更新", "正在检查Docs仓库远程更新...", 0.3f);
|
||||
|
||||
string fetchResult = ExecuteGitCommand(docsRootPath, "fetch", out bool fetchSuccess);
|
||||
|
||||
if (!fetchSuccess)
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
EditorUtility.DisplayDialog("Git Fetch失败",
|
||||
$"无法检查远程更新:\n{fetchResult}\n\n请在SourceTree或GitHubDesktop中检查网络连接和仓库状态",
|
||||
"确定");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3. 检查仓库状态
|
||||
EditorUtility.DisplayProgressBar("检查更新", "正在检查是否有新提交...", 0.6f);
|
||||
|
||||
string statusResult = ExecuteGitCommand(docsRootPath, "status -uno", out bool statusSuccess);
|
||||
|
||||
if (!statusSuccess)
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
EditorUtility.DisplayDialog("Git Status失败",
|
||||
$"无法获取仓库状态:\n{statusResult}\n\n请在SourceTree或GitHubDesktop中检查仓库状态",
|
||||
"确定");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4. 检查是否有未提交的更改
|
||||
if (statusResult.Contains("Changes not staged") || statusResult.Contains("Changes to be committed"))
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
bool proceed = EditorUtility.DisplayDialog("警告:有未提交的更改",
|
||||
"Docs仓库中有未提交的更改,这可能导致拉取时产生冲突。\n\n建议先提交或暂存这些更改。\n\n是否继续加载配置?(不推荐)",
|
||||
"继续(不推荐)", "取消,前往处理");
|
||||
|
||||
if (!proceed)
|
||||
{
|
||||
Debug.Log("请在SourceTree或GitHubDesktop中处理未提交的更改");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 如果远程有更新,则执行Pull
|
||||
if (statusResult.Contains("Your branch is behind"))
|
||||
{
|
||||
EditorUtility.DisplayProgressBar("更新中", "正在从远程拉取最新代码...", 0.8f);
|
||||
|
||||
string pullResult = ExecuteGitCommand(docsRootPath, "pull", out bool pullSuccess);
|
||||
|
||||
EditorUtility.ClearProgressBar();
|
||||
|
||||
if (!pullSuccess)
|
||||
{
|
||||
if (pullResult.Contains("CONFLICT") || pullResult.Contains("conflict"))
|
||||
{
|
||||
EditorUtility.DisplayDialog("拉取失败:存在冲突",
|
||||
$"拉取远程更新时发生冲突:\n{pullResult}\n\n请在SourceTree或GitHubDesktop中解决冲突后再操作",
|
||||
"确定");
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorUtility.DisplayDialog("拉取失败",
|
||||
$"无法拉取远程更新:\n{pullResult}\n\n请在SourceTree或GitHubDesktop中检查并解决问题",
|
||||
"确定");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Debug.Log($"Docs仓库已更新到最新版本:\n{pullResult}");
|
||||
EditorUtility.DisplayDialog("更新成功", "Docs仓库已更新到最新版本", "确定");
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
Debug.Log("Docs仓库已是最新版本");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查并切换Design_SubModule到main分支
|
||||
/// </summary>
|
||||
protected virtual bool CheckAndSwitchDesignSubModuleBranch()
|
||||
{
|
||||
string designSubModulePath = Path.Combine(Application.dataPath, "..", DESIGN_SUBMODULE_PATH);
|
||||
designSubModulePath = Path.GetFullPath(designSubModulePath);
|
||||
|
||||
if (!Directory.Exists(designSubModulePath))
|
||||
{
|
||||
EditorUtility.DisplayDialog("错误",
|
||||
$"Design_SubModule目录不存在:\n{designSubModulePath}\n\n请确保子模块已正确初始化",
|
||||
"确定");
|
||||
return false;
|
||||
}
|
||||
|
||||
EditorUtility.DisplayProgressBar("检查分支", "正在检查Design_SubModule分支...", 0.5f);
|
||||
|
||||
string branchResult = ExecuteGitCommand(designSubModulePath, "branch --show-current", out bool branchSuccess);
|
||||
|
||||
if (!branchSuccess)
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
EditorUtility.DisplayDialog("Git Branch失败",
|
||||
$"无法获取当前分支:\n{branchResult}\n\n请在SourceTree或GitHubDesktop中检查Design_SubModule状态",
|
||||
"确定");
|
||||
return false;
|
||||
}
|
||||
|
||||
string currentBranch = branchResult.Trim();
|
||||
|
||||
if (currentBranch != "main")
|
||||
{
|
||||
EditorUtility.DisplayProgressBar("切换分支", "正在切换到main分支...", 0.8f);
|
||||
|
||||
string checkoutResult = ExecuteGitCommand(designSubModulePath, "checkout main", out bool checkoutSuccess);
|
||||
|
||||
EditorUtility.ClearProgressBar();
|
||||
|
||||
if (!checkoutSuccess)
|
||||
{
|
||||
EditorUtility.DisplayDialog("切换分支失败",
|
||||
$"无法切换到main分支:\n{checkoutResult}\n\n当前分支: {currentBranch}\n\n请在SourceTree或GitHubDesktop中手动切换到main分支",
|
||||
"确定");
|
||||
return false;
|
||||
}
|
||||
|
||||
Debug.Log($"Design_SubModule已从 {currentBranch} 切换到 main 分支");
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
Debug.Log("Design_SubModule已在main分支");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 工具方法
|
||||
|
||||
/// <summary>
|
||||
/// 获取Docs配置文件的完整路径
|
||||
/// </summary>
|
||||
/// <param name="fileName">文件名(包含扩展名)</param>
|
||||
/// <returns>完整路径</returns>
|
||||
protected string GetDocsConfigFilePath(string fileName)
|
||||
{
|
||||
return Path.Combine(docsRootPath, GetDocsConfigPath(), fileName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取Docs根目录下的完整路径
|
||||
/// </summary>
|
||||
/// <param name="relativePath">相对路径</param>
|
||||
/// <returns>完整路径</returns>
|
||||
protected string GetDocsFullPath(string relativePath)
|
||||
{
|
||||
return Path.Combine(docsRootPath, relativePath);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
11
Scripts/Editor/Design_Tools/BaseDesignToolEditor.cs.meta
Normal file
11
Scripts/Editor/Design_Tools/BaseDesignToolEditor.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6b0be63b60b34f34fa1652bf3126867a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
322
Scripts/Editor/Design_Tools/BaseDesignToolEditor_使用说明.md
Normal file
322
Scripts/Editor/Design_Tools/BaseDesignToolEditor_使用说明.md
Normal file
@ -0,0 +1,322 @@
|
||||
# BaseDesignToolEditor 使用说明
|
||||
|
||||
## 概述
|
||||
|
||||
`BaseDesignToolEditor` 是为策划工具统一设计的编辑器基类,封装了常见的功能,包括:
|
||||
- ✅ Docs路径的选择和保存
|
||||
- ✅ 自动检查并拉取Docs仓库的最新更新
|
||||
- ✅ 检查是否有未提交的更改(提示但不强制)
|
||||
- ✅ 自动切换Design_SubModule到main分支
|
||||
- ✅ 统一的UI框架(工具栏、路径选择、数据编辑区)
|
||||
- ✅ Git命令执行的封装
|
||||
|
||||
## 功能特点
|
||||
|
||||
### 1. 自动Git管理
|
||||
- **自动Fetch**: 检查远程仓库更新
|
||||
- **智能提醒**: 如果有未提交的更改,会提示用户但允许继续(不强制)
|
||||
- **自动Pull**: 如果远程有更新,自动拉取
|
||||
- **冲突检测**: 如果拉取时有冲突,会友好提示
|
||||
|
||||
### 2. 分支管理
|
||||
- 自动检查Design_SubModule是否在main分支
|
||||
- 如果不在main分支,自动切换
|
||||
|
||||
### 3. 路径管理
|
||||
- EditorPrefs自动保存和恢复用户上次选择的路径
|
||||
- 提供便捷的路径选择对话框
|
||||
|
||||
### 4. 统一UI
|
||||
- 工具栏显示工具名称
|
||||
- 路径选择区域
|
||||
- 加载按钮
|
||||
- 数据编辑区域
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 基本用法
|
||||
|
||||
创建一个新的Editor工具时,继承 `BaseDesignToolEditor` 并实现必需的抽象方法:
|
||||
|
||||
```csharp
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using DesignTools;
|
||||
|
||||
namespace DesignTools.YourCategory
|
||||
{
|
||||
public class YourConfigEditor : BaseDesignToolEditor
|
||||
{
|
||||
// 1. 定义MenuItem来显示窗口
|
||||
[MenuItem("策划工具/你的分类/你的工具")]
|
||||
public static void ShowWindow()
|
||||
{
|
||||
var window = GetWindow<YourConfigEditor>("你的工具");
|
||||
window.minSize = window.GetMinWindowSize(); // 可选:使用默认大小或自定义
|
||||
window.Show();
|
||||
}
|
||||
|
||||
// 2. 实现必需的抽象方法
|
||||
|
||||
/// <summary>
|
||||
/// 返回保存路径的EditorPrefs键(需要唯一)
|
||||
/// </summary>
|
||||
protected override string GetDocsPathPrefKey()
|
||||
{
|
||||
return "YourConfigEditor_DocsPath";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回窗口标题
|
||||
/// </summary>
|
||||
protected override string GetWindowTitle()
|
||||
{
|
||||
return "你的工具配置工具";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载具体的配置数据
|
||||
/// 在Git检查和更新完成后调用
|
||||
/// </summary>
|
||||
protected override void LoadConfigData()
|
||||
{
|
||||
// 使用 GetDocsConfigFilePath() 获取Excel文件路径
|
||||
string excelPath = GetDocsConfigFilePath("YourExcel.xlsx");
|
||||
|
||||
// 加载你的Excel数据
|
||||
// LoadYourExcelData(excelPath);
|
||||
|
||||
// 加载其他必要数据
|
||||
// ...
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绘制数据编辑器UI
|
||||
/// </summary>
|
||||
protected override void DrawDataEditor()
|
||||
{
|
||||
// 使用 scrollPosition 管理滚动视图
|
||||
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
|
||||
|
||||
// 绘制你的数据编辑UI
|
||||
// ...
|
||||
|
||||
EditorGUILayout.EndScrollView();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 可选的虚方法覆盖
|
||||
|
||||
#### 1. 自定义窗口尺寸
|
||||
|
||||
```csharp
|
||||
protected override Vector2 GetMinWindowSize()
|
||||
{
|
||||
return new Vector2(1200, 700); // 自定义最小窗口大小
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 禁用Design_SubModule分支检查
|
||||
|
||||
```csharp
|
||||
protected override bool NeedCheckDesignSubModuleBranch()
|
||||
{
|
||||
return false; // 如果不需要检查分支,返回false
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. 自定义Docs配置路径
|
||||
|
||||
```csharp
|
||||
protected override string GetDocsConfigPath()
|
||||
{
|
||||
return "custom/config/path"; // 默认是 "config"
|
||||
}
|
||||
```
|
||||
|
||||
#### 4. 自定义路径验证
|
||||
|
||||
```csharp
|
||||
protected override bool ValidateDocsPath()
|
||||
{
|
||||
// 先调用基类的验证
|
||||
if (!base.ValidateDocsPath())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 添加你自己的验证逻辑
|
||||
// ...
|
||||
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
## 完整示例
|
||||
|
||||
以下是一个完整的示例,展示如何使用基类创建一个简单的配置工具:
|
||||
|
||||
```csharp
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using OfficeOpenXml;
|
||||
using DesignTools;
|
||||
|
||||
namespace DesignTools.Examples
|
||||
{
|
||||
public class SimpleConfigEditor : BaseDesignToolEditor
|
||||
{
|
||||
private List<string> dataList = new List<string>();
|
||||
|
||||
[MenuItem("策划工具/示例/简单配置工具")]
|
||||
public static void ShowWindow()
|
||||
{
|
||||
var window = GetWindow<SimpleConfigEditor>("简单配置工具");
|
||||
window.minSize = window.GetMinWindowSize();
|
||||
window.Show();
|
||||
}
|
||||
|
||||
protected override string GetDocsPathPrefKey()
|
||||
{
|
||||
return "SimpleConfigEditor_DocsPath";
|
||||
}
|
||||
|
||||
protected override string GetWindowTitle()
|
||||
{
|
||||
return "简单配置工具";
|
||||
}
|
||||
|
||||
protected override void LoadConfigData()
|
||||
{
|
||||
// 清空旧数据
|
||||
dataList.Clear();
|
||||
|
||||
// 获取Excel文件路径
|
||||
string excelPath = GetDocsConfigFilePath("SimpleConfig.xlsx");
|
||||
|
||||
// 使用EPPlus加载Excel
|
||||
using (var package = new ExcelPackage(new System.IO.FileInfo(excelPath)))
|
||||
{
|
||||
var worksheet = package.Workbook.Worksheets[0];
|
||||
int rowCount = worksheet.Dimension.Rows;
|
||||
|
||||
for (int row = 2; row <= rowCount; row++)
|
||||
{
|
||||
string data = worksheet.Cells[row, 1].Text;
|
||||
if (!string.IsNullOrEmpty(data))
|
||||
{
|
||||
dataList.Add(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log($"加载了 {dataList.Count} 条数据");
|
||||
}
|
||||
|
||||
protected override void DrawDataEditor()
|
||||
{
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
EditorGUILayout.LabelField($"共有 {dataList.Count} 条数据", EditorStyles.boldLabel);
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
EditorGUILayout.Space(5);
|
||||
|
||||
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
|
||||
|
||||
foreach (var data in dataList)
|
||||
{
|
||||
EditorGUILayout.LabelField(data);
|
||||
}
|
||||
|
||||
EditorGUILayout.EndScrollView();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 基类提供的受保护字段
|
||||
|
||||
可以在子类中直接使用以下字段:
|
||||
|
||||
```csharp
|
||||
protected string docsRootPath; // Docs根目录路径
|
||||
protected bool isDataLoaded; // 数据是否已加载
|
||||
protected Vector2 scrollPosition; // 滚动位置
|
||||
```
|
||||
|
||||
## 基类提供的受保护常量
|
||||
|
||||
```csharp
|
||||
protected const string DESIGN_SUBMODULE_PATH = "Assets/Design_SubModule";
|
||||
```
|
||||
|
||||
## 基类提供的工具方法
|
||||
|
||||
### 1. 获取配置文件路径
|
||||
|
||||
```csharp
|
||||
// 获取 Docs/config/YourFile.xlsx 的完整路径
|
||||
string path = GetDocsConfigFilePath("YourFile.xlsx");
|
||||
```
|
||||
|
||||
### 2. 获取Docs下的任意路径
|
||||
|
||||
```csharp
|
||||
// 获取 Docs/custom/path/file.txt 的完整路径
|
||||
string path = GetDocsFullPath("custom/path/file.txt");
|
||||
```
|
||||
|
||||
### 3. 执行Git命令
|
||||
|
||||
```csharp
|
||||
string result = ExecuteGitCommand(
|
||||
workingDirectory: docsRootPath,
|
||||
arguments: "log -1 --oneline",
|
||||
out bool success
|
||||
);
|
||||
|
||||
if (success)
|
||||
{
|
||||
Debug.Log($"Git命令执行成功: {result}");
|
||||
}
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **唯一的PrefsKey**: 确保每个编辑器工具使用唯一的 `GetDocsPathPrefKey()` 返回值
|
||||
2. **异常处理**: 基类已经处理了 `LoadData()` 的异常,子类在 `LoadConfigData()` 中只需关注具体逻辑
|
||||
3. **进度条**: Git操作时会自动显示进度条,无需在子类中处理
|
||||
4. **EPPlus许可证**: 如果使用EPPlus,记得在子类的 `OnEnable()` 中设置许可证上下文
|
||||
|
||||
```csharp
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable(); // 调用基类的OnEnable
|
||||
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
|
||||
}
|
||||
```
|
||||
|
||||
## 迁移现有工具
|
||||
|
||||
如果要将现有的Editor工具迁移到使用基类,步骤如下:
|
||||
|
||||
1. 将类声明改为继承 `BaseDesignToolEditor`
|
||||
2. 删除重复的字段定义(如 `docsRootPath`、`isDataLoaded` 等)
|
||||
3. 删除 `ExecuteGitCommand`、`CheckAndUpdateDocsRepository` 等方法
|
||||
4. 实现必需的抽象方法
|
||||
5. 修改 `LoadData()` 逻辑,将具体加载逻辑移到 `LoadConfigData()` 中
|
||||
6. 修改 `OnGUI()`,删除路径选择和工具栏部分,只保留 `DrawDataEditor()` 的实现
|
||||
|
||||
## 未来扩展
|
||||
|
||||
基类还可以继续扩展以下功能:
|
||||
- 语言表加载的通用封装
|
||||
- Excel读取的辅助方法
|
||||
- ArtTableSO加载的通用方法
|
||||
- 数据验证的通用框架
|
||||
- 数据保存和导出的通用方法
|
||||
|
||||
如有需要,可以继续向基类添加通用功能。
|
||||
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 79679bc3bbf215040ac9e7bad1eca064
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Scripts/Editor/Design_Tools/DesignSoundEditorWindow.meta
Normal file
8
Scripts/Editor/Design_Tools/DesignSoundEditorWindow.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 948d9a14622d03a4884178645ac059ab
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,756 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using OfficeOpenXml;
|
||||
using Debug = UnityEngine.Debug;
|
||||
|
||||
namespace DesignTools
|
||||
{
|
||||
/// <summary>
|
||||
/// 环境音配置Editor工具
|
||||
/// 读取Docs/config/Sound.xlsx的Ambient Sheet和Sound Sheet,编辑环境音配置和环境音属性
|
||||
/// </summary>
|
||||
public class AmbientSoundConfigEditor : BaseDesignToolEditor
|
||||
{
|
||||
private const string SOUND_EXCEL_NAME = "Sound.xlsx";
|
||||
private const string AMBIENT_SHEET_NAME = "Ambient";
|
||||
private const string SOUND_SHEET_NAME = "Sound";
|
||||
private const string LANGUAGE_EXCEL_NAME = "AllLanguage.xlsx";
|
||||
private const string LANGUAGE_SHEET_NAME = "client";
|
||||
|
||||
// Ambient表格列索引
|
||||
private const int COL_ID = 1;
|
||||
private const int COL_AREA_ID = 2;
|
||||
private const int COL_SOUND_ID = 3;
|
||||
|
||||
// Sound表格列索引
|
||||
private const int COL_SOUND_ID_IN_SOUND = 1;
|
||||
private const int COL_COMMENT = 2;
|
||||
private const int COL_ASSET_NAME = 3;
|
||||
private const int COL_PRIORITY = 4;
|
||||
private const int COL_LOOP = 5;
|
||||
private const int COL_VOLUME = 6;
|
||||
private const int COL_SPATIAL_BLEND = 7;
|
||||
private const int COL_MAX_DISTANCE = 8;
|
||||
|
||||
// 固定的环境音ID列表
|
||||
private static readonly int[] AMBIENT_SOUND_IDS = { 10172, 10173, 10174, 10175, 10176, 10177, 10178, 10179 };
|
||||
|
||||
private List<AmbientSoundData> ambientDataList = new List<AmbientSoundData>();
|
||||
private Dictionary<int, SoundData> soundDataDict = new Dictionary<int, SoundData>(); // 环境音的Sound数据
|
||||
private Dictionary<string, Dictionary<string, string>> languageDict = new Dictionary<string, Dictionary<string, string>>();
|
||||
|
||||
// UI状态
|
||||
private Vector2 ambientScrollPosition;
|
||||
private Vector2 soundScrollPosition;
|
||||
private int selectedTab = 0; // 0=场景关联, 1=环境音编辑
|
||||
|
||||
[MenuItem("策划工具/声音/环境音配置")]
|
||||
public static void ShowWindow()
|
||||
{
|
||||
var window = GetWindow<AmbientSoundConfigEditor>("环境音配置");
|
||||
window.minSize = window.GetMinWindowSize();
|
||||
window.Show();
|
||||
}
|
||||
|
||||
#region 基类实现
|
||||
|
||||
protected override string GetDocsPathPrefKey()
|
||||
{
|
||||
return "AmbientSoundConfigEditor_DocsPath";
|
||||
}
|
||||
|
||||
protected override string GetWindowTitle()
|
||||
{
|
||||
return "环境音配置工具";
|
||||
}
|
||||
|
||||
protected override Vector2 GetMinWindowSize()
|
||||
{
|
||||
return new Vector2(1200, 700);
|
||||
}
|
||||
|
||||
protected override void LoadConfigData()
|
||||
{
|
||||
// 1. 加载语言表
|
||||
LoadLanguageData();
|
||||
|
||||
// 2. 加载Sound表中的环境音数据
|
||||
LoadSoundData();
|
||||
|
||||
// 3. 加载Ambient表
|
||||
LoadAmbientExcel();
|
||||
}
|
||||
|
||||
protected override void DrawDataEditor()
|
||||
{
|
||||
// 标签页切换
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
string[] tabNames = { "场景环境音关联", "环境音属性编辑" };
|
||||
selectedTab = GUILayout.Toolbar(selectedTab, tabNames, GUILayout.Height(30));
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.Space(5);
|
||||
|
||||
// 根据选中的标签页显示不同内容
|
||||
if (selectedTab == 0)
|
||||
{
|
||||
DrawAmbientDataTable();
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawSoundDataTable();
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool ShowBottomButtons()
|
||||
{
|
||||
return false; // 使用顶部保存按钮
|
||||
}
|
||||
|
||||
protected override void SaveDataToExcel()
|
||||
{
|
||||
SaveToExcel();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 数据加载
|
||||
|
||||
/// <summary>
|
||||
/// 加载语言表
|
||||
/// </summary>
|
||||
private void LoadLanguageData()
|
||||
{
|
||||
languageDict.Clear();
|
||||
|
||||
string languageExcelPath = GetDocsConfigFilePath(LANGUAGE_EXCEL_NAME);
|
||||
|
||||
if (!File.Exists(languageExcelPath))
|
||||
{
|
||||
Debug.LogWarning($"未找到语言表: {languageExcelPath}");
|
||||
return;
|
||||
}
|
||||
|
||||
// ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
|
||||
|
||||
using (var package = new ExcelPackage(new FileInfo(languageExcelPath)))
|
||||
{
|
||||
var worksheet = package.Workbook.Worksheets[LANGUAGE_SHEET_NAME];
|
||||
|
||||
if (worksheet == null)
|
||||
{
|
||||
Debug.LogWarning($"未找到Sheet: {LANGUAGE_SHEET_NAME}");
|
||||
return;
|
||||
}
|
||||
|
||||
int rowCount = worksheet.Dimension?.Rows ?? 0;
|
||||
if (rowCount < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 第一行是表头,找到各列的索引
|
||||
int keyColIndex = -1;
|
||||
int zhCNColIndex = -1;
|
||||
|
||||
for (int col = 1; col <= worksheet.Dimension.Columns; col++)
|
||||
{
|
||||
string header = worksheet.Cells[1, col].Text.Trim();
|
||||
if (header.Equals("key", StringComparison.OrdinalIgnoreCase) ||
|
||||
header.Equals("Key", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
keyColIndex = col;
|
||||
}
|
||||
else if (header == "zh_CN")
|
||||
{
|
||||
zhCNColIndex = col;
|
||||
}
|
||||
}
|
||||
|
||||
if (keyColIndex == -1 || zhCNColIndex == -1)
|
||||
{
|
||||
Debug.LogWarning($"语言表格式错误,未找到key或zh_CN列(已扫描 {worksheet.Dimension.Columns} 列)");
|
||||
return;
|
||||
}
|
||||
|
||||
// 从第3行开始读取数据(第1行是字段名,第2行是中文说明)
|
||||
for (int row = 3; row <= rowCount; row++)
|
||||
{
|
||||
string key = worksheet.Cells[row, keyColIndex].Text.Trim();
|
||||
string zhCN = worksheet.Cells[row, zhCNColIndex].Text.Trim();
|
||||
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
{
|
||||
if (!languageDict.ContainsKey(key))
|
||||
{
|
||||
languageDict[key] = new Dictionary<string, string>();
|
||||
}
|
||||
languageDict[key]["zh_CN"] = zhCN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log($"加载了 {languageDict.Count} 条语言数据");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载Sound表中的环境音数据
|
||||
/// </summary>
|
||||
private void LoadSoundData()
|
||||
{
|
||||
soundDataDict.Clear();
|
||||
|
||||
string excelPath = GetDocsConfigFilePath(SOUND_EXCEL_NAME);
|
||||
|
||||
if (!File.Exists(excelPath))
|
||||
{
|
||||
EditorUtility.DisplayDialog("错误",
|
||||
$"未找到Sound.xlsx\n路径: {excelPath}",
|
||||
"确定");
|
||||
return;
|
||||
}
|
||||
|
||||
// ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
|
||||
|
||||
using (var package = new ExcelPackage(new FileInfo(excelPath)))
|
||||
{
|
||||
var worksheet = package.Workbook.Worksheets[SOUND_SHEET_NAME];
|
||||
|
||||
if (worksheet == null)
|
||||
{
|
||||
EditorUtility.DisplayDialog("错误",
|
||||
$"未找到Sheet: {SOUND_SHEET_NAME}",
|
||||
"确定");
|
||||
return;
|
||||
}
|
||||
|
||||
int rowCount = worksheet.Dimension?.Rows ?? 0;
|
||||
|
||||
// 从第3行开始读取(第1行是字段名,第2行是中文说明)
|
||||
for (int row = 3; row <= rowCount; row++)
|
||||
{
|
||||
string idText = worksheet.Cells[row, COL_SOUND_ID_IN_SOUND].Text;
|
||||
if (string.IsNullOrEmpty(idText))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!int.TryParse(idText, out int soundId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 只加载固定的环境音ID
|
||||
if (!AMBIENT_SOUND_IDS.Contains(soundId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var soundData = new SoundData
|
||||
{
|
||||
Id = soundId,
|
||||
Comment = worksheet.Cells[row, COL_COMMENT].Text,
|
||||
AssetName = worksheet.Cells[row, COL_ASSET_NAME].Text,
|
||||
Priority = ParseInt(worksheet.Cells[row, COL_PRIORITY].Text, 0),
|
||||
Loop = ParseBool(worksheet.Cells[row, COL_LOOP].Text),
|
||||
Volume = ParseFloat(worksheet.Cells[row, COL_VOLUME].Text, 1f),
|
||||
SpatialBlend = ParseFloat(worksheet.Cells[row, COL_SPATIAL_BLEND].Text, 0f),
|
||||
MaxDistance = ParseFloat(worksheet.Cells[row, COL_MAX_DISTANCE].Text, 100f),
|
||||
RowIndex = row
|
||||
};
|
||||
|
||||
soundDataDict[soundId] = soundData;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log($"加载了 {soundDataDict.Count} 个环境音数据");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载Ambient.xlsx
|
||||
/// </summary>
|
||||
private void LoadAmbientExcel()
|
||||
{
|
||||
ambientDataList.Clear();
|
||||
|
||||
string excelPath = GetDocsConfigFilePath(SOUND_EXCEL_NAME);
|
||||
|
||||
if (!File.Exists(excelPath))
|
||||
{
|
||||
EditorUtility.DisplayDialog("错误",
|
||||
$"未找到Sound.xlsx\n路径: {excelPath}",
|
||||
"确定");
|
||||
return;
|
||||
}
|
||||
|
||||
// ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
|
||||
|
||||
using (var package = new ExcelPackage(new FileInfo(excelPath)))
|
||||
{
|
||||
var worksheet = package.Workbook.Worksheets[AMBIENT_SHEET_NAME];
|
||||
|
||||
if (worksheet == null)
|
||||
{
|
||||
EditorUtility.DisplayDialog("错误",
|
||||
$"未找到Sheet: {AMBIENT_SHEET_NAME}",
|
||||
"确定");
|
||||
return;
|
||||
}
|
||||
|
||||
int rowCount = worksheet.Dimension?.Rows ?? 0;
|
||||
|
||||
// 从第3行开始读取(第1行是字段名,第2行是中文说明)
|
||||
for (int row = 3; row <= rowCount; row++)
|
||||
{
|
||||
string idText = worksheet.Cells[row, COL_ID].Text;
|
||||
if (string.IsNullOrEmpty(idText))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!int.TryParse(idText, out int id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int areaId = ParseInt(worksheet.Cells[row, COL_AREA_ID].Text, 0);
|
||||
int soundId = ParseInt(worksheet.Cells[row, COL_SOUND_ID].Text, 0);
|
||||
|
||||
var ambientData = new AmbientSoundData
|
||||
{
|
||||
Id = id,
|
||||
AreaId = areaId,
|
||||
SoundId = soundId,
|
||||
RowIndex = row
|
||||
};
|
||||
|
||||
ambientDataList.Add(ambientData);
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log($"加载了 {ambientDataList.Count} 条环境音配置");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI绘制
|
||||
|
||||
/// <summary>
|
||||
/// 绘制环境音数据表格
|
||||
/// </summary>
|
||||
private void DrawAmbientDataTable()
|
||||
{
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
|
||||
// 顶部信息和保存按钮
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField($"共 {ambientDataList.Count} 条环境音配置", EditorStyles.boldLabel);
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
// 添加新行按钮
|
||||
if (GUILayout.Button("➕ 添加新行", GUILayout.Height(25), GUILayout.Width(100)))
|
||||
{
|
||||
AddNewAmbientData();
|
||||
}
|
||||
|
||||
// 保存按钮
|
||||
GUI.backgroundColor = Color.green;
|
||||
if (GUILayout.Button("💾 保存到Excel", GUILayout.Height(25), GUILayout.Width(120)))
|
||||
{
|
||||
SaveToExcel();
|
||||
}
|
||||
GUI.backgroundColor = Color.white;
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.Space(5);
|
||||
|
||||
// 表头
|
||||
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
|
||||
EditorGUILayout.LabelField("ID", EditorStyles.boldLabel, GUILayout.Width(50));
|
||||
EditorGUILayout.LabelField("场景ID", EditorStyles.boldLabel, GUILayout.Width(60));
|
||||
EditorGUILayout.LabelField("场景名称", EditorStyles.boldLabel, GUILayout.Width(200));
|
||||
EditorGUILayout.LabelField("环境音", EditorStyles.boldLabel, GUILayout.Width(300));
|
||||
EditorGUILayout.LabelField("操作", EditorStyles.boldLabel, GUILayout.Width(60));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
// 数据行
|
||||
ambientScrollPosition = EditorGUILayout.BeginScrollView(ambientScrollPosition, GUILayout.ExpandHeight(true));
|
||||
|
||||
for (int i = 0; i < ambientDataList.Count; i++)
|
||||
{
|
||||
var data = ambientDataList[i];
|
||||
DrawAmbientDataRow(data, i);
|
||||
}
|
||||
|
||||
EditorGUILayout.EndScrollView();
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绘制单行环境音数据
|
||||
/// </summary>
|
||||
private void DrawAmbientDataRow(AmbientSoundData data, int index)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal("box");
|
||||
|
||||
// ID(只读,自增)
|
||||
EditorGUILayout.LabelField(data.Id.ToString(), GUILayout.Width(50));
|
||||
|
||||
// 场景ID(可编辑)
|
||||
int newAreaId = EditorGUILayout.IntField(data.AreaId, GUILayout.Width(60));
|
||||
if (newAreaId != data.AreaId)
|
||||
{
|
||||
data.AreaId = newAreaId;
|
||||
}
|
||||
|
||||
// 场景名称(显示 AreaId + 中文名)
|
||||
string sceneName = GetSceneName(data.AreaId);
|
||||
EditorGUILayout.LabelField(sceneName, GUILayout.Width(200));
|
||||
|
||||
// 环境音下拉选择
|
||||
int currentIndex = GetSoundIndex(data.SoundId);
|
||||
string[] soundOptions = GetSoundOptions();
|
||||
int[] soundIds = AMBIENT_SOUND_IDS;
|
||||
|
||||
int newIndex = EditorGUILayout.Popup(currentIndex, soundOptions, GUILayout.Width(300));
|
||||
if (newIndex != currentIndex && newIndex >= 0 && newIndex < soundIds.Length)
|
||||
{
|
||||
data.SoundId = soundIds[newIndex];
|
||||
}
|
||||
|
||||
// 删除按钮
|
||||
GUI.backgroundColor = new Color(1f, 0.3f, 0.3f);
|
||||
if (GUILayout.Button("删除", GUILayout.Width(60), GUILayout.Height(20)))
|
||||
{
|
||||
if (EditorUtility.DisplayDialog("确认删除",
|
||||
$"确定要删除ID为 {data.Id} 的环境音配置吗?",
|
||||
"删除", "取消"))
|
||||
{
|
||||
ambientDataList.RemoveAt(index);
|
||||
}
|
||||
}
|
||||
GUI.backgroundColor = Color.white;
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绘制环境音属性编辑表格
|
||||
/// </summary>
|
||||
private void DrawSoundDataTable()
|
||||
{
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
|
||||
// 顶部信息和保存按钮
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField($"共 {soundDataDict.Count} 个环境音", EditorStyles.boldLabel);
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
// 保存按钮
|
||||
GUI.backgroundColor = Color.green;
|
||||
if (GUILayout.Button("💾 保存到Excel", GUILayout.Height(25), GUILayout.Width(120)))
|
||||
{
|
||||
SaveToExcel();
|
||||
}
|
||||
GUI.backgroundColor = Color.white;
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.Space(5);
|
||||
|
||||
// 表头
|
||||
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
|
||||
EditorGUILayout.LabelField("ID", EditorStyles.boldLabel, GUILayout.Width(60));
|
||||
EditorGUILayout.LabelField("策划备注", EditorStyles.boldLabel, GUILayout.Width(120));
|
||||
EditorGUILayout.LabelField("资源名称", EditorStyles.boldLabel, GUILayout.Width(180));
|
||||
EditorGUILayout.LabelField("优先级", EditorStyles.boldLabel, GUILayout.Width(60));
|
||||
EditorGUILayout.LabelField("循环", EditorStyles.boldLabel, GUILayout.Width(50));
|
||||
EditorGUILayout.LabelField("音量", EditorStyles.boldLabel, GUILayout.Width(120));
|
||||
EditorGUILayout.LabelField("空间混合", EditorStyles.boldLabel, GUILayout.Width(120));
|
||||
EditorGUILayout.LabelField("最大距离", EditorStyles.boldLabel, GUILayout.Width(80));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
// 数据行
|
||||
soundScrollPosition = EditorGUILayout.BeginScrollView(soundScrollPosition, GUILayout.ExpandHeight(true));
|
||||
|
||||
// 按固定顺序显示环境音
|
||||
foreach (int soundId in AMBIENT_SOUND_IDS)
|
||||
{
|
||||
if (soundDataDict.ContainsKey(soundId))
|
||||
{
|
||||
DrawSoundDataRow(soundDataDict[soundId]);
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.EndScrollView();
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绘制单行环境音Sound数据
|
||||
/// </summary>
|
||||
private void DrawSoundDataRow(SoundData data)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal("box");
|
||||
|
||||
// ID(只读)
|
||||
EditorGUILayout.LabelField(data.Id.ToString(), GUILayout.Width(60));
|
||||
|
||||
// 策划备注
|
||||
string newComment = EditorGUILayout.TextField(data.Comment, GUILayout.Width(120));
|
||||
if (newComment != data.Comment)
|
||||
{
|
||||
data.Comment = newComment;
|
||||
}
|
||||
|
||||
// 资源名称
|
||||
string newAssetName = EditorGUILayout.TextField(data.AssetName, GUILayout.Width(180));
|
||||
if (newAssetName != data.AssetName)
|
||||
{
|
||||
data.AssetName = newAssetName;
|
||||
}
|
||||
|
||||
// 优先级
|
||||
int newPriority = EditorGUILayout.IntField(data.Priority, GUILayout.Width(60));
|
||||
if (newPriority != data.Priority)
|
||||
{
|
||||
data.Priority = Mathf.Clamp(newPriority, -128, 128);
|
||||
}
|
||||
|
||||
// 循环
|
||||
bool newLoop = EditorGUILayout.Toggle(data.Loop, GUILayout.Width(50));
|
||||
if (newLoop != data.Loop)
|
||||
{
|
||||
data.Loop = newLoop;
|
||||
}
|
||||
|
||||
// 音量(带滑动条)
|
||||
float newVolume = EditorGUILayout.Slider(data.Volume, 0f, 1f, GUILayout.Width(120));
|
||||
if (!Mathf.Approximately(newVolume, data.Volume))
|
||||
{
|
||||
data.Volume = newVolume;
|
||||
}
|
||||
|
||||
// 空间混合(带滑动条)
|
||||
float newSpatialBlend = EditorGUILayout.Slider(data.SpatialBlend, 0f, 1f, GUILayout.Width(120));
|
||||
if (!Mathf.Approximately(newSpatialBlend, data.SpatialBlend))
|
||||
{
|
||||
data.SpatialBlend = newSpatialBlend;
|
||||
}
|
||||
|
||||
// 最大距离
|
||||
float newMaxDistance = EditorGUILayout.FloatField(data.MaxDistance, GUILayout.Width(80));
|
||||
if (!Mathf.Approximately(newMaxDistance, data.MaxDistance))
|
||||
{
|
||||
data.MaxDistance = Mathf.Max(0f, newMaxDistance);
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 数据操作
|
||||
|
||||
/// <summary>
|
||||
/// 添加新环境音数据
|
||||
/// </summary>
|
||||
private void AddNewAmbientData()
|
||||
{
|
||||
int newId = ambientDataList.Count > 0 ? ambientDataList.Max(d => d.Id) + 1 : 1;
|
||||
|
||||
var newData = new AmbientSoundData
|
||||
{
|
||||
Id = newId,
|
||||
AreaId = 0,
|
||||
SoundId = 10172, // 默认第一个环境音
|
||||
RowIndex = -1 // 新行,还没有Excel行索引
|
||||
};
|
||||
|
||||
ambientDataList.Add(newData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取场景名称
|
||||
/// </summary>
|
||||
private string GetSceneName(int areaId)
|
||||
{
|
||||
if (areaId == 0)
|
||||
{
|
||||
return "未设置";
|
||||
}
|
||||
|
||||
string key = $"CS_ScenePanel_Scene{areaId}";
|
||||
|
||||
if (languageDict.ContainsKey(key) && languageDict[key].ContainsKey("zh_CN"))
|
||||
{
|
||||
string zhName = languageDict[key]["zh_CN"];
|
||||
return $"{areaId} - {zhName}";
|
||||
}
|
||||
|
||||
return $"{areaId} - (未找到名称)";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取环境音选项(用于下拉框)
|
||||
/// </summary>
|
||||
private string[] GetSoundOptions()
|
||||
{
|
||||
List<string> options = new List<string>();
|
||||
foreach (int soundId in AMBIENT_SOUND_IDS)
|
||||
{
|
||||
if (soundDataDict.ContainsKey(soundId))
|
||||
{
|
||||
var soundData = soundDataDict[soundId];
|
||||
options.Add($"{soundId} - {soundData.Comment} - {soundData.AssetName}");
|
||||
}
|
||||
else
|
||||
{
|
||||
options.Add($"{soundId} - (未加载)");
|
||||
}
|
||||
}
|
||||
return options.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取SoundId在下拉列表中的索引
|
||||
/// </summary>
|
||||
private int GetSoundIndex(int soundId)
|
||||
{
|
||||
for (int i = 0; i < AMBIENT_SOUND_IDS.Length; i++)
|
||||
{
|
||||
if (AMBIENT_SOUND_IDS[i] == soundId)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0; // 默认返回第一个
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存到Excel
|
||||
/// </summary>
|
||||
private void SaveToExcel()
|
||||
{
|
||||
try
|
||||
{
|
||||
string excelPath = GetDocsConfigFilePath(SOUND_EXCEL_NAME);
|
||||
|
||||
// ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
|
||||
|
||||
using (var package = new ExcelPackage(new FileInfo(excelPath)))
|
||||
{
|
||||
// 1. 保存Ambient Sheet
|
||||
var ambientWorksheet = package.Workbook.Worksheets[AMBIENT_SHEET_NAME];
|
||||
|
||||
if (ambientWorksheet != null)
|
||||
{
|
||||
// 先清除旧数据(从第3行开始)
|
||||
int existingRowCount = ambientWorksheet.Dimension?.Rows ?? 2;
|
||||
for (int row = 3; row <= existingRowCount; row++)
|
||||
{
|
||||
ambientWorksheet.DeleteRow(3);
|
||||
}
|
||||
|
||||
// 写入新数据
|
||||
int currentRow = 3;
|
||||
foreach (var data in ambientDataList)
|
||||
{
|
||||
ambientWorksheet.Cells[currentRow, COL_ID].Value = data.Id;
|
||||
ambientWorksheet.Cells[currentRow, COL_AREA_ID].Value = data.AreaId;
|
||||
ambientWorksheet.Cells[currentRow, COL_SOUND_ID].Value = data.SoundId;
|
||||
|
||||
data.RowIndex = currentRow;
|
||||
currentRow++;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 保存Sound Sheet中的环境音数据
|
||||
var soundWorksheet = package.Workbook.Worksheets[SOUND_SHEET_NAME];
|
||||
|
||||
if (soundWorksheet != null)
|
||||
{
|
||||
foreach (var kvp in soundDataDict)
|
||||
{
|
||||
var data = kvp.Value;
|
||||
int row = data.RowIndex;
|
||||
|
||||
soundWorksheet.Cells[row, COL_SOUND_ID_IN_SOUND].Value = data.Id;
|
||||
soundWorksheet.Cells[row, COL_COMMENT].Value = data.Comment;
|
||||
soundWorksheet.Cells[row, COL_ASSET_NAME].Value = data.AssetName;
|
||||
soundWorksheet.Cells[row, COL_PRIORITY].Value = data.Priority;
|
||||
soundWorksheet.Cells[row, COL_LOOP].Value = data.Loop ? "TRUE" : "FALSE";
|
||||
soundWorksheet.Cells[row, COL_VOLUME].Value = data.Volume;
|
||||
soundWorksheet.Cells[row, COL_SPATIAL_BLEND].Value = data.SpatialBlend;
|
||||
soundWorksheet.Cells[row, COL_MAX_DISTANCE].Value = data.MaxDistance;
|
||||
}
|
||||
}
|
||||
|
||||
package.Save();
|
||||
}
|
||||
|
||||
EditorUtility.DisplayDialog("成功", "环境音配置已保存到Excel!", "确定");
|
||||
Debug.Log("环境音配置已保存");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
EditorUtility.DisplayDialog("错误", $"保存失败: {e.Message}", "确定");
|
||||
Debug.LogError($"保存环境音配置失败: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 辅助方法
|
||||
|
||||
private int ParseInt(string text, int defaultValue)
|
||||
{
|
||||
if (int.TryParse(text, out int result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
private float ParseFloat(string text, float defaultValue)
|
||||
{
|
||||
if (float.TryParse(text, out float result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
private bool ParseBool(string text)
|
||||
{
|
||||
return text.Equals("TRUE", StringComparison.OrdinalIgnoreCase) ||
|
||||
text.Equals("true", StringComparison.OrdinalIgnoreCase) ||
|
||||
text == "1";
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 环境音数据类
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class AmbientSoundData
|
||||
{
|
||||
public int Id; // 自增ID
|
||||
public int AreaId; // 场景ID
|
||||
public int SoundId; // 环境音SoundId
|
||||
public int RowIndex; // Excel中的行索引(用于保存时定位)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b44817e7f3595b842bfe9f3c94795890
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,506 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using OfficeOpenXml;
|
||||
using Debug = UnityEngine.Debug;
|
||||
|
||||
namespace DesignTools
|
||||
{
|
||||
/// <summary>
|
||||
/// 音效配置Editor工具
|
||||
/// 读取Docs/config/Sound.xlsx的Sound Sheet,编辑音效配置
|
||||
/// </summary>
|
||||
public class SoundItemConfigEditor : BaseDesignToolEditor
|
||||
{
|
||||
private const string SOUND_EXCEL_NAME = "Sound.xlsx";
|
||||
private const string SOUND_SHEET_NAME = "Sound";
|
||||
|
||||
// 表格列索引
|
||||
private const int COL_ID = 1;
|
||||
private const int COL_COMMENT = 2;
|
||||
private const int COL_ASSET_NAME = 3;
|
||||
private const int COL_PRIORITY = 4;
|
||||
private const int COL_LOOP = 5;
|
||||
private const int COL_VOLUME = 6;
|
||||
private const int COL_SPATIAL_BLEND = 7;
|
||||
private const int COL_MAX_DISTANCE = 8;
|
||||
|
||||
private List<SoundData> soundDataList = new List<SoundData>();
|
||||
private List<SoundData> filteredSoundDataList = new List<SoundData>();
|
||||
|
||||
// 搜索和筛选
|
||||
private string searchText = "";
|
||||
private bool showOnlyLoopSounds = false;
|
||||
|
||||
// 分页
|
||||
private int currentPage = 0;
|
||||
private int itemsPerPage = 20;
|
||||
private int totalPages = 0;
|
||||
|
||||
// 编辑状态
|
||||
private Dictionary<int, bool> foldoutStates = new Dictionary<int, bool>();
|
||||
|
||||
[MenuItem("策划工具/声音/音效配置")]
|
||||
public static void ShowWindow()
|
||||
{
|
||||
var window = GetWindow<SoundItemConfigEditor>("音效配置");
|
||||
window.minSize = window.GetMinWindowSize();
|
||||
window.Show();
|
||||
}
|
||||
|
||||
#region 基类实现
|
||||
|
||||
protected override string GetDocsPathPrefKey()
|
||||
{
|
||||
return "SoundItemConfigEditor_DocsPath";
|
||||
}
|
||||
|
||||
protected override string GetWindowTitle()
|
||||
{
|
||||
return "音效配置工具";
|
||||
}
|
||||
|
||||
protected override Vector2 GetMinWindowSize()
|
||||
{
|
||||
return new Vector2(1200, 700);
|
||||
}
|
||||
|
||||
protected override void LoadConfigData()
|
||||
{
|
||||
// 加载Sound表
|
||||
LoadSoundExcel();
|
||||
}
|
||||
|
||||
protected override void DrawDataEditor()
|
||||
{
|
||||
DrawFilterAndPagination();
|
||||
EditorGUILayout.Space(5);
|
||||
DrawSoundDataTable();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 不显示基类的底部按钮(已在顶部显示)
|
||||
/// </summary>
|
||||
protected override bool ShowBottomButtons()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存数据到Excel(覆盖基类方法)
|
||||
/// </summary>
|
||||
protected override void SaveDataToExcel()
|
||||
{
|
||||
SaveToExcel();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 数据加载
|
||||
|
||||
/// <summary>
|
||||
/// 加载Sound.xlsx
|
||||
/// </summary>
|
||||
private void LoadSoundExcel()
|
||||
{
|
||||
soundDataList.Clear();
|
||||
|
||||
string excelPath = GetDocsConfigFilePath(SOUND_EXCEL_NAME);
|
||||
|
||||
if (!File.Exists(excelPath))
|
||||
{
|
||||
EditorUtility.DisplayDialog("错误",
|
||||
$"未找到Sound.xlsx\n路径: {excelPath}",
|
||||
"确定");
|
||||
return;
|
||||
}
|
||||
|
||||
// ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
|
||||
|
||||
using (var package = new ExcelPackage(new FileInfo(excelPath)))
|
||||
{
|
||||
var worksheet = package.Workbook.Worksheets[SOUND_SHEET_NAME];
|
||||
|
||||
if (worksheet == null)
|
||||
{
|
||||
EditorUtility.DisplayDialog("错误",
|
||||
$"未找到Sheet: {SOUND_SHEET_NAME}",
|
||||
"确定");
|
||||
return;
|
||||
}
|
||||
|
||||
int rowCount = worksheet.Dimension?.Rows ?? 0;
|
||||
|
||||
// 从第3行开始读取(第1行是字段名,第2行是中文说明)
|
||||
for (int row = 3; row <= rowCount; row++)
|
||||
{
|
||||
string idText = worksheet.Cells[row, COL_ID].Text;
|
||||
if (string.IsNullOrEmpty(idText))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!int.TryParse(idText, out int id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var soundData = new SoundData
|
||||
{
|
||||
Id = id,
|
||||
Comment = worksheet.Cells[row, COL_COMMENT].Text,
|
||||
AssetName = worksheet.Cells[row, COL_ASSET_NAME].Text,
|
||||
Priority = ParseInt(worksheet.Cells[row, COL_PRIORITY].Text, 0),
|
||||
Loop = ParseBool(worksheet.Cells[row, COL_LOOP].Text),
|
||||
Volume = ParseFloat(worksheet.Cells[row, COL_VOLUME].Text, 1f),
|
||||
SpatialBlend = ParseFloat(worksheet.Cells[row, COL_SPATIAL_BLEND].Text, 0f),
|
||||
MaxDistance = ParseFloat(worksheet.Cells[row, COL_MAX_DISTANCE].Text, 100f),
|
||||
RowIndex = row
|
||||
};
|
||||
|
||||
soundDataList.Add(soundData);
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log($"加载了 {soundDataList.Count} 条音效配置");
|
||||
|
||||
// 初始化筛选列表
|
||||
ApplyFilter();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI绘制
|
||||
|
||||
/// <summary>
|
||||
/// 绘制筛选和分页
|
||||
/// </summary>
|
||||
private void DrawFilterAndPagination()
|
||||
{
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
|
||||
// 搜索和筛选
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
EditorGUILayout.LabelField("搜索", GUILayout.Width(40));
|
||||
string newSearchText = EditorGUILayout.TextField(searchText);
|
||||
if (newSearchText != searchText)
|
||||
{
|
||||
searchText = newSearchText;
|
||||
ApplyFilter();
|
||||
}
|
||||
|
||||
bool newShowOnlyLoop = EditorGUILayout.Toggle("仅显示循环音效", showOnlyLoopSounds, GUILayout.Width(150));
|
||||
if (newShowOnlyLoop != showOnlyLoopSounds)
|
||||
{
|
||||
showOnlyLoopSounds = newShowOnlyLoop;
|
||||
ApplyFilter();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("清除筛选", GUILayout.Width(80)))
|
||||
{
|
||||
searchText = "";
|
||||
showOnlyLoopSounds = false;
|
||||
ApplyFilter();
|
||||
}
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
// 保存按钮(放在筛选区域右侧,更显眼)
|
||||
GUI.backgroundColor = Color.green;
|
||||
if (GUILayout.Button("💾 保存到Excel", GUILayout.Height(25), GUILayout.Width(120)))
|
||||
{
|
||||
SaveToExcel();
|
||||
}
|
||||
GUI.backgroundColor = Color.white;
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
// 分页控制
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
EditorGUILayout.LabelField($"共 {filteredSoundDataList.Count} 条音效", GUILayout.Width(120));
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
if (GUILayout.Button("<<", GUILayout.Width(40)))
|
||||
{
|
||||
currentPage = 0;
|
||||
}
|
||||
|
||||
GUI.enabled = currentPage > 0;
|
||||
if (GUILayout.Button("<", GUILayout.Width(40)))
|
||||
{
|
||||
currentPage--;
|
||||
}
|
||||
GUI.enabled = true;
|
||||
|
||||
EditorGUILayout.LabelField($"第 {currentPage + 1}/{totalPages} 页", GUILayout.Width(100));
|
||||
|
||||
GUI.enabled = currentPage < totalPages - 1;
|
||||
if (GUILayout.Button(">", GUILayout.Width(40)))
|
||||
{
|
||||
currentPage++;
|
||||
}
|
||||
GUI.enabled = true;
|
||||
|
||||
if (GUILayout.Button(">>", GUILayout.Width(40)))
|
||||
{
|
||||
currentPage = totalPages - 1;
|
||||
}
|
||||
|
||||
EditorGUILayout.LabelField("每页", GUILayout.Width(30));
|
||||
int newItemsPerPage = EditorGUILayout.IntField(itemsPerPage, GUILayout.Width(50));
|
||||
if (newItemsPerPage != itemsPerPage && newItemsPerPage > 0)
|
||||
{
|
||||
itemsPerPage = newItemsPerPage;
|
||||
ApplyFilter();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绘制音效数据表格
|
||||
/// </summary>
|
||||
private void DrawSoundDataTable()
|
||||
{
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
|
||||
// 表头
|
||||
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
|
||||
EditorGUILayout.LabelField("ID", EditorStyles.boldLabel, GUILayout.Width(60));
|
||||
EditorGUILayout.LabelField("策划备注", EditorStyles.boldLabel, GUILayout.Width(120));
|
||||
EditorGUILayout.LabelField("资源名称", EditorStyles.boldLabel, GUILayout.Width(180));
|
||||
EditorGUILayout.LabelField("优先级", EditorStyles.boldLabel, GUILayout.Width(60));
|
||||
EditorGUILayout.LabelField("循环", EditorStyles.boldLabel, GUILayout.Width(50));
|
||||
EditorGUILayout.LabelField("音量", EditorStyles.boldLabel, GUILayout.Width(120));
|
||||
EditorGUILayout.LabelField("空间混合", EditorStyles.boldLabel, GUILayout.Width(120));
|
||||
EditorGUILayout.LabelField("最大距离", EditorStyles.boldLabel, GUILayout.Width(80));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
// 数据行(使用 ExpandHeight 让 ScrollView 自适应剩余空间)
|
||||
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition, GUILayout.ExpandHeight(true));
|
||||
|
||||
int startIndex = currentPage * itemsPerPage;
|
||||
int endIndex = Mathf.Min(startIndex + itemsPerPage, filteredSoundDataList.Count);
|
||||
|
||||
for (int i = startIndex; i < endIndex; i++)
|
||||
{
|
||||
var soundData = filteredSoundDataList[i];
|
||||
DrawSoundDataRow(soundData);
|
||||
}
|
||||
|
||||
EditorGUILayout.EndScrollView();
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绘制单行音效数据
|
||||
/// </summary>
|
||||
private void DrawSoundDataRow(SoundData data)
|
||||
{
|
||||
bool isExpanded = foldoutStates.ContainsKey(data.Id) && foldoutStates[data.Id];
|
||||
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
|
||||
// 基础信息行
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
// ID(可编辑)
|
||||
int newId = EditorGUILayout.IntField(data.Id, GUILayout.Width(60));
|
||||
if (newId != data.Id && newId > 0)
|
||||
{
|
||||
data.Id = newId;
|
||||
}
|
||||
|
||||
// 策划备注
|
||||
string newComment = EditorGUILayout.TextField(data.Comment, GUILayout.Width(120));
|
||||
if (newComment != data.Comment)
|
||||
{
|
||||
data.Comment = newComment;
|
||||
}
|
||||
|
||||
// 资源名称
|
||||
string newAssetName = EditorGUILayout.TextField(data.AssetName, GUILayout.Width(180));
|
||||
if (newAssetName != data.AssetName)
|
||||
{
|
||||
data.AssetName = newAssetName;
|
||||
}
|
||||
|
||||
// 优先级
|
||||
int newPriority = EditorGUILayout.IntField(data.Priority, GUILayout.Width(60));
|
||||
if (newPriority != data.Priority)
|
||||
{
|
||||
data.Priority = Mathf.Clamp(newPriority, -128, 128);
|
||||
}
|
||||
|
||||
// 循环
|
||||
bool newLoop = EditorGUILayout.Toggle(data.Loop, GUILayout.Width(50));
|
||||
if (newLoop != data.Loop)
|
||||
{
|
||||
data.Loop = newLoop;
|
||||
}
|
||||
|
||||
// 音量(带滑动条)
|
||||
float newVolume = EditorGUILayout.Slider(data.Volume, 0f, 1f, GUILayout.Width(120));
|
||||
if (!Mathf.Approximately(newVolume, data.Volume))
|
||||
{
|
||||
data.Volume = newVolume;
|
||||
}
|
||||
|
||||
// 空间混合(带滑动条)
|
||||
float newSpatialBlend = EditorGUILayout.Slider(data.SpatialBlend, 0f, 1f, GUILayout.Width(120));
|
||||
if (!Mathf.Approximately(newSpatialBlend, data.SpatialBlend))
|
||||
{
|
||||
data.SpatialBlend = newSpatialBlend;
|
||||
}
|
||||
|
||||
// 最大距离
|
||||
float newMaxDistance = EditorGUILayout.FloatField(data.MaxDistance, GUILayout.Width(80));
|
||||
if (!Mathf.Approximately(newMaxDistance, data.MaxDistance))
|
||||
{
|
||||
data.MaxDistance = Mathf.Max(0f, newMaxDistance);
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 数据筛选和保存
|
||||
|
||||
/// <summary>
|
||||
/// 应用筛选
|
||||
/// </summary>
|
||||
private void ApplyFilter()
|
||||
{
|
||||
filteredSoundDataList.Clear();
|
||||
|
||||
foreach (var data in soundDataList)
|
||||
{
|
||||
bool matchSearch = string.IsNullOrEmpty(searchText) ||
|
||||
data.Id.ToString().Contains(searchText) ||
|
||||
data.Comment.Contains(searchText) ||
|
||||
data.AssetName.Contains(searchText);
|
||||
|
||||
bool matchLoop = !showOnlyLoopSounds || data.Loop;
|
||||
|
||||
if (matchSearch && matchLoop)
|
||||
{
|
||||
filteredSoundDataList.Add(data);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新分页
|
||||
totalPages = Mathf.Max(1, Mathf.CeilToInt((float)filteredSoundDataList.Count / itemsPerPage));
|
||||
currentPage = Mathf.Clamp(currentPage, 0, totalPages - 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存到Excel
|
||||
/// </summary>
|
||||
private void SaveToExcel()
|
||||
{
|
||||
try
|
||||
{
|
||||
string excelPath = GetDocsConfigFilePath(SOUND_EXCEL_NAME);
|
||||
|
||||
// ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
|
||||
|
||||
using (var package = new ExcelPackage(new FileInfo(excelPath)))
|
||||
{
|
||||
var worksheet = package.Workbook.Worksheets[SOUND_SHEET_NAME];
|
||||
|
||||
if (worksheet == null)
|
||||
{
|
||||
EditorUtility.DisplayDialog("错误",
|
||||
$"未找到Sheet: {SOUND_SHEET_NAME}",
|
||||
"确定");
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新每一行数据
|
||||
foreach (var data in soundDataList)
|
||||
{
|
||||
int row = data.RowIndex;
|
||||
|
||||
worksheet.Cells[row, COL_ID].Value = data.Id;
|
||||
worksheet.Cells[row, COL_COMMENT].Value = data.Comment;
|
||||
worksheet.Cells[row, COL_ASSET_NAME].Value = data.AssetName;
|
||||
worksheet.Cells[row, COL_PRIORITY].Value = data.Priority;
|
||||
worksheet.Cells[row, COL_LOOP].Value = data.Loop ? "TRUE" : "FALSE";
|
||||
worksheet.Cells[row, COL_VOLUME].Value = data.Volume;
|
||||
worksheet.Cells[row, COL_SPATIAL_BLEND].Value = data.SpatialBlend;
|
||||
worksheet.Cells[row, COL_MAX_DISTANCE].Value = data.MaxDistance;
|
||||
}
|
||||
|
||||
package.Save();
|
||||
}
|
||||
|
||||
EditorUtility.DisplayDialog("成功", "音效配置已保存到Excel!", "确定");
|
||||
Debug.Log("音效配置已保存");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
EditorUtility.DisplayDialog("错误", $"保存失败: {e.Message}", "确定");
|
||||
Debug.LogError($"保存音效配置失败: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 辅助方法
|
||||
|
||||
private int ParseInt(string text, int defaultValue)
|
||||
{
|
||||
if (int.TryParse(text, out int result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
private float ParseFloat(string text, float defaultValue)
|
||||
{
|
||||
if (float.TryParse(text, out float result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
private bool ParseBool(string text)
|
||||
{
|
||||
return text.Equals("TRUE", StringComparison.OrdinalIgnoreCase) ||
|
||||
text.Equals("true", StringComparison.OrdinalIgnoreCase) ||
|
||||
text == "1";
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 音效数据类
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SoundData
|
||||
{
|
||||
public int Id; // 声音编号
|
||||
public string Comment; // 策划备注
|
||||
public string AssetName; // 资源名称
|
||||
public int Priority; // 优先级(0默认,128最高,-128最低)
|
||||
public bool Loop; // 是否循环
|
||||
public float Volume; // 音量(0~1)
|
||||
public float SpatialBlend; // 空间混合量(0为2D,1为3D)
|
||||
public float MaxDistance; // 最大距离
|
||||
public int RowIndex; // Excel中的行索引(用于保存时定位)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f0b337e7484be964986c964bcadd7867
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -128,6 +128,7 @@ namespace Byway.Thrift.Data
|
||||
private global::Byway.Thrift.Data.GuideReward _GuideReward;
|
||||
private global::Byway.Thrift.Data.FriendConst _FriendConst;
|
||||
private global::Byway.Thrift.Data.ChargeConst _ChargeConst;
|
||||
private global::Byway.Thrift.Data.AmbientData _AmbientData;
|
||||
|
||||
[DataMember(Order = 0)]
|
||||
public global::Byway.Thrift.Data.AdGiftData AdGiftData
|
||||
@ -1361,6 +1362,20 @@ namespace Byway.Thrift.Data
|
||||
}
|
||||
}
|
||||
|
||||
[DataMember(Order = 0)]
|
||||
public global::Byway.Thrift.Data.AmbientData AmbientData
|
||||
{
|
||||
get
|
||||
{
|
||||
return _AmbientData;
|
||||
}
|
||||
set
|
||||
{
|
||||
__isset.AmbientData = true;
|
||||
this._AmbientData = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[DataMember(Order = 1)]
|
||||
public Isset __isset;
|
||||
@ -1543,6 +1558,8 @@ namespace Byway.Thrift.Data
|
||||
public bool FriendConst;
|
||||
[DataMember]
|
||||
public bool ChargeConst;
|
||||
[DataMember]
|
||||
public bool AmbientData;
|
||||
}
|
||||
|
||||
#region XmlSerializer support
|
||||
@ -1987,6 +2004,11 @@ namespace Byway.Thrift.Data
|
||||
return __isset.ChargeConst;
|
||||
}
|
||||
|
||||
public bool ShouldSerializeAmbientData()
|
||||
{
|
||||
return __isset.AmbientData;
|
||||
}
|
||||
|
||||
#endregion XmlSerializer support
|
||||
|
||||
public AllConfigs()
|
||||
@ -2436,6 +2458,11 @@ namespace Byway.Thrift.Data
|
||||
tmp0.ChargeConst = (global::Byway.Thrift.Data.ChargeConst)this.ChargeConst.DeepCopy();
|
||||
}
|
||||
tmp0.__isset.ChargeConst = this.__isset.ChargeConst;
|
||||
if((AmbientData != null) && __isset.AmbientData)
|
||||
{
|
||||
tmp0.AmbientData = (global::Byway.Thrift.Data.AmbientData)this.AmbientData.DeepCopy();
|
||||
}
|
||||
tmp0.__isset.AmbientData = this.__isset.AmbientData;
|
||||
return tmp0;
|
||||
}
|
||||
|
||||
@ -3424,6 +3451,17 @@ namespace Byway.Thrift.Data
|
||||
await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);
|
||||
}
|
||||
break;
|
||||
case 89:
|
||||
if (field.Type == TType.Struct)
|
||||
{
|
||||
AmbientData = new global::Byway.Thrift.Data.AmbientData();
|
||||
await AmbientData.ReadAsync(iprot, cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);
|
||||
break;
|
||||
@ -4240,6 +4278,15 @@ namespace Byway.Thrift.Data
|
||||
await ChargeConst.WriteAsync(oprot, cancellationToken);
|
||||
await oprot.WriteFieldEndAsync(cancellationToken);
|
||||
}
|
||||
if((AmbientData != null) && __isset.AmbientData)
|
||||
{
|
||||
tmp2.Name = "AmbientData";
|
||||
tmp2.Type = TType.Struct;
|
||||
tmp2.ID = 89;
|
||||
await oprot.WriteFieldBeginAsync(tmp2, cancellationToken);
|
||||
await AmbientData.WriteAsync(oprot, cancellationToken);
|
||||
await oprot.WriteFieldEndAsync(cancellationToken);
|
||||
}
|
||||
await oprot.WriteFieldStopAsync(cancellationToken);
|
||||
await oprot.WriteStructEndAsync(cancellationToken);
|
||||
}
|
||||
@ -4340,7 +4387,8 @@ namespace Byway.Thrift.Data
|
||||
&& ((__isset.ConstantString == other.__isset.ConstantString) && ((!__isset.ConstantString) || (global::System.Object.Equals(ConstantString, other.ConstantString))))
|
||||
&& ((__isset.GuideReward == other.__isset.GuideReward) && ((!__isset.GuideReward) || (global::System.Object.Equals(GuideReward, other.GuideReward))))
|
||||
&& ((__isset.FriendConst == other.__isset.FriendConst) && ((!__isset.FriendConst) || (global::System.Object.Equals(FriendConst, other.FriendConst))))
|
||||
&& ((__isset.ChargeConst == other.__isset.ChargeConst) && ((!__isset.ChargeConst) || (global::System.Object.Equals(ChargeConst, other.ChargeConst))));
|
||||
&& ((__isset.ChargeConst == other.__isset.ChargeConst) && ((!__isset.ChargeConst) || (global::System.Object.Equals(ChargeConst, other.ChargeConst))))
|
||||
&& ((__isset.AmbientData == other.__isset.AmbientData) && ((!__isset.AmbientData) || (global::System.Object.Equals(AmbientData, other.AmbientData))));
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
@ -4698,6 +4746,10 @@ namespace Byway.Thrift.Data
|
||||
{
|
||||
hashcode = (hashcode * 397) + ChargeConst.GetHashCode();
|
||||
}
|
||||
if((AmbientData != null) && __isset.AmbientData)
|
||||
{
|
||||
hashcode = (hashcode * 397) + AmbientData.GetHashCode();
|
||||
}
|
||||
}
|
||||
return hashcode;
|
||||
}
|
||||
@ -5234,6 +5286,12 @@ namespace Byway.Thrift.Data
|
||||
tmp3.Append("ChargeConst: ");
|
||||
ChargeConst.ToString(tmp3);
|
||||
}
|
||||
if((AmbientData != null) && __isset.AmbientData)
|
||||
{
|
||||
if(0 < tmp4++) { tmp3.Append(", "); }
|
||||
tmp3.Append("AmbientData: ");
|
||||
AmbientData.ToString(tmp3);
|
||||
}
|
||||
tmp3.Append(')');
|
||||
return tmp3.ToString();
|
||||
}
|
||||
|
||||
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* <auto-generated>
|
||||
* Autogenerated by Thrift Compiler (0.22.0)
|
||||
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
* </auto-generated>
|
||||
*/
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Thrift;
|
||||
using Thrift.Collections;
|
||||
using System.Runtime.Serialization;
|
||||
using Thrift.Protocol;
|
||||
|
||||
|
||||
#pragma warning disable IDE0079 // remove unnecessary pragmas
|
||||
#pragma warning disable IDE0017 // object init can be simplified
|
||||
#pragma warning disable IDE0028 // collection init can be simplified
|
||||
#pragma warning disable IDE0305 // collection init can be simplified
|
||||
#pragma warning disable IDE0034 // simplify default expression
|
||||
#pragma warning disable IDE0066 // use switch expression
|
||||
#pragma warning disable IDE0090 // simplify new expression
|
||||
#pragma warning disable IDE0290 // use primary CTOR
|
||||
#pragma warning disable IDE1006 // parts of the code use IDL spelling
|
||||
#pragma warning disable CA1822 // empty DeepCopy() methods still non-static
|
||||
#pragma warning disable IDE0083 // pattern matching "that is not SomeType" requires net5.0 but we still support earlier versions
|
||||
|
||||
namespace Byway.Thrift.Data
|
||||
{
|
||||
public static class AmbientDataExtensions
|
||||
{
|
||||
public static bool Equals(this Dictionary<int, global::Byway.Thrift.Data.AmbientDataItem> instance, object that)
|
||||
{
|
||||
if (!(that is Dictionary<int, global::Byway.Thrift.Data.AmbientDataItem> other)) return false;
|
||||
if (ReferenceEquals(instance, other)) return true;
|
||||
|
||||
return TCollections.Equals(instance, other);
|
||||
}
|
||||
|
||||
|
||||
public static int GetHashCode(this Dictionary<int, global::Byway.Thrift.Data.AmbientDataItem> instance)
|
||||
{
|
||||
return TCollections.GetHashCode(instance);
|
||||
}
|
||||
|
||||
|
||||
public static Dictionary<int, global::Byway.Thrift.Data.AmbientDataItem> DeepCopy(this Dictionary<int, global::Byway.Thrift.Data.AmbientDataItem> source)
|
||||
{
|
||||
if (source == null)
|
||||
return null;
|
||||
|
||||
var tmp15 = new Dictionary<int, global::Byway.Thrift.Data.AmbientDataItem>(source.Count);
|
||||
foreach (var pair in source)
|
||||
tmp15.Add(pair.Key, (pair.Value != null) ? pair.Value.DeepCopy() : null);
|
||||
return tmp15;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9e07ba4d5cb076f4bb8d6dcb0cdaa1b3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
214
Scripts/thrift/gen-netstd/Byway/Thrift/Data/AmbientData.cs
Normal file
214
Scripts/thrift/gen-netstd/Byway/Thrift/Data/AmbientData.cs
Normal file
@ -0,0 +1,214 @@
|
||||
/**
|
||||
* <auto-generated>
|
||||
* Autogenerated by Thrift Compiler (0.22.0)
|
||||
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
* </auto-generated>
|
||||
*/
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Thrift;
|
||||
using Thrift.Collections;
|
||||
using System.Runtime.Serialization;
|
||||
using Thrift.Protocol;
|
||||
using Thrift.Protocol.Entities;
|
||||
using Thrift.Protocol.Utilities;
|
||||
using Thrift.Transport;
|
||||
using Thrift.Transport.Client;
|
||||
|
||||
|
||||
#pragma warning disable IDE0079 // remove unnecessary pragmas
|
||||
#pragma warning disable IDE0017 // object init can be simplified
|
||||
#pragma warning disable IDE0028 // collection init can be simplified
|
||||
#pragma warning disable IDE0305 // collection init can be simplified
|
||||
#pragma warning disable IDE0034 // simplify default expression
|
||||
#pragma warning disable IDE0066 // use switch expression
|
||||
#pragma warning disable IDE0090 // simplify new expression
|
||||
#pragma warning disable IDE0290 // use primary CTOR
|
||||
#pragma warning disable IDE1006 // parts of the code use IDL spelling
|
||||
#pragma warning disable CA1822 // empty DeepCopy() methods still non-static
|
||||
#pragma warning disable IDE0083 // pattern matching "that is not SomeType" requires net5.0 but we still support earlier versions
|
||||
|
||||
namespace Byway.Thrift.Data
|
||||
{
|
||||
|
||||
[DataContract(Namespace="")]
|
||||
public partial class AmbientData : TBase
|
||||
{
|
||||
private Dictionary<int, global::Byway.Thrift.Data.AmbientDataItem> _ambientdatas;
|
||||
|
||||
[DataMember(Order = 0)]
|
||||
public Dictionary<int, global::Byway.Thrift.Data.AmbientDataItem> Ambientdatas
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ambientdatas;
|
||||
}
|
||||
set
|
||||
{
|
||||
__isset.@ambientdatas = true;
|
||||
this._ambientdatas = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[DataMember(Order = 1)]
|
||||
public Isset __isset;
|
||||
[DataContract]
|
||||
public struct Isset
|
||||
{
|
||||
[DataMember]
|
||||
public bool @ambientdatas;
|
||||
}
|
||||
|
||||
#region XmlSerializer support
|
||||
|
||||
public bool ShouldSerializeAmbientdatas()
|
||||
{
|
||||
return __isset.@ambientdatas;
|
||||
}
|
||||
|
||||
#endregion XmlSerializer support
|
||||
|
||||
public AmbientData()
|
||||
{
|
||||
}
|
||||
|
||||
public AmbientData DeepCopy()
|
||||
{
|
||||
var tmp5 = new AmbientData();
|
||||
if((Ambientdatas != null) && __isset.@ambientdatas)
|
||||
{
|
||||
tmp5.Ambientdatas = this.Ambientdatas.DeepCopy();
|
||||
}
|
||||
tmp5.__isset.@ambientdatas = this.__isset.@ambientdatas;
|
||||
return tmp5;
|
||||
}
|
||||
|
||||
public async global::System.Threading.Tasks.Task ReadAsync(TProtocol iprot, CancellationToken cancellationToken)
|
||||
{
|
||||
iprot.IncrementRecursionDepth();
|
||||
try
|
||||
{
|
||||
TField field;
|
||||
await iprot.ReadStructBeginAsync(cancellationToken);
|
||||
while (true)
|
||||
{
|
||||
field = await iprot.ReadFieldBeginAsync(cancellationToken);
|
||||
if (field.Type == TType.Stop)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
switch (field.ID)
|
||||
{
|
||||
case 1:
|
||||
if (field.Type == TType.Map)
|
||||
{
|
||||
{
|
||||
var _map6 = await iprot.ReadMapBeginAsync(cancellationToken);
|
||||
Ambientdatas = new Dictionary<int, global::Byway.Thrift.Data.AmbientDataItem>(_map6.Count);
|
||||
for(int _i7 = 0; _i7 < _map6.Count; ++_i7)
|
||||
{
|
||||
int _key8;
|
||||
global::Byway.Thrift.Data.AmbientDataItem _val9;
|
||||
_key8 = await iprot.ReadI32Async(cancellationToken);
|
||||
_val9 = new global::Byway.Thrift.Data.AmbientDataItem();
|
||||
await _val9.ReadAsync(iprot, cancellationToken);
|
||||
Ambientdatas[_key8] = _val9;
|
||||
}
|
||||
await iprot.ReadMapEndAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);
|
||||
break;
|
||||
}
|
||||
|
||||
await iprot.ReadFieldEndAsync(cancellationToken);
|
||||
}
|
||||
|
||||
await iprot.ReadStructEndAsync(cancellationToken);
|
||||
}
|
||||
finally
|
||||
{
|
||||
iprot.DecrementRecursionDepth();
|
||||
}
|
||||
}
|
||||
|
||||
public async global::System.Threading.Tasks.Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken)
|
||||
{
|
||||
oprot.IncrementRecursionDepth();
|
||||
try
|
||||
{
|
||||
var tmp10 = new TStruct("AmbientData");
|
||||
await oprot.WriteStructBeginAsync(tmp10, cancellationToken);
|
||||
var tmp11 = new TField();
|
||||
if((Ambientdatas != null) && __isset.@ambientdatas)
|
||||
{
|
||||
tmp11.Name = "ambientdatas";
|
||||
tmp11.Type = TType.Map;
|
||||
tmp11.ID = 1;
|
||||
await oprot.WriteFieldBeginAsync(tmp11, cancellationToken);
|
||||
await oprot.WriteMapBeginAsync(new TMap(TType.I32, TType.Struct, Ambientdatas.Count), cancellationToken);
|
||||
foreach (int _iter12 in Ambientdatas.Keys)
|
||||
{
|
||||
await oprot.WriteI32Async(_iter12, cancellationToken);
|
||||
await Ambientdatas[_iter12].WriteAsync(oprot, cancellationToken);
|
||||
}
|
||||
await oprot.WriteMapEndAsync(cancellationToken);
|
||||
await oprot.WriteFieldEndAsync(cancellationToken);
|
||||
}
|
||||
await oprot.WriteFieldStopAsync(cancellationToken);
|
||||
await oprot.WriteStructEndAsync(cancellationToken);
|
||||
}
|
||||
finally
|
||||
{
|
||||
oprot.DecrementRecursionDepth();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object that)
|
||||
{
|
||||
if (!(that is AmbientData other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
return ((__isset.@ambientdatas == other.__isset.@ambientdatas) && ((!__isset.@ambientdatas) || (TCollections.Equals(Ambientdatas, other.Ambientdatas))));
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
int hashcode = 157;
|
||||
unchecked {
|
||||
if((Ambientdatas != null) && __isset.@ambientdatas)
|
||||
{
|
||||
hashcode = (hashcode * 397) + TCollections.GetHashCode(Ambientdatas);
|
||||
}
|
||||
}
|
||||
return hashcode;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var tmp13 = new StringBuilder("AmbientData(");
|
||||
int tmp14 = 0;
|
||||
if((Ambientdatas != null) && __isset.@ambientdatas)
|
||||
{
|
||||
if(0 < tmp14++) { tmp13.Append(", "); }
|
||||
tmp13.Append("Ambientdatas: ");
|
||||
Ambientdatas.ToString(tmp13);
|
||||
}
|
||||
tmp13.Append(')');
|
||||
return tmp13.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0e4ea8fd0e667194b8f6079e25b9c1cf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
309
Scripts/thrift/gen-netstd/Byway/Thrift/Data/AmbientDataItem.cs
Normal file
309
Scripts/thrift/gen-netstd/Byway/Thrift/Data/AmbientDataItem.cs
Normal file
@ -0,0 +1,309 @@
|
||||
/**
|
||||
* <auto-generated>
|
||||
* Autogenerated by Thrift Compiler (0.22.0)
|
||||
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
* </auto-generated>
|
||||
*/
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Thrift;
|
||||
using Thrift.Collections;
|
||||
using System.Runtime.Serialization;
|
||||
using Thrift.Protocol;
|
||||
using Thrift.Protocol.Entities;
|
||||
using Thrift.Protocol.Utilities;
|
||||
using Thrift.Transport;
|
||||
using Thrift.Transport.Client;
|
||||
|
||||
|
||||
#pragma warning disable IDE0079 // remove unnecessary pragmas
|
||||
#pragma warning disable IDE0017 // object init can be simplified
|
||||
#pragma warning disable IDE0028 // collection init can be simplified
|
||||
#pragma warning disable IDE0305 // collection init can be simplified
|
||||
#pragma warning disable IDE0034 // simplify default expression
|
||||
#pragma warning disable IDE0066 // use switch expression
|
||||
#pragma warning disable IDE0090 // simplify new expression
|
||||
#pragma warning disable IDE0290 // use primary CTOR
|
||||
#pragma warning disable IDE1006 // parts of the code use IDL spelling
|
||||
#pragma warning disable CA1822 // empty DeepCopy() methods still non-static
|
||||
#pragma warning disable IDE0083 // pattern matching "that is not SomeType" requires net5.0 but we still support earlier versions
|
||||
|
||||
namespace Byway.Thrift.Data
|
||||
{
|
||||
|
||||
[DataContract(Namespace="")]
|
||||
public partial class AmbientDataItem : TBase
|
||||
{
|
||||
private int _Id;
|
||||
private int _AreaId;
|
||||
private int _SoundId;
|
||||
|
||||
[DataMember(Order = 0)]
|
||||
public int Id
|
||||
{
|
||||
get
|
||||
{
|
||||
return _Id;
|
||||
}
|
||||
set
|
||||
{
|
||||
__isset.Id = true;
|
||||
this._Id = value;
|
||||
}
|
||||
}
|
||||
|
||||
[DataMember(Order = 0)]
|
||||
public int AreaId
|
||||
{
|
||||
get
|
||||
{
|
||||
return _AreaId;
|
||||
}
|
||||
set
|
||||
{
|
||||
__isset.AreaId = true;
|
||||
this._AreaId = value;
|
||||
}
|
||||
}
|
||||
|
||||
[DataMember(Order = 0)]
|
||||
public int SoundId
|
||||
{
|
||||
get
|
||||
{
|
||||
return _SoundId;
|
||||
}
|
||||
set
|
||||
{
|
||||
__isset.SoundId = true;
|
||||
this._SoundId = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[DataMember(Order = 1)]
|
||||
public Isset __isset;
|
||||
[DataContract]
|
||||
public struct Isset
|
||||
{
|
||||
[DataMember]
|
||||
public bool Id;
|
||||
[DataMember]
|
||||
public bool AreaId;
|
||||
[DataMember]
|
||||
public bool SoundId;
|
||||
}
|
||||
|
||||
#region XmlSerializer support
|
||||
|
||||
public bool ShouldSerializeId()
|
||||
{
|
||||
return __isset.Id;
|
||||
}
|
||||
|
||||
public bool ShouldSerializeAreaId()
|
||||
{
|
||||
return __isset.AreaId;
|
||||
}
|
||||
|
||||
public bool ShouldSerializeSoundId()
|
||||
{
|
||||
return __isset.SoundId;
|
||||
}
|
||||
|
||||
#endregion XmlSerializer support
|
||||
|
||||
public AmbientDataItem()
|
||||
{
|
||||
}
|
||||
|
||||
public AmbientDataItem DeepCopy()
|
||||
{
|
||||
var tmp0 = new AmbientDataItem();
|
||||
if(__isset.Id)
|
||||
{
|
||||
tmp0.Id = this.Id;
|
||||
}
|
||||
tmp0.__isset.Id = this.__isset.Id;
|
||||
if(__isset.AreaId)
|
||||
{
|
||||
tmp0.AreaId = this.AreaId;
|
||||
}
|
||||
tmp0.__isset.AreaId = this.__isset.AreaId;
|
||||
if(__isset.SoundId)
|
||||
{
|
||||
tmp0.SoundId = this.SoundId;
|
||||
}
|
||||
tmp0.__isset.SoundId = this.__isset.SoundId;
|
||||
return tmp0;
|
||||
}
|
||||
|
||||
public async global::System.Threading.Tasks.Task ReadAsync(TProtocol iprot, CancellationToken cancellationToken)
|
||||
{
|
||||
iprot.IncrementRecursionDepth();
|
||||
try
|
||||
{
|
||||
TField field;
|
||||
await iprot.ReadStructBeginAsync(cancellationToken);
|
||||
while (true)
|
||||
{
|
||||
field = await iprot.ReadFieldBeginAsync(cancellationToken);
|
||||
if (field.Type == TType.Stop)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
switch (field.ID)
|
||||
{
|
||||
case 1:
|
||||
if (field.Type == TType.I32)
|
||||
{
|
||||
Id = await iprot.ReadI32Async(cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (field.Type == TType.I32)
|
||||
{
|
||||
AreaId = await iprot.ReadI32Async(cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (field.Type == TType.I32)
|
||||
{
|
||||
SoundId = await iprot.ReadI32Async(cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);
|
||||
break;
|
||||
}
|
||||
|
||||
await iprot.ReadFieldEndAsync(cancellationToken);
|
||||
}
|
||||
|
||||
await iprot.ReadStructEndAsync(cancellationToken);
|
||||
}
|
||||
finally
|
||||
{
|
||||
iprot.DecrementRecursionDepth();
|
||||
}
|
||||
}
|
||||
|
||||
public async global::System.Threading.Tasks.Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken)
|
||||
{
|
||||
oprot.IncrementRecursionDepth();
|
||||
try
|
||||
{
|
||||
var tmp1 = new TStruct("AmbientDataItem");
|
||||
await oprot.WriteStructBeginAsync(tmp1, cancellationToken);
|
||||
var tmp2 = new TField();
|
||||
if(__isset.Id)
|
||||
{
|
||||
tmp2.Name = "Id";
|
||||
tmp2.Type = TType.I32;
|
||||
tmp2.ID = 1;
|
||||
await oprot.WriteFieldBeginAsync(tmp2, cancellationToken);
|
||||
await oprot.WriteI32Async(Id, cancellationToken);
|
||||
await oprot.WriteFieldEndAsync(cancellationToken);
|
||||
}
|
||||
if(__isset.AreaId)
|
||||
{
|
||||
tmp2.Name = "AreaId";
|
||||
tmp2.Type = TType.I32;
|
||||
tmp2.ID = 2;
|
||||
await oprot.WriteFieldBeginAsync(tmp2, cancellationToken);
|
||||
await oprot.WriteI32Async(AreaId, cancellationToken);
|
||||
await oprot.WriteFieldEndAsync(cancellationToken);
|
||||
}
|
||||
if(__isset.SoundId)
|
||||
{
|
||||
tmp2.Name = "SoundId";
|
||||
tmp2.Type = TType.I32;
|
||||
tmp2.ID = 3;
|
||||
await oprot.WriteFieldBeginAsync(tmp2, cancellationToken);
|
||||
await oprot.WriteI32Async(SoundId, cancellationToken);
|
||||
await oprot.WriteFieldEndAsync(cancellationToken);
|
||||
}
|
||||
await oprot.WriteFieldStopAsync(cancellationToken);
|
||||
await oprot.WriteStructEndAsync(cancellationToken);
|
||||
}
|
||||
finally
|
||||
{
|
||||
oprot.DecrementRecursionDepth();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object that)
|
||||
{
|
||||
if (!(that is AmbientDataItem other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
return ((__isset.Id == other.__isset.Id) && ((!__isset.Id) || (global::System.Object.Equals(Id, other.Id))))
|
||||
&& ((__isset.AreaId == other.__isset.AreaId) && ((!__isset.AreaId) || (global::System.Object.Equals(AreaId, other.AreaId))))
|
||||
&& ((__isset.SoundId == other.__isset.SoundId) && ((!__isset.SoundId) || (global::System.Object.Equals(SoundId, other.SoundId))));
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
int hashcode = 157;
|
||||
unchecked {
|
||||
if(__isset.Id)
|
||||
{
|
||||
hashcode = (hashcode * 397) + Id.GetHashCode();
|
||||
}
|
||||
if(__isset.AreaId)
|
||||
{
|
||||
hashcode = (hashcode * 397) + AreaId.GetHashCode();
|
||||
}
|
||||
if(__isset.SoundId)
|
||||
{
|
||||
hashcode = (hashcode * 397) + SoundId.GetHashCode();
|
||||
}
|
||||
}
|
||||
return hashcode;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var tmp3 = new StringBuilder("AmbientDataItem(");
|
||||
int tmp4 = 0;
|
||||
if(__isset.Id)
|
||||
{
|
||||
if(0 < tmp4++) { tmp3.Append(", "); }
|
||||
tmp3.Append("Id: ");
|
||||
Id.ToString(tmp3);
|
||||
}
|
||||
if(__isset.AreaId)
|
||||
{
|
||||
if(0 < tmp4++) { tmp3.Append(", "); }
|
||||
tmp3.Append("AreaId: ");
|
||||
AreaId.ToString(tmp3);
|
||||
}
|
||||
if(__isset.SoundId)
|
||||
{
|
||||
if(0 < tmp4++) { tmp3.Append(", "); }
|
||||
tmp3.Append("SoundId: ");
|
||||
SoundId.ToString(tmp3);
|
||||
}
|
||||
tmp3.Append(')');
|
||||
return tmp3.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 922d8ef1f3bf5924d8cdc069deb0143f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
Reference in New Issue
Block a user