1
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using BITKit.Modification;
|
||||
using UnityEngine;
|
||||
// ReSharper disable ConvertToAutoProperty
|
||||
|
||||
@@ -12,6 +13,12 @@ namespace BITFALL.Cosmetic
|
||||
[SerializeField] private Texture texture;
|
||||
public Texture Texture => texture;
|
||||
}
|
||||
[Serializable]
|
||||
public struct CosmeticModelContent:ICosmeticContent
|
||||
{
|
||||
[SerializeField] private GameObject model;
|
||||
public GameObject Model => model;
|
||||
}
|
||||
public class AssetableCosmetic : ScriptableObject,ICosmetic
|
||||
{
|
||||
[SerializeField] private ulong id;
|
||||
@@ -19,12 +26,15 @@ namespace BITFALL.Cosmetic
|
||||
[SerializeField] private Sprite icon;
|
||||
[SerializeReference, SubclassSelector] private ICosmeticType type;
|
||||
[SerializeReference, SubclassSelector] private ICosmeticContent[] contents;
|
||||
|
||||
[SerializeReference, SubclassSelector] private IModifyElement[] require;
|
||||
[SerializeReference, SubclassSelector] private IModifyElement[] incompatible;
|
||||
public Sprite Icon => icon;
|
||||
|
||||
public string AddressablePath=> addressablePath;
|
||||
public ulong Id => id;
|
||||
public ICosmeticType Type=> type;
|
||||
public ICosmeticContent[] Contents=> contents;
|
||||
public IModifyElement[] Require=> require;
|
||||
public IModifyElement[] Incompatible=> incompatible;
|
||||
}
|
||||
}
|
||||
|
61
Assets/Artists/Scripts/CosmeticInventory/CosmeticService.cs
Normal file
61
Assets/Artists/Scripts/CosmeticInventory/CosmeticService.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BITKit.Modification;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BITFALL.Cosmetic
|
||||
{
|
||||
[Serializable]
|
||||
public struct CosmeticServiceSingleton:ICosmeticService
|
||||
{
|
||||
public ICosmetic[] Cosmetics=>CosmeticService.Singleton.Cosmetics;
|
||||
public event Action OnCosmeticsChanged
|
||||
{
|
||||
add => CosmeticService.Singleton.OnCosmeticsChanged += value;
|
||||
remove => CosmeticService.Singleton.OnCosmeticsChanged -= value;
|
||||
}
|
||||
|
||||
public IDictionary<IModifyElement, object> Modifies { get; set; }
|
||||
public IDictionary<IModifyElement, object> Modified { get; set; }
|
||||
public void Add(IModifyElement modify, object obj)=>CosmeticService.Singleton.Add(modify,obj);
|
||||
|
||||
public void Remove(IModifyElement modify, out object obj)=>CosmeticService.Singleton.Remove(modify,out obj);
|
||||
}
|
||||
public class CosmeticService : MonoBehaviour,ICosmeticService
|
||||
{
|
||||
internal static ICosmeticService Singleton { get; private set; }
|
||||
|
||||
[SerializeField] private AssetableCosmetic[] initialCosmetics;
|
||||
public ICosmetic[] Cosmetics { get; set; } = Array.Empty<ICosmetic>();
|
||||
|
||||
public event Action OnCosmeticsChanged;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
Singleton = this;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
Cosmetics = initialCosmetics.OfType<ICosmetic>().ToArray();
|
||||
OnCosmeticsChanged?.Invoke();
|
||||
}
|
||||
private readonly IModifyManager _modifyManager = new ModifyManager();
|
||||
public IDictionary<IModifyElement, object> Modifies => _modifyManager.Modifies;
|
||||
public IDictionary<IModifyElement, object> Modified => _modifyManager.Modified;
|
||||
|
||||
public void Add(IModifyElement modify, object obj)
|
||||
{
|
||||
_modifyManager.Add(modify, obj);
|
||||
OnCosmeticsChanged?.Invoke();
|
||||
}
|
||||
public void Remove(IModifyElement modify, out object obj)
|
||||
{
|
||||
_modifyManager.Remove(modify, out obj);
|
||||
OnCosmeticsChanged?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BITFALL.Cosmetic;
|
||||
using BITKit;
|
||||
using BITKit.Entities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BITFALL.Entities.Cosmetic
|
||||
{
|
||||
public class CosmeticModelBehaviour : EntityBehavior
|
||||
{
|
||||
[Inject(true)] private ICosmeticService _cosmeticService;
|
||||
[SerializeField] private SkinnedMeshRenderer[] currentRenderers;
|
||||
[SerializeField] private Transform armature;
|
||||
[SerializeField] private Transform meshRoot;
|
||||
public override void OnAwake()
|
||||
{
|
||||
if (_cosmeticService is null) return;
|
||||
|
||||
_cosmeticService.OnCosmeticsChanged += OnCosmeticsChanged;
|
||||
destroyCancellationToken.Register(() => _cosmeticService.OnCosmeticsChanged -= OnCosmeticsChanged);
|
||||
}
|
||||
|
||||
private void OnCosmeticsChanged()
|
||||
{
|
||||
foreach (var cosmetic in _cosmeticService.Cosmetics)
|
||||
{
|
||||
foreach (var content in cosmetic.Contents.OfType<CosmeticModelContent>())
|
||||
{
|
||||
foreach (var _renderer in currentRenderers)
|
||||
{
|
||||
Destroy(_renderer);
|
||||
}
|
||||
var instance = Instantiate(content.Model, armature);
|
||||
currentRenderers = instance.GetComponentsInChildren<SkinnedMeshRenderer>(true);
|
||||
TransferSkinnedMeshes(currentRenderers, meshRoot, armature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void TransferSkinnedMeshes(SkinnedMeshRenderer[] skinnedMeshRenderersList, Transform newParent, Transform newArmature)
|
||||
{
|
||||
foreach (var t in skinnedMeshRenderersList)
|
||||
{
|
||||
var cachedRootBoneName = t.rootBone.name;
|
||||
var newBones = new Transform[t.bones.Length];
|
||||
for (var x = 0; x < t.bones.Length; x++)
|
||||
foreach (var newBone in newArmature.GetComponentsInChildren<Transform>(true))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (newBone.name == t.bones[x].name)
|
||||
{
|
||||
newBones[x] = newBone;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BIT4Log.LogException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var matchingRootBone = GetRootBoneByName(newArmature, cachedRootBoneName);
|
||||
t.rootBone = matchingRootBone != null ? matchingRootBone : newArmature.transform;
|
||||
t.bones = newBones;
|
||||
Transform transform;
|
||||
(transform = t.transform).SetParent(newParent);
|
||||
transform.localPosition = Vector3.zero;
|
||||
}
|
||||
|
||||
}
|
||||
private static Transform GetRootBoneByName(Component parentTransform, string name)
|
||||
{
|
||||
return parentTransform.GetComponentsInChildren<Transform>().FirstOrDefault(transformChild => transformChild.name == name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -18,7 +19,10 @@ namespace BITFALL.Entities.Cosmetic
|
||||
public override void OnAwake()
|
||||
{
|
||||
if (_cosmeticService is not null)
|
||||
{
|
||||
_cosmeticService.OnCosmeticsChanged += OnCosmeticsChanged;
|
||||
destroyCancellationToken.Register(() => _cosmeticService.OnCosmeticsChanged -= OnCosmeticsChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCosmeticsChanged()
|
||||
|
@@ -13,24 +13,13 @@ using Object = UnityEngine.Object;
|
||||
|
||||
namespace BITFALL.Entities.Cosmetic
|
||||
{
|
||||
[CustomType(typeof(ICosmeticService))]
|
||||
public class EntityCosmeticService : EntityBehavior,ICosmeticService
|
||||
public class EntityCosmeticService : EntityBehavior
|
||||
{
|
||||
[SerializeReference, SubclassSelector] private ISteamService steamService;
|
||||
|
||||
public ICosmetic[] Cosmetics { get; private set; }
|
||||
public event Action OnCosmeticsChanged;
|
||||
public override async void OnStart()
|
||||
[SerializeReference, SubclassSelector] private ICosmeticService cosmeticService;
|
||||
public override void Initialize(IEntity _entity)
|
||||
{
|
||||
base.OnStart();var items =await steamService.GetInventoryItemDefsAsync(destroyCancellationToken);
|
||||
List<ICosmetic> cosmetics=new List<ICosmetic>();
|
||||
foreach (var x in items.Select(x=>YooAssets.LoadAssetAsync<Object>(x.AddressablePath) ))
|
||||
{
|
||||
x.WaitForAsyncComplete();
|
||||
cosmetics.Add(x.AssetObject as ICosmetic);
|
||||
}
|
||||
Cosmetics = cosmetics.ToArray();
|
||||
OnCosmeticsChanged?.Invoke();
|
||||
base.Initialize(_entity);
|
||||
_entity.As<Entity>().AddService<ICosmeticService>(cosmeticService);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,11 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BITFALL.Cosmetic;
|
||||
using BITKit;
|
||||
using BITKit.IO;
|
||||
using BITKit.Modification;
|
||||
using BITKit.UX;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
@@ -29,20 +31,43 @@ namespace BITFALL.UX
|
||||
|
||||
Rebuild();
|
||||
}
|
||||
private async void Rebuild()
|
||||
private void Rebuild()
|
||||
{
|
||||
_cosmeticsContainer.Clear();
|
||||
|
||||
var modified = _cosmeticService.Modified.Values.ToArray();
|
||||
|
||||
foreach (var cosmetic in _cosmeticService.Cosmetics)
|
||||
{
|
||||
var assetHandle = YooAssets.LoadAssetAsync(cosmetic.AddressablePath);
|
||||
await assetHandle;
|
||||
assetHandle.WaitForAsyncComplete();
|
||||
if(destroyCancellationToken.IsCancellationRequested) return;
|
||||
|
||||
var so = assetHandle.AssetObject.As<AssetableCosmetic>();
|
||||
var instance =new UXContainer(_cosmeticsContainer.Create(cosmeticsTemplate)) ;
|
||||
instance.icon.style.backgroundImage = new StyleBackground(so.Icon);
|
||||
instance.contextLabel.text = so.name;
|
||||
|
||||
if(modified.Contains(cosmetic))
|
||||
{
|
||||
instance.visualElement.AddToClassList("--toggled");
|
||||
}
|
||||
|
||||
instance.button.clicked += () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
_cosmeticService.Add(so.Type, cosmetic);
|
||||
}
|
||||
catch (NotRequireModifyException e)
|
||||
{
|
||||
Alert.Print("需要前置",e.Message);
|
||||
}
|
||||
catch (IncompatibleModifyException e)
|
||||
{
|
||||
Alert.Print("不兼容的修改",e.Message);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user