(client) feat:添加游玩时UI相关贴图,添加3d模型场景按钮,添加多级调色进度条,添加SVG图片包,添加事件定义以及管理器,添加音频管理器,定义部分怪物,添加通信协议定义;fix:修复维度切换错误,修复LogUI显示不正确 (#55)

Co-authored-by: m0_75251201 <m0_75251201@noreply.gitcode.com>
Reviewed-on: #55
This commit is contained in:
2025-09-03 19:59:22 +08:00
parent 450b15e4df
commit 78849e0cc5
208 changed files with 16296 additions and 2228 deletions

View File

@ -3,152 +3,22 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
// 未在提供代码段中使用,但保留以便与原始上下文保持一致
// 未在提供代码段中使用,但保留以便与原始上下文保持一致
using System.Xml.Linq;
// 未在提供代码段中使用,但保留以便与原始上下文保持一致
using UnityEngine;
using Formatting = Newtonsoft.Json.Formatting;
using UnityEngine.Networking;
// 未在提供代码段中使用,但保留以便与原始上下文保持一致
// 未在提供代码段中使用,但保留以便与原始上下文保持一致
namespace Configs
{
public static class ConfigProcessor
{
// 保存文件的默认文件夹路径
private const string FolderPath = "save";
/// <summary>
/// 初始化文件夹
/// </summary>
static ConfigProcessor()
{
if (!Directory.Exists(FolderPath)) Directory.CreateDirectory(FolderPath);
}
/// <summary>
/// 保存单个类为 JSON 文件
/// </summary>
/// <param name="obj">要保存的类对象</param>
/// <param name="fileName">可选的文件名(不包括扩展名)</param>
public static bool SaveFile<T>(T obj, string fileName = null)
{
try
{
// 如果未提供文件名,则使用类名作为文件名
if (string.IsNullOrEmpty(fileName)) fileName = typeof(T).Name;
// 构建完整的文件路径
var filePath = Path.Combine(FolderPath, fileName + ".json");
// 将对象序列化为 JSON 字符串
var jsonContent = JsonConvert.SerializeObject(obj, Formatting.Indented);
// 写入文件
File.WriteAllText(filePath, jsonContent);
Debug.Log($"Saved file: {filePath}");
return true;
}
catch (Exception ex)
{
Debug.LogError($"Failed to save file: {ex.Message}");
return false;
}
}
/// <summary>
/// 从 JSON 文件读取单个类
/// </summary>
/// <param name="fileName">文件名(不包括扩展名)</param>
public static T LoadFile<T>(string fileName)
{
try
{
// 构建完整的文件路径
var filePath = Path.Combine(FolderPath, fileName + ".json");
// 检查文件是否存在
if (!File.Exists(filePath))
{
Debug.LogError($"File not found: {filePath}");
return default;
}
// 读取文件内容
var jsonContent = File.ReadAllText(filePath);
// 反序列化为指定类型的对象
var obj = JsonConvert.DeserializeObject<T>(jsonContent);
Debug.Log($"Loaded file: {filePath}");
return obj;
}
catch (Exception ex)
{
Debug.LogError($"Failed to load file: {ex.Message}");
return default;
}
}
/// <summary>
/// 打包多个类并保存为一个存档文件
/// </summary>
/// <param name="archiveName">存档文件名(不包括扩展名)</param>
/// <param name="objects">要保存的类对象字典</param>
public static bool SaveArchive(string archiveName, Dictionary<string, object> objects)
{
try
{
// 构建完整的文件路径
var filePath = Path.Combine(FolderPath, archiveName + ".archive.json");
// 将字典中的对象序列化为 JSON
var jsonContent = JsonConvert.SerializeObject(objects, Formatting.Indented);
// 写入文件
File.WriteAllText(filePath, jsonContent);
Debug.Log($"Saved archive: {filePath}");
return true;
}
catch (Exception ex)
{
Debug.LogError($"Failed to save archive: {ex.Message}");
return false;
}
}
/// <summary>
/// 从存档文件中读取多个类
/// </summary>
/// <param name="archiveName">存档文件名(不包括扩展名)</param>
public static Dictionary<string, object> LoadArchive(string archiveName)
{
try
{
// 构建完整的文件路径
var filePath = Path.Combine(FolderPath, archiveName + ".archive.json");
// 检查文件是否存在
if (!File.Exists(filePath))
{
Debug.LogError($"Archive not found: {filePath}");
return null;
}
// 读取文件内容
var jsonContent = File.ReadAllText(filePath);
// 反序列化为字典
var objects = JsonConvert.DeserializeObject<Dictionary<string, object>>(jsonContent);
Debug.Log($"Loaded archive: {filePath}");
return objects;
}
catch (Exception ex)
{
Debug.LogError($"Failed to load archive: {ex.Message}");
return null;
}
}
/// <summary>
/// 获取指定路径下的所有xml文件
@ -161,29 +31,25 @@ namespace Configs
foreach (var path in paths)
{
try
{
// 检查目录是否存在
if (!Directory.Exists(path))
{
// **逻辑修改 1.1**: 将静默跳过改为记录警告,提供更友好的提示。
Debug.LogWarning($"警告: 指定路径不存在或无法访问 - {path}");
continue;
}
// 获取目录下的所有子文件夹
var subDirectories = Directory.GetDirectories(path);
// 遍历并收集每个子文件夹中的 XML 文件
foreach (var dir in subDirectories)
{
var xmlFiles = Directory.GetFiles(dir, "*.xml", SearchOption.AllDirectories);
xmlFilePaths.AddRange(xmlFiles);
}
// **逻辑修改 1.2**: 原始逻辑仅遍历子文件夹导致根路径下的XML文件被忽略。
// 现修改为直接获取当前路径及其所有子目录中的 XML 文件。
var xmlFiles = Directory.GetFiles(path, "*.xml", SearchOption.AllDirectories);
xmlFilePaths.AddRange(xmlFiles);
}
catch (Exception ex)
{
Debug.LogError($"加载文件时发生错误: {ex.Message}");
// 优化错误信息,明确是哪个路径出现问题
Debug.LogError($"获取路径 '{path}' 下的XML文件时发生错误: {ex.Message}");
}
}
@ -300,20 +166,19 @@ namespace Configs
}
// 检查文件是否存在
if (!System.IO.File.Exists(filePath))
if (!File.Exists(filePath))
{
Debug.LogError($"文件不存在: {filePath}");
return null;
}
byte[] bytes = null;
byte[] bytes;
try
{
// 使用 using 自动管理 FileStream 的生命周期
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
fs.Seek(0, SeekOrigin.Begin); // 将游标移动到文件开头(可选)
bytes = new byte[fs.Length]; // 创建一个字节数组来存储文件内容
fs.Read(bytes, 0, bytes.Length); // 读取文件内容到字节数组
}
@ -383,11 +248,93 @@ namespace Configs
}
catch (UnauthorizedAccessException ex)
{
// 可选:记录日志或忽略无权限目录
Console.WriteLine($"访问被拒绝: {ex.Message}");
// **逻辑修改 3**: 在 Unity 环境中,应使用 Debug.LogError 而非 Console.WriteLine 记录错误。
Debug.LogError($"访问目录 '{directoryPath}' 被拒绝: {ex.Message}");
}
return result;
}
/// <summary>
/// 根据文件路径推断音频类型。
/// </summary>
/// <param name="filePath">音频文件的完整路径。</param>
/// <returns>推断出的 AudioType如果无法推断则返回 AudioType.UNKNOWN。</returns>
private static AudioType GetAudioTypeFromFilePath(string filePath)
{
string ext = Path.GetExtension(filePath)?.ToLower(); // 获取扩展名并转小写
switch (ext)
{
case ".wav": return AudioType.WAV;
case ".mp3": return AudioType.MPEG;
case ".ogg": return AudioType.OGGVORBIS;
case ".aiff": return AudioType.AIFF;
// 可以根据需要添加更多常见的音频类型
default:
Debug.LogWarning($"警告: 未知音频文件类型 '{ext}' for file '{filePath}'. 尝试使用 AudioType.UNKNOWN.");
return AudioType.UNKNOWN; // 让Unity尝试自动检测但成功率可能不如指定类型高
}
}
/// <summary>
/// 从外部指定文件中异步加载音频。
/// 注意:此方法是异步的,需要使用 await 调用。在Unity主线程中调用以避免潜在的线程问题。
/// </summary>
/// <param name="filePath">音频文件的完整路径。</param>
/// <returns>Task其结果为加载成功的 AudioClip 对象,或加载失败时返回 null。</returns>
public static async Task<AudioClip> LoadAudioByIO(string filePath)
{
if (string.IsNullOrEmpty(filePath))
{
Debug.LogError("音频文件路径为空,请检查输入!");
return null;
}
if (!File.Exists(filePath))
{
Debug.LogError($"音频文件不存在: {filePath}");
return null;
}
// UnityWebRequest需要使用file://协议来访问本地文件
string uri = "file://" + Path.GetFullPath(filePath);
// 根据文件扩展名推断音频类型
AudioType audioType = GetAudioTypeFromFilePath(filePath);
using (UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(uri, audioType))
{
try
{
// 发送请求并等待完成
// await www.SendWebRequest(); 是核心,它会异步执行网络请求。
// 如果在Unity Editor中遇到“You are trying to load data from a www stream that had a non-OK status”等错误
// 可以检查文件路径和文件权限。
await www.SendWebRequest();
// 检查请求结果
// www.isNetworkError 或 www.isHttpError 在较新的Unity版本中已弃用
// 推荐使用 www.result。
if (www.result == UnityWebRequest.Result.ConnectionError || www.result == UnityWebRequest.Result.ProtocolError)
{
Debug.LogError($"加载音频文件 '{filePath}' 失败: {www.error}");
return null;
}
else
{
// 获取下载的AudioClip
AudioClip clip = DownloadHandlerAudioClip.GetContent(www);
if (clip == null)
{
Debug.LogError($"未能从文件 '{filePath}' 获取 AudioClip 内容,请检查文件是否损坏或格式是否支持 ({audioType} 类型).");
}
return clip;
}
}
catch (Exception e)
{
Debug.LogError($"处理音频文件 '{filePath}' 时发生异常: {e.Message}");
return null;
}
}
}
}
}
}