Files
Cielonos/Assets/Scripts/MainGame/Items/Base/ExtenderBase.cs
SoulliesOfficial 649b7a5ddc 更新
2026-05-23 08:27:50 -04:00

175 lines
5.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Sirenix.OdinInspector;
using UnityEngine;
namespace Cielonos.MainGame.Inventory
{
/// <summary>
/// 扩展器基类:作为 PassiveEquipment 附着在指定类型的宿主道具上,为其提供额外能力。
/// <para>
/// 获取时自动在背包中查找第一个类型匹配的宿主并绑定;丢弃时自动解绑。
/// </para>
/// </summary>
public abstract class ExtenderBase : PassiveEquipmentBase
{
[ValueDropdown("GetHostTypeOptions")]
public Type hostType;
/// <summary>
/// 当前绑定的宿主道具。未绑定时为 null。
/// </summary>
public ItemBase Host { get; private set; }
/// <summary>
/// 当前扩展器是否已成功绑定到宿主。
/// </summary>
public bool IsAttached => Host != null;
public override void OnObtained()
{
if (hostType == null) throw new Exception("尚未对Host类型进行初始化检查子类OnObtained函数或者在Prefab中否设置了hostType");
base.OnObtained();
ItemBase host = FindHost();
if (host != null)
{
Attach(host);
}
else
{
Debug.LogWarning($"[{GetType().Name}] 背包中未找到类型为 {hostType} 的宿主道具,扩展器暂不生效。");
}
}
public override void OnDiscarded()
{
if (IsAttached)
{
Detach();
}
base.OnDiscarded();
}
/// <summary>
/// 将扩展器绑定到指定宿主。若已绑定到其它宿主,会先解绑。
/// </summary>
public void Attach(ItemBase host)
{
if (host == null)
{
Debug.LogWarning($"[{GetType().Name}] 尝试绑定到 null 宿主。");
return;
}
if (Host == host) return;
// 如果已绑定到别的宿主,先解绑
if (IsAttached)
{
Detach();
}
Host = host;
host.RegisterExtender(this);
OnAttached(host);
}
/// <summary>
/// 从当前宿主解绑。
/// </summary>
public void Detach()
{
if (!IsAttached) return;
ItemBase previousHost = Host;
previousHost.UnregisterExtender(this);
Host = null;
OnDetached(previousHost);
}
/// <summary>
/// 扩展器成功绑定到宿主后调用。子类在此订阅事件、修改数据或注入行为。
/// </summary>
/// <param name="host">已绑定的宿主道具实例。</param>
protected virtual void OnAttached(ItemBase host) { }
/// <summary>
/// 扩展器从宿主解绑后调用。子类在此清理事件订阅和还原修改。
/// </summary>
/// <param name="previousHost">之前绑定的宿主道具实例。</param>
protected virtual void OnDetached(ItemBase previousHost) { }
/// <summary>
/// 在背包中查找第一个类型匹配的宿主道具。
/// 默认搜索所有道具列表(主武器、辅助装备、被动装备)。
/// 子类可重写以自定义查找逻辑(如指定特定实例)。
/// </summary>
/// <returns>找到的宿主实例,不存在则返回 null。</returns>
protected virtual ItemBase FindHost()
{
var backpack = player.inventorySc.backpackSm;
foreach (var mainWeapon in backpack.mainWeapons.Where(mainWeapon => mainWeapon.GetType() == hostType))
{
return mainWeapon;
}
foreach (var support in backpack.supportEquipments.Where(support => support.GetType() == hostType))
{
return support;
}
foreach (var passive in backpack.passiveEquipments.Where(passive => passive.GetType() == hostType))
{
return passive;
}
return null;
}
#if UNITY_EDITOR
/// <summary>
/// 收集所有可作为宿主的具体道具类型MainWeaponBase、SupportEquipmentBase、PassiveEquipmentBase
/// 的非抽象子类,但排除 ExtenderBase 及其子类。
/// </summary>
private static IEnumerable<ValueDropdownItem<Type>> GetHostTypeOptions()
{
Type[] baseTypes =
{
typeof(MainWeaponBase),
typeof(SupportEquipmentBase),
typeof(PassiveEquipmentBase)
};
Type extenderType = typeof(ExtenderBase);
IEnumerable<Type> candidateTypes = Assembly.GetAssembly(typeof(ItemBase))
.GetTypes()
.Where(t => !t.IsAbstract && !t.IsGenericTypeDefinition)
.Where(t => baseTypes.Any(bt => bt.IsAssignableFrom(t)))
.Where(t => !extenderType.IsAssignableFrom(t))
.OrderBy(t => t.Name);
foreach (Type type in candidateTypes)
{
string category = GetCategoryLabel(type);
yield return new ValueDropdownItem<Type>($"{category}/{type.Name}", type);
}
}
private static string GetCategoryLabel(Type type)
{
if (typeof(MainWeaponBase).IsAssignableFrom(type)) return "MainWeapon";
if (typeof(SupportEquipmentBase).IsAssignableFrom(type)) return "SupportEquipment";
return "PassiveEquipment";
}
#endif
}
}