(client) feat:添加事件定义,定义部分怪物

This commit is contained in:
m0_75251201
2025-09-03 18:13:29 +08:00
parent ce04c8cec8
commit eb9cf415f2
79 changed files with 4666 additions and 4981 deletions

View File

@ -51,31 +51,44 @@ namespace Managers
/// <summary> 默认实体的预制体,用于生成失败时的回退。 </summary>
public EntityPrefab defaultEntityPrefab;
public EntityPrefab[] GetAllEntities(string dimensionId)
{
if (!_dimensionFactionEntities.ContainsKey(dimensionId))
{
Debug.LogWarning($"实体管理器:尝试在维度 '{dimensionId}' 中查找实体,但其内部存储未初始化。");
return null;
}
// 获取对应维度的内层字典
var factionEntitiesForDimension = _dimensionFactionEntities[dimensionId];
// 使用 LINQ 的 SelectMany 方法来扁平化所有 LinkedList 中的 EntityPrefab
return factionEntitiesForDimension.Values // 获取所有 LinkedList<EntityPrefab> 的集合
.SelectMany(linkedList => linkedList) // 将每个 LinkedList 中的元素展开到一个单一的序列中
.ToArray(); // 将该序列转换为一个数组
}
/// <summary>
/// 在指定维度中,根据派系键查找所有实体。
/// </summary>
/// <param name="dimensionId">维度的唯一标识符。</param>
/// <param name="factionKey">派系键。</param>
/// <returns>指定派系下的实体列表,如果未找到则返回空列表。</returns>
public LinkedList<EntityPrefab> FindEntitiesByFaction(string dimensionId, string factionKey)
public EntityPrefab[] FindEntitiesByFaction(string dimensionId, string factionKey)
{
// 如果在场景加载前或维度未在Program中注册_dimensionFactionEntities可能还没有该维度ID的条目。
if (!_dimensionFactionEntities.ContainsKey(dimensionId))
{
Debug.LogWarning($"实体管理器:尝试在维度 '{dimensionId}' 中查找实体,但其内部存储未初始化。");
return new LinkedList<EntityPrefab>();
return null;
}
if (_dimensionFactionEntities.TryGetValue(dimensionId, out var factionDict))
{
if (factionDict.TryGetValue(factionKey, out var entities))
{
return entities;
return entities.ToArray();
}
}
return new LinkedList<EntityPrefab>(); // 如果未找到,返回一个空列表
return null; // 如果未找到,返回一个空列表
}
/// <summary>

View File

@ -1,75 +1,154 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Data;
using Entity;
using Prefab;
using UnityEngine;
using EventWorkClass;
using Utils;
using Random = System.Random;
using UnityEngine;
namespace Managers
{
class EventManager:Singleton<EventManager>,ILaunchManager
/// <summary>
/// 事件管理器,负责事件的加载、注册和执行。
/// 遵循单例模式,并在启动流程中扮演一个管理器角色。
/// </summary>
class EventManager : Singleton<EventManager>, ILaunchManager
{
private static Random _random = new();
public EventDef[] EventDefs { get; private set; }
/// <summary>
/// 存储所有已加载的事件定义,键为事件名称,值为对应的事件工作类实例。
/// </summary>
public Dictionary<string, EventWorkClassBase> EventDefs { get; private set; } = null;
/// <summary>
/// 获取当前加载步骤的描述,用于启动流程的进度显示。
/// </summary>
public string StepDescription => "正在载入事件";
/// <summary>
/// 初始化事件管理器,从定义管理器中加载所有事件定义并实例化其工作类。
/// </summary>
public void Init()
{
if(EventDefs!=null)
// 如果事件定义已经加载,则直接返回,避免重复初始化。
if (EventDefs != null)
return;
EventDefs = DefineManager.Instance.QueryDefinesByType<EventDef>();
var defs = DefineManager.Instance.QueryDefinesByType<EventDef>();
EventDefs = new Dictionary<string, EventWorkClassBase>();
foreach (var def in defs)
{
if (EventDefs.ContainsKey(def.defName))
{
Debug.LogWarning($"警告:事件名称重复,已跳过加载名称为 {def.defName} 的事件定义。");
continue;
}
var eventWorker = GetAndInstantiateEventWorker(def.workClass);
if (eventWorker == null)
{
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("事件管理器已清理。");
}
public static void ExecuteEvent(EventDef eventDef)
/// <summary>
/// 执行指定名称的事件。
/// </summary>
/// <param name="eventName">要执行的事件的名称。</param>
/// <param name="dimensionID">事件执行的维度ID如果为null将使用当前焦点的维度ID。</param>
public void Action(string eventName, string dimensionID = null)
{
if(eventDef == null)
if (EventDefs == null)
{
Debug.LogError($"错误:事件管理器尚未初始化或已被清理。无法执行事件 '{eventName}'。");
return;
if (eventDef.hediffEvent != null)
{
var entityList = EntityManage.Instance.FindEntitiesByFaction(Program.Instance.FocusedDimensionId,
eventDef.hediffEvent.affiliation.defName);
List<Entity.Entity> filteredEntitiesTraditional = new();
foreach (var prefab in entityList)
{
var entity = prefab.entity;
if (entity is Character || entity is Monster)
{
filteredEntitiesTraditional.Add(entity);
}
}
var selectedElements = SelectRandomElements_FisherYates(filteredEntitiesTraditional, eventDef.hediffEvent.specificPawnCount);
foreach (var selectedElement in selectedElements)
{
}
}
if (!EventDefs.ContainsKey(eventName))
{
Debug.LogWarning($"警告:未能找到名称为 '{eventName}' 的事件定义,已跳过执行该事件。");
return;
}
// 假设 Program.Instance 和 FocusedDimensionId 存在且可访问。
// 如果 dimensionID 为 null则使用当前焦点维度ID。
dimensionID ??= Program.Instance.FocusedDimensionId;
EventDefs[eventName].Run(dimensionID);
}
public static List<T> SelectRandomElements_FisherYates<T>(List<T> sourceList, int count)
/// <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) // 默认程序集
{
if (sourceList == null) throw new ArgumentNullException(nameof(sourceList));
if (count < 0) throw new ArgumentOutOfRangeException(nameof(count), "Count cannot be negative.");
if (count == 0) return new List<T>();
if (count >= sourceList.Count) return new List<T>(sourceList); // 如果n大于等于列表大小则返回所有元素副本
List<T> result = new List<T>(count); // 预分配容量
List<T> temp = new List<T>(sourceList); // 创建一个副本以避免修改原始列表
int n = temp.Count;
for (int i = 0; i < count; i++)
// 1. 确定要搜索的程序集。
if (assemblyToSearch == null)
{
int k = _random.Next(i, n);
result.Add(temp[k]);
(temp[k], temp[i]) = (temp[i], temp[k]);
// 默认从 EventWorkClassBase 所在的程序集查找,通常其实现类也会在这个程序集。
assemblyToSearch = typeof(EventWorkClassBase).Assembly;
}
return result;
}
// 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;
}
}
}
}
}