(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

@ -1,181 +1,154 @@
using Data;
using System;
using System.Collections.Generic;
using System.Reflection;
using Data;
using EventWorkClass;
using Utils;
using UnityEngine;
using EventType = Data.EventType;
namespace Managers
{
// 新增私有结构体,用于在事件队列中存储事件定义及其运行时上下文
public struct EventPayload // Make it public if EventManager exposes it directly
/// <summary>
/// 事件管理器,负责事件的加载、注册和执行。
/// 遵循单例模式,并在启动流程中扮演一个管理器角色。
/// </summary>
class EventManager : Singleton<EventManager>, ILaunchManager
{
public string DimensionId;
public EventDef EventDefinition;
public Vector3 Position; // 适用于 Character, Bullet, Pickup, DefaultEntity
public Vector3 Direction; // 仅适用于 Bullet
public Entity.Entity SourceEntity; // 仅适用于 Bullet (发射源)
public Vector3Int GridPosition; // 仅适用于 Building
}
public class EventManager : Utils.MonoSingleton<EventManager>
{
private Queue<EventPayload> _eventQueue = new Queue<EventPayload>();
private EventManager()
{
/* Private constructor for singleton */
}
// ===================================
// 公共入队方法
// ===================================
public void EnqueueCharacterSpawnEvent(string dimensionId, EventDef eventDef, Vector3 pos)
{
if (eventDef == null || eventDef.eventType != EventType.SpawnCharacter ||
eventDef.entityDef_Character == null)
{
Debug.LogError(
$"EnqueueCharacterSpawnEvent: Invalid EventDef, mismatched EventType ({eventDef?.eventType}), or missing characterDef for event '{eventDef?.defName ?? "Unknown"}'.");
return;
}
_eventQueue.Enqueue(new EventPayload
{
DimensionId = dimensionId,
EventDefinition = eventDef,
Position = pos,
});
Debug.Log($"Event '{eventDef.defName}' (SpawnCharacter) enqueued for dimension {dimensionId} at {pos}.");
}
public void EnqueueBuildingSpawnEvent(string dimensionId, EventDef eventDef, Vector3Int gridPos)
{
if (eventDef == null || eventDef.eventType != EventType.SpawnBuilding ||
eventDef.entityDef_Building == null)
{
Debug.LogError(
$"EnqueueBuildingSpawnEvent: Invalid EventDef, mismatched EventType ({eventDef?.eventType}), or missing buildingDef for event '{eventDef?.defName ?? "Unknown"}'.");
return;
}
_eventQueue.Enqueue(new EventPayload
{
DimensionId = dimensionId,
EventDefinition = eventDef,
GridPosition = gridPos,
});
Debug.Log($"Event '{eventDef.defName}' (SpawnBuilding) enqueued for dimension {dimensionId} at grid {gridPos}.");
}
public void EnqueueBulletSpawnEvent(string dimensionId, EventDef eventDef, Vector3 pos, Vector3 dir,
Entity.Entity source = null)
{
if (eventDef == null || eventDef.eventType != EventType.SpawnBullet || eventDef.entityDef_Bullet == null)
{
Debug.LogError(
$"EnqueueBulletSpawnEvent: Invalid EventDef, mismatched EventType ({eventDef?.eventType}), or missing bulletDef for event '{eventDef?.defName ?? "Unknown"}'.");
return;
}
_eventQueue.Enqueue(new EventPayload
{
DimensionId = dimensionId,
EventDefinition = eventDef,
Position = pos,
Direction = dir,
SourceEntity = source,
});
Debug.Log($"Event '{eventDef.defName}' (SpawnBullet) enqueued for dimension {dimensionId} at {pos}, dir {dir}.");
}
public void EnqueuePickupSpawnEvent(string dimensionId, EventDef eventDef, Vector3 pos)
{
if (eventDef == null || eventDef.eventType != EventType.SpawnPickup || eventDef.entityDef_Pickup == null)
{
Debug.LogError(
$"EnqueuePickupSpawnEvent: Invalid EventDef, mismatched EventType ({eventDef?.eventType}), or missing itemDef for event '{eventDef?.defName ?? "Unknown"}'.");
return;
}
_eventQueue.Enqueue(new EventPayload
{
DimensionId = dimensionId,
EventDefinition = eventDef,
Position = pos,
});
Debug.Log($"Event '{eventDef.defName}' (SpawnPickup) enqueued for dimension {dimensionId} at {pos}.");
}
public void EnqueueDefaultEntitySpawnEvent(string dimensionId, EventDef eventDef, Vector3 pos)
{
if (eventDef == null || eventDef.eventType != EventType.SpawnDefaultEntity)
{
Debug.LogError(
$"EnqueueDefaultEntitySpawnEvent: Invalid EventDef or mismatched EventType ({eventDef?.eventType}) for event '{eventDef?.defName ?? "Unknown"}'.");
return;
}
_eventQueue.Enqueue(new EventPayload
{
DimensionId = dimensionId,
EventDefinition = eventDef,
Position = pos,
});
Debug.Log($"Event '{eventDef.defName}' (SpawnDefaultEntity) enqueued for dimension {dimensionId} at {pos}.");
}
// ===================================
// 事件处理方法
// ===================================
/// <summary>
/// 处理所有在队列中的待处理事件
/// 存储所有已加载的事件定义,键为事件名称,值为对应的事件工作类实例
/// </summary>
public void ProcessEvents()
public Dictionary<string, EventWorkClassBase> EventDefs { get; private set; } = null;
/// <summary>
/// 获取当前加载步骤的描述,用于启动流程的进度显示。
/// </summary>
public string StepDescription => "正在载入事件";
/// <summary>
/// 初始化事件管理器,从定义管理器中加载所有事件定义并实例化其工作类。
/// </summary>
public void Init()
{
while (_eventQueue.Count > 0)
// 如果事件定义已经加载,则直接返回,避免重复初始化。
if (EventDefs != null)
return;
var defs = DefineManager.Instance.QueryDefinesByType<EventDef>();
EventDefs = new Dictionary<string, EventWorkClassBase>();
foreach (var def in defs)
{
EventPayload eventData = _eventQueue.Dequeue();
if (!Program.Instance.GetDimension(eventData.DimensionId))
if (EventDefs.ContainsKey(def.defName))
{
Debug.LogWarning(
$"Event '{eventData.EventDefinition.defName}' for dimension {eventData.DimensionId} dropped as dimension is no longer active.");
Debug.LogWarning($"警告:事件名称重复,已跳过加载名称为 {def.defName} 的事件定义。");
continue;
}
// 核心:调用 EntityManage.Instance 的现有公共方法
switch (eventData.EventDefinition.eventType)
var eventWorker = GetAndInstantiateEventWorker(def.workClass);
if (eventWorker == null)
{
case EventType.SpawnCharacter:
EntityManage.Instance.GenerateEntity(eventData.DimensionId,
eventData.EventDefinition.entityDef_Character, eventData.Position);
break;
case EventType.SpawnBuilding:
EntityManage.Instance.GenerateBuildingEntity(eventData.DimensionId,
eventData.EventDefinition.entityDef_Building, eventData.GridPosition);
break;
case EventType.SpawnBullet:
EntityManage.Instance.GenerateBulletEntity(eventData.DimensionId,
eventData.EventDefinition.entityDef_Bullet, eventData.Position, eventData.Direction,
eventData.SourceEntity);
break;
case EventType.SpawnPickup:
EntityManage.Instance.GeneratePickupEntity(eventData.DimensionId,
eventData.EventDefinition.entityDef_Pickup, eventData.Position);
break;
case EventType.SpawnDefaultEntity:
EntityManage.Instance.GenerateDefaultEntity(eventData.DimensionId, eventData.Position);
break;
case EventType.None:
default:
Debug.LogWarning(
$"EventManager: Unhandled or invalid event type: {eventData.EventDefinition.eventType} for event '{eventData.EventDefinition.defName}'.");
break;
Debug.LogWarning($"警告:未能找到或实例化名称为 '{def.workClass}' 的事件工作类,已跳过加载名称为 '{def.defName}' 的事件定义。");
continue;
}
eventWorker.Init(def.value);
EventDefs.Add(def.defName, eventWorker);
}
Debug.Log($"事件管理器初始化完成,共载入 {EventDefs.Count} 个事件。");
}
/// <summary>
/// 清理事件管理器,释放所有已加载的事件定义。
/// </summary>
public void Clear()
{
EventDefs = null;
Debug.Log("事件管理器已清理。");
}
/// <summary>
/// 执行指定名称的事件。
/// </summary>
/// <param name="eventName">要执行的事件的名称。</param>
/// <param name="dimensionID">事件执行的维度ID如果为null将使用当前焦点的维度ID。</param>
public void Action(string eventName, string dimensionID = null)
{
if (EventDefs == null)
{
Debug.LogError($"错误:事件管理器尚未初始化或已被清理。无法执行事件 '{eventName}'。");
return;
}
if (!EventDefs.ContainsKey(eventName))
{
Debug.LogWarning($"警告:未能找到名称为 '{eventName}' 的事件定义,已跳过执行该事件。");
return;
}
// 假设 Program.Instance 和 FocusedDimensionId 存在且可访问。
// 如果 dimensionID 为 null则使用当前焦点维度ID。
dimensionID ??= Program.Instance.FocusedDimensionId;
EventDefs[eventName].Run(dimensionID);
}
/// <summary>
/// 根据类名从指定命名空间和程序集下获取并实例化一个 <see cref="EventWorkClassBase"/> 的子类。
/// </summary>
/// <param name="className">要实例化的类的短名称(不包含命名空间)。</param>
/// <param name="targetNamespace">目标类所在的完整命名空间。</param>
/// <param name="assemblyToSearch">要搜索的程序集。如果为 null将搜索 <see cref="EventWorkClassBase"/> 所在的程序集。</param>
/// <returns>实例化后的 <see cref="EventWorkClassBase"/> 对象,如果找不到或不符合条件则返回 null。</returns>
public static EventWorkClassBase GetAndInstantiateEventWorker(
string className,
string targetNamespace = "EventWorkClass", // 默认命名空间
Assembly assemblyToSearch = null) // 默认程序集
{
// 1. 确定要搜索的程序集。
if (assemblyToSearch == null)
{
// 默认从 EventWorkClassBase 所在的程序集查找,通常其实现类也会在这个程序集。
assemblyToSearch = typeof(EventWorkClassBase).Assembly;
}
// 2. 构造完整的类型名称。
string fullTypeName = $"{targetNamespace}.{className}";
Type targetType = null;
// 3. 尝试直接从程序集获取类型。
targetType = assemblyToSearch.GetType(fullTypeName);
// 4. 进行类型检查。
if (targetType == null)
{
Debug.LogError($"错误:在程序集 '{assemblyToSearch.FullName}' 的命名空间 '{targetNamespace}' 中未找到类 '{className}'。");
return null;
}
// 检查是否是 EventWorkClassBase 的子类。
if (!typeof(EventWorkClassBase).IsAssignableFrom(targetType))
{
Debug.LogError($"错误:类 '{fullTypeName}' 不是 '{typeof(EventWorkClassBase).FullName}' 的子类。");
return null;
}
// 检查是否可以实例化(非抽象类,非接口)。
if (targetType.IsAbstract || targetType.IsInterface)
{
Debug.LogError($"错误:类 '{fullTypeName}' 是抽象类或接口,不能直接实例化。");
return null;
}
// 5. 实例化对象。
try
{
// 使用 Activator.CreateInstance 实例化对象。它默认调用无参公共构造函数。
object instance = Activator.CreateInstance(targetType);
return instance as EventWorkClassBase;
}
catch (MissingMethodException ex)
{
Debug.LogError($"错误:类 '{fullTypeName}' 没有公共的无参构造函数。详情: {ex.Message}");
return null;
}
catch (Exception ex)
{
Debug.LogError($"实例化类 '{fullTypeName}' 时发生未知错误。详情: {ex.Message}");
return null;
}
}
protected override void OnStart()
{
throw new System.NotImplementedException();
}
}
}
}