BITFALL/Assets/Artists/Scripts/Entities/EquipSelector/PlayerEquipSelector.cs

305 lines
10 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BITKit;
using BITKit.Entities;
using UnityEngine.InputSystem;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using BITFALL.Entities;
using BITFALL.Entities.Improvised;
using BITFALL.Entities.Inventory;
using BITFALL.Player.Inventory;
using BITKit.Entities.Player;
using Cysharp.Threading.Tasks;
using JetBrains.Annotations;
using UnityEditor;
using UnityEngine.InputSystem.Interactions;
using Debug = UnityEngine.Debug;
namespace BITFALL.Entities.Equipment
{
[CustomType(typeof(IPlayerEquipSelector))]
public class PlayerEquipSelector : EntityComponent,IPlayerEquipSelector
{
[Header(Constant.Header.InternalVariables)]
private readonly Dictionary<int, IBasicItem> equips=new();
public event Func<IBasicItem, bool> TryEquipFactory;
public event Action<IDictionary<int, IBasicItem>> OnUpdateEquip;
[Inject]
private IEntityInventory _inventory;
[Inject(true)]
private IKnockdown _knockdown;
[Inject]
private IHealth _health;
private IBasicItem currentEquip;
[Inject(true)]
private IEntityEquipment _equipment;
[Inject(true)]
private ImprovisedServiceInterface _improvisedService;
[Inject]
private IEntityEquipmentContainer _equipmentContainer;
private readonly DoubleBuffer<IBasicItem> _cachedItem=new();
private readonly List<int> _blockList=new();
public override void OnAwake()
{
_health.OnSetAlive += OnSetAlive;
if (_knockdown is not null)
{
_knockdown.OnKnockdown +=()=>
{
Equip(null);
};
}
if (_improvisedService is not null)
{
_improvisedService.OnEquipImprovisedItem += OnEquipImprovisedItem;
_improvisedService.OnUnEquipImprovisedItem += OnUnEquipImprovisedItem;
_improvisedService.OnTryEquipImprovisedItem += OnTryEquipImprovisedItem;
_improvisedService.OnTryUnEquipImprovisedItem += OnTryUnEquipImprovisedItem;
}
}
public override void OnStart()
{
base.OnStart();
_inventory.TryUseItemFactory += TryEquip;
_inventory.OnUsedItem += OnEquip;
_inventory.OnAdd += OnAdd;
_inventory.OnRemove += OnRemove;
}
private bool OnTryUnEquipImprovisedItem(IBasicItem arg)
{
return true;
}
private bool OnTryEquipImprovisedItem(IBasicItem arg)
{
return true;
}
private void OnUnEquipImprovisedItem(IBasicItem obj)
{
Equip(null);
if (_cachedItem.TryGetRelease(out var item))
{
Equip(item);
}
}
private void OnEquipImprovisedItem(IBasicItem obj)
{
if (currentEquip is not null)
{
_cachedItem.Release(currentEquip);
}
Equip(obj);
}
public void OnPrimary(InputAction.CallbackContext context)
{
if (context is not {interaction:PressInteraction ,performed:true}) return;
Equip(1);
}
public void OnSecondary(InputAction.CallbackContext context)
{
if (context is not {interaction:PressInteraction ,performed:true}) return;
Equip(2);
}
public void OnTertiary(InputAction.CallbackContext context)
{
if (context is not {interaction:PressInteraction ,performed:true}) return;
if (Equip(3) is false)
{
Equip(-1);
}
}
public void OnQuaternary(InputAction.CallbackContext context)
{
if (context is not {interaction:PressInteraction ,performed:true}) return;
Equip<EquipmentAsArmorPlate>();
}
public void OnHolster(InputAction.CallbackContext context)
{
if (context is not {interaction:PressInteraction ,performed:true}) return;
Equip(-1);
}
private void OnSetAlive(bool alive)
{
if (alive) return;
foreach (var x in equips.ToArray())
{
_inventory.Add(x.Value);
}
equips.Clear();
UpdateEquip();
Equip(-1);
}
private bool TryEquip(IBasicItem value)
{
if (_knockdown is not null && _knockdown.IsKnockdown) return false;
var asset = value.GetAssetable();
if (_equipment.IsSupportItem(value) is false) return false;
switch (asset)
{
case var _ when asset.TryGetProperty<EquipmentAsWeapon>(out _):
if (equips.TryAdd(1, value) || equips.TryAdd(2,value))
{
_equipment.EntryEquip(value);
UpdateEquip();
_improvisedService?.TryUnEquipImprovised(out _);
currentEquip = value;
_inventory.UseItem(value);
return true;
}
break;
case var _ when asset.TryGetProperty<EquipmentUseItem>(out _):
if (TryEquipFactory?.CastAsFunc().Any(x => x.Invoke(value)) is false) return false;
_equipment.EntryEquip(value);
_improvisedService?.TryUnEquipImprovised(out _);
if (currentEquip is not null)
{
_cachedItem.Release(currentEquip);
}
currentEquip = value;
return true;
}
return false;
}
public async void OnAdd(IBasicItem item)
{
if (_blockList.Contains(item.Id)) return;
if(currentEquip is not null && currentEquip.AddressablePath == item.AddressablePath)
{
if(equips.TryGetAny(x=>x.Value.AddressablePath == item.AddressablePath,out var pair))
{
equips.Remove(pair.Key);
UpdateEquip();
}
currentEquip = null;
_equipment.EntryEquip((IBasicItem)null);
}
else
{
try
{
for (var i = 0; i < 8; i++)
{
await UniTask.NextFrame();
}
if (_equipment.IsSupportItem(item) && item.GetAssetable().TryGetProperty<EquipmentAsWeapon>(out _))
{
_inventory.TryUseItem(item);
}
}
catch(OperationCanceledException){}
}
}
public void Throw(InputAction.CallbackContext context)
{
switch (context)
{
case { interaction: HoldInteraction, performed: true }:
if (currentEquip is null) return;
if (equips.TryGetAny(x => x.Value.AddressablePath == currentEquip.AddressablePath, out var pair))
{
if (_inventory.DropOrSpawn(currentEquip))
{
equips.Remove(pair.Key);
_equipment.EntryEquip((IBasicItem)null);
currentEquip = null;
UpdateEquip();
}
}
break;
case { interaction: TapInteraction, performed: true }:
Equip<EquipmentAsThrow>();
break;
}
}
public void OnRemove(IBasicItem item)
{
if (_equipment.IsSupportItem(item) is false)
{
UpdateEquip();
}
_blockList.Add(item.Id);
}
private void OnEquip(IBasicItem obj)
{
_blockList.Remove(obj.Id);
}
private void UpdateEquip()
{
OnUpdateEquip?.Invoke(new Dictionary<int, IBasicItem>(equips));
_cachedItem.Clear();
}
public bool TryDeEquip(IBasicItem item)
{
if (item is null) return false;
if (equips.Any(x => x.Value.AddressablePath == item.AddressablePath) is false) return false;
var index = equips.Single(x=>x.Value.AddressablePath==item.AddressablePath).Key;
if (equips.TryRemove(index) is false) return false;
if (!_inventory.Add(item)) return false;
UpdateEquip();
return true;
}
public bool Cancel()
{
if (currentEquip is null) return false;
if (_cachedItem.TryGetRelease(out var item))
{
Equip(item);
return true;
}
Equip(null);
return false;
}
private void Equip(IBasicItem item)
{
_equipment.EntryEquip(item);
currentEquip = item;
}
private bool Equip(int index)
{
if (!equips.TryGetValue(index, out var x) && index is not -1) return false;
if (_knockdown is not null && _knockdown.IsKnockdown) return false;
currentEquip = x;
_improvisedService?.TryUnEquipImprovised(out _);
_equipment.EntryEquip(x);
return true;
}
private bool Equip<T>() where T : IEquipmentSlot
{
if (!_equipmentContainer.Equipment.TryGetAny(x => x.Key is T, out var item)) return false;
//if (!_inventory.TryUseItem(item.Value)) return false;
_improvisedService.TryUnEquipImprovised(out _);
Equip(item.Value);
return true;
}
}
}