Initial Commit

This commit is contained in:
Simeon Radivoev 2022-02-12 12:53:50 +02:00
commit ee5c2f922d
Signed by: simeonradivoev
GPG key ID: 7611A451D2A5D37A
2255 changed files with 547750 additions and 0 deletions

View file

@ -0,0 +1,33 @@
using Events;
using Items;
using Unity.Entities;
using UnityEngine;
namespace DefaultNamespace
{
public class GrenadeUseSystem : ItemUseSystemAbstract<GrenadeItem>
{
public override ItemUseFlags Flags => ItemUseFlags.UseOnlyInteractive;
public override ItemUseType UseType => ItemUseType.Grenade;
public override bool IsAdditiveUsage => true;
protected override void Use(GrenadeItem prefab, ref ItemData itemData, Entity user, Entity inventory)
{
itemData.Amount--;
entityManager.PostEntityEvent<InventoryDirtyEventData>(inventory);
entityManager.PostEntityEvent(user, new FireGrenadeEvent { GrenadePrefab = itemData.Item });
}
protected override bool Validate(GrenadeItem prefab, Entity user, Entity inventory)
{
return true;
}
public override Sprite GetItemIcon(GrenadeItem prefab)
{
return null;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ef39a98683c52864d846421dc14c9401
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,48 @@
using Events;
using Items;
using Unity.Entities;
using UnityEngine;
namespace DefaultNamespace
{
public class HealthPackUseSystem : ItemUseSystemAbstract<HealthKitItem>
{
public override ItemUseFlags Flags => ItemUseFlags.UseOnlyInteractive | ItemUseFlags.UseOnlyGrounded;
public override ItemUseType UseType => ItemUseType.HealthPack;
public override bool IsAdditiveUsage => false;
protected override void Use(HealthKitItem prefab, ref ItemData itemData, Entity user, Entity inventory)
{
var facade = entityManager.GetComponentObject<PlayerFacade>(user);
var actorData = entityManager.GetComponentData<ActorData>(user);
actorData.Health = Mathf.Min(actorData.Health + prefab.Health, facade.MaxHealth);
itemData.Amount--;
entityManager.SetComponentData(user, actorData);
entityManager.PostEntityEvent<InventoryDirtyEventData>(user);
}
protected override bool Validate(HealthKitItem prefab, Entity user, Entity inventory)
{
if (!entityManager.HasComponent<ActorData>(user))
{
return false;
}
var playerFacade = entityManager.GetComponentObject<PlayerFacade>(user);
if (playerFacade == null)
{
return false;
}
var actorData = entityManager.GetComponentData<ActorData>(user);
return actorData.Health < playerFacade.MaxHealth;
}
public override Sprite GetItemIcon(HealthKitItem prefab)
{
return prefab.UseItemIcon;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e22016dc3c17bb849afc787c8d4d8abe
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,28 @@
using Unity.Entities;
using UnityEngine;
namespace DefaultNamespace
{
public interface IItemUseSystem
{
ItemUseFlags Flags { get; }
/// <summary>
/// The use type in animator. Converst to integer index.
/// </summary>
ItemUseType UseType { get; }
/// <summary>
/// Should use animation be on additive layer
/// </summary>
bool IsAdditiveUsage { get; }
bool CanUse(ItemPrefab prefab);
bool Validate(ItemPrefab prefab, Entity user, Entity inventory);
Sprite GetItemIcon(ItemPrefab prefab);
void Use(ItemPrefab prefab, ref ItemData itemData, Entity user, Entity inventory);
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8286d73d7aaeff94f803396767d8f590
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,59 @@
using Events;
using System.Collections.Generic;
using Unity.Entities;
using UnityEngine;
namespace DefaultNamespace
{
[UpdateInGroup(typeof(PresentationSystemGroup)), UpdateAfter(typeof(ItemPickupSystem))]
public class InventoryPickupSystem : ComponentSystem
{
protected override void OnUpdate()
{
var toDelete = new List<Object>();
Entities.ForEach(
(Rigidbody2D rigidBody, ref ItemPickupEventData pickup, ref ItemContainerData item) =>
{
var playerInventory = EntityManager.GetBuffer<Slot>(pickup.PlayerEntity);
var pickedUpItemFlag = false;
for (var j = 0; j < playerInventory.Length; j++)
{
var data = playerInventory[j];
if (data.Item.Item == item.ItemPrefab)
{
data.Item.Amount++;
playerInventory[j] = data;
PostUpdateCommands.PostEntityEvent<InventoryDirtyEventData>(EntityManager, pickup.PlayerEntity);
toDelete.Add(rigidBody.gameObject);
pickedUpItemFlag = true;
break;
}
}
//add in free spot
if (!pickedUpItemFlag)
{
for (var j = 0; j < playerInventory.Length; j++)
{
var data = playerInventory[j];
if (!data.Item.Item.IsValid)
{
data.Item.Item = item.ItemPrefab;
data.Item.Amount = 1;
playerInventory[j] = data;
PostUpdateCommands.PostEntityEvent<InventoryDirtyEventData>(EntityManager, pickup.PlayerEntity);
toDelete.Add(rigidBody.gameObject);
break;
}
}
}
});
foreach (var o in toDelete)
{
Object.Destroy(o);
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8a7c6501fc4d7294b87eca0f2aafa2ed
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,37 @@
using Events;
using Unity.Entities;
namespace DefaultNamespace
{
[UpdateInGroup(typeof(PresentationSystemGroup)), UpdateAfter(typeof(PlayerActionMapSystem))]
public class InventorySystem : ComponentSystem
{
protected override void OnUpdate()
{
Entities.WithAll<Slot>()
.ForEach(
(Entity entity, ref PlayerData player, ref PlayerInput input) =>
{
var inventoryDirtyFlag = false;
var inventory = EntityManager.GetBuffer<Slot>(entity);
for (var j = 0; j < inventory.Length; j++)
{
var slot = inventory[j];
if (slot.Item.Amount <= 0 && slot.Item.Item.IsValid)
{
slot.Item = new ItemData();
inventory[j] = slot;
inventoryDirtyFlag = true;
}
}
if (inventoryDirtyFlag)
{
PostUpdateCommands.PostEntityEvent<InventoryDirtyEventData>(EntityManager, entity);
}
});
PostUpdateCommands.RemoveEventComponents<InventoryDirtyEventData>(Entities);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 535ade2fff3ef7b4884e6b102f12fdcc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,146 @@
using Events;
using Items;
using UnityEngine;
using UnityEngine.AddressableAssets;
using Zenject;
using Entity = Unity.Entities.Entity;
namespace DefaultNamespace
{
public class ItemDropSystem : InjectableComponentSystem
{
[Inject] private readonly ItemContainerFactory itemContainerFactory;
protected override void OnSystemUpdate()
{
Entities.WithNone<AssetReferenceData<ItemPrefab>>()
.ForEach(
(Entity entity, ref ItemDropEvent drop) =>
{
PostUpdateCommands.AddSharedComponent(
entity,
new AssetReferenceData<ItemPrefab>(Addressables.LoadAssetAsync<ItemPrefab>(drop.Item.Item.ToString())));
});
Entities.ForEach(
(Entity entity, AssetReferenceData<ItemPrefab> itemPrefab, ref ItemDropEvent drop) =>
{
if (!itemPrefab.Operation.IsValid)
{
PostUpdateCommands.DestroyEntity(entity);
}
else if (itemPrefab.Operation.IsDone)
{
var pos = drop.Pos;
var dropInventory = drop.Inventory;
var dropItem = drop.Item;
var dropVelocity = drop.Velocity;
if (EntityManager.Exists(drop.Inventory))
{
var inventory = EntityManager.GetBuffer<Slot>(drop.Inventory);
Slot ItemModification(Slot slot, bool set)
{
if (set)
{
slot.Item = dropItem;
}
else
{
slot.Item.Amount += dropItem.Amount;
slot.Item.Item = dropItem.Item;
}
PostUpdateCommands.DestroyEntity(entity);
PostUpdateCommands.PostEntityEvent(EntityManager, dropInventory, new InventoryDirtyEventData());
return slot;
}
//put in specific empty slot or combine with existing item in that slot
if (drop.ToSlot > 0 && drop.ToSlot < inventory.Length)
{
var toSlotData = inventory[drop.ToSlot];
if (CanDrop(toSlotData, itemPrefab.Operation.Result) &&
(!toSlotData.HasItem() || toSlotData.Item.Item == dropItem.Item))
{
inventory[drop.ToSlot] = ItemModification(toSlotData, !toSlotData.HasItem());
return;
}
}
//combine with existing item
if (inventory.NativeFirstOrOptional(slot => slot.Item.Item == dropItem.Item)
.NativeModify(s => ItemModification(s, false)))
{
return;
}
//move item in destination slot to slot drag came from if possible and occupy new slot with new item
if (drop.ToSlot > 0 && drop.ToSlot < inventory.Length)
{
var toSlotData = inventory[drop.ToSlot];
if (CanDrop(toSlotData, itemPrefab.Operation.Result) && drop.FromSlot >= 0 && drop.FromSlot < inventory.Length)
{
var fromSlotData = inventory[drop.FromSlot];
if (!fromSlotData.HasItem())
{
//todo check for slot compatibility
fromSlotData.Item = toSlotData.Item;
inventory[drop.FromSlot] = fromSlotData;
inventory[drop.ToSlot] = ItemModification(toSlotData, true);
return;
}
}
}
//put in free slot
if (inventory.NativeFirstOrOptional(slot => !slot.HasItem() && CanDrop(slot, itemPrefab.Operation.Result))
.NativeModify(s => ItemModification(s, true)))
{
return;
}
//drop on ground near inventory
if (EntityManager.HasComponent<Rigidbody2D>(drop.Inventory))
{
pos = EntityManager.GetComponentObject<Rigidbody2D>(drop.Inventory).position;
}
}
itemContainerFactory.Create(itemPrefab.Operation.Result, dropItem.Item).Completed += asyncOperation =>
{
var rigidbody = asyncOperation.Result.GetComponent<Rigidbody2D>();
rigidbody.position = pos;
rigidbody.velocity = dropVelocity;
};
PostUpdateCommands.DestroyEntity(entity);
}
});
}
private bool CanDrop(Slot slot, ItemPrefab prefab)
{
switch (slot.Type)
{
case SlotType.None:
return true;
case SlotType.RangedWeapon:
return prefab is RangedWeaponItem;
case SlotType.MeleeWeapon:
return false;
case SlotType.Grenade:
return prefab is GrenadeItem;
case SlotType.Health:
return prefab is IHealItem;
}
return false;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1f16dfa58ee27c14480c68b9ab406203
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,136 @@
using Events;
using System;
using System.Collections.Generic;
using Unity.Collections;
using Unity.Entities;
using UnityEngine;
using Zenject;
namespace DefaultNamespace
{
[UpdateInGroup(typeof(PresentationSystemGroup)), UpdateAfter(typeof(PlayerMoveSystem)), UpdateBefore(typeof(ActorAnimationEventResetSystem))]
public class ItemPickupSystem : InjectableComponentSystem
{
[Serializable]
public class Settings
{
public float PickupDistance;
public SoundLibrary PickupSound;
}
[Inject] private readonly Settings settings;
[Inject] private readonly SoundManager soundManager;
private NativeList<Entity> CloseItems;
private HashSet<Entity> TakenItems;
protected override void OnCreate()
{
TakenItems = new HashSet<Entity>();
CloseItems = new NativeList<Entity>(Allocator.Persistent);
}
protected override void OnSystemUpdate()
{
TakenItems.Clear();
//waiting for pickup animation even to do the actual pickup if possible
//it will cancel the pickup even if animation state is not on tagged state with tag 'PickingUp'
ManageItemPickupEvents();
//only add actor pickup event to be processed in the upper loop
ManagePlayerPickupEvents();
Entities.ForEach((Entity entity, ref ItemPickupEventData pickup) => { PostUpdateCommands.RemoveComponent<ItemPickupEventData>(entity); });
}
private void ManageItemPickupEvents()
{
Entities.ForEach(
(
Entity playerEntity,
ref RigidBody2DData playerRigidBody,
ref ActorPickupEvent pickupEvent,
ref ActorAnimationEventData animationEvent,
ref AnimatorStateData animatorState,
ref ActorAnimationData animation) =>
{
if (animationEvent.PickedUp)
{
var itemRigidbody = EntityManager.GetComponentObject<Rigidbody2D>(pickupEvent.Item);
var d = Vector2.Distance(itemRigidbody.position, playerRigidBody.Position);
if (d <= settings.PickupDistance)
{
PostUpdateCommands.AddComponent(pickupEvent.Item, new ItemPickupEventData(playerEntity));
soundManager.PlayClip(PostUpdateCommands, settings.PickupSound, itemRigidbody.position);
}
PostUpdateCommands.RemoveComponent<ActorPickupEvent>(playerEntity);
}
else if (animationEvent.PickedCanceled)
{
PostUpdateCommands.RemoveComponent<ActorPickupEvent>(playerEntity);
animation.Triggers &= ~AnimationTriggerType.Pickup;
}
});
}
private void ManagePlayerPickupEvents()
{
var pickupDistanceSqr = settings.PickupDistance * settings.PickupDistance;
Entities.WithNone<ActorPickupEvent>()
.ForEach(
(
Entity playerEntity,
PlayerFacade playerFacade,
ref PlayerInput input,
ref AnimatorStateData animationState,
ref ActorAnimationData animation,
ref PlayerData player) =>
{
if (input.Pickup && animationState.State.IsTag("Interactive"))
{
CloseItems.Clear();
Entities.WithNone<ItemPickupEventData>()
.ForEach(
(Entity entity, ref RigidBody2DData rigidBody, ref ItemContainerData item) =>
{
var d = Vector2.SqrMagnitude(rigidBody.Position - (Vector2)playerFacade.transform.position);
if (d <= pickupDistanceSqr)
{
CloseItems.Add(entity);
}
});
for (var i = 0; i < CloseItems.Length; i++)
{
var itemIndex = CloseItems[i];
if (player.PickupIndex == i && !TakenItems.Contains(itemIndex))
{
TakenItems.Add(itemIndex);
PostUpdateCommands.AddComponent(playerEntity, new ActorPickupEvent { Item = itemIndex });
animation.Triggers |= AnimationTriggerType.Pickup;
break;
}
}
player.PickupIndex -= input.ScrollInput;
if (player.PickupIndex < 0)
{
player.PickupIndex += CloseItems.Length;
}
else if (player.PickupIndex >= CloseItems.Length)
{
player.PickupIndex -= CloseItems.Length;
}
player.PickupIndex = Mathf.Min(player.PickupIndex, Mathf.Max(CloseItems.Length - 1, 0));
}
});
}
protected override void OnDestroy()
{
CloseItems.Dispose();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dee8253f18bbcf240abfcb80b705d894
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,7 @@
using System;
namespace DefaultNamespace
{
[Flags]
public enum ItemUseFlags { UseOnlyGrounded = 1 << 0, UseOnlyInteractive = 1 << 1, InteruptAttack = 1 << 2 }
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2082c72c7f4737b44920e76055cf990e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,145 @@
using Events;
using System;
using System.Collections.Generic;
using System.Linq;
using Unity.Entities;
using UnityEngine;
using UnityEngine.AddressableAssets;
using Zenject;
namespace DefaultNamespace
{
[UpdateInGroup(typeof(PresentationSystemGroup)), UpdateBefore(typeof(ActorAnimationSystem))]
public class ItemUseSystem : InjectableComponentSystem
{
[Inject] private List<IItemUseSystem> useSystems;
protected override void OnSystemUpdate()
{
Entities.ForEach(
(Entity entity, ref ItemUseEventData e) =>
{
var inventoryEntity = e.Inventory;
var inventory = EntityManager.GetBuffer<Slot>(e.Inventory);
if (!e.Validating)
{
if (e.Slot < inventory.Length && inventory[e.Slot].HasItem())
{
e.Validating = true;
var item = inventory[e.Slot];
Addressables.LoadAssetAsync<ItemPrefab>(item.Item.Item.ToString()).Completed += operation =>
{
try
{
var ev = EntityManager.GetComponentData<ItemUseEventData>(entity);
var actor = EntityManager.GetComponentData<ActorData>(entity);
IEnumerable<IItemUseSystem> validatedSystemsEnumerable = useSystems;
if (EntityManager.HasComponent<AnimatorStateData>(entity))
{
var state = EntityManager.GetComponentData<AnimatorStateData>(entity);
validatedSystemsEnumerable = validatedSystemsEnumerable.Where(
s =>
{
if (s.Flags.HasFlag(ItemUseFlags.UseOnlyInteractive) && !state.State.IsTag("Interactive"))
{
return false;
}
if (!s.Flags.HasFlag(ItemUseFlags.InteruptAttack) && state.State.IsName("Attack"))
{
return false;
}
if (s.Flags.HasFlag(ItemUseFlags.UseOnlyGrounded) && !actor.Grounded)
{
return false;
}
return true;
});
}
var validatedSystems = validatedSystemsEnumerable.Where(
s => s.CanUse(operation.Result) && s.Validate(operation.Result, entity, inventoryEntity))
.ToArray();
ev.Invalid = operation.Result == null || validatedSystems.Length <= 0;
if (validatedSystems.Length > 0)
{
//trigger animation
var animation = EntityManager.GetComponentData<ActorAnimationData>(entity);
animation.Triggers |= AnimationTriggerType.ItemUse;
animation.UseType = validatedSystems[0].UseType;
animation.ItemUseAdditive = validatedSystems[0].IsAdditiveUsage;
EntityManager.SetComponentData(entity, animation);
if (EntityManager.HasComponent<ActorBodyParts>(entity))
{
var parts = EntityManager.GetComponentObject<ActorBodyParts>(entity);
if (parts.ItemRenderer != null)
{
parts.ItemRenderer.sprite = validatedSystems[0].GetItemIcon(operation.Result);
}
}
}
EntityManager.SetComponentData(entity, ev);
}
catch (Exception ex)
{
Debug.LogException(ex);
EntityManager.RemoveComponent<ItemUseEventData>(entity);
}
};
}
else
{
e.Invalid = true;
}
PostUpdateCommands.SetComponent(entity, e);
}
else if (e.Done)
{
var item = inventory[e.Slot];
var eLocal = e;
Addressables.LoadAssetAsync<ItemPrefab>(item.Item.Item.ToString()).Completed += operation =>
{
if (operation.Result != null)
{
var inv = EntityManager.GetBuffer<Slot>(eLocal.Inventory);
var slot = inv[eLocal.Slot];
foreach (var system in useSystems.Where(
s => s.CanUse(operation.Result) && s.Validate(operation.Result, entity, eLocal.Inventory)))
{
if (slot.HasItem())
{
system.Use(operation.Result, ref slot.Item, entity, eLocal.Inventory);
}
}
inv = EntityManager.GetBuffer<Slot>(eLocal.Inventory);
inv[eLocal.Slot] = slot;
}
};
PostUpdateCommands.RemoveComponent<ItemUseEventData>(entity);
}
else if (e.Invalid)
{
PostUpdateCommands.RemoveComponent<ItemUseEventData>(entity);
}
});
Entities.ForEach(
(Entity entity, ref ItemUseEventData itemEvent, ref ActorAnimationEventData e) =>
{
if (e.ItemUsed && !itemEvent.Invalid)
{
itemEvent.Done = true;
}
else if (e.ItemUsedCancled)
{
itemEvent.Invalid = true;
}
});
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ccb01c4fd6f8d154b82b406cc27c0cb0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,43 @@
using Unity.Entities;
using UnityEngine;
using Zenject;
namespace DefaultNamespace
{
public abstract class ItemUseSystemAbstract<T> : IItemUseSystem where T : ItemPrefab
{
[Inject] protected readonly EntityManager entityManager;
bool IItemUseSystem.CanUse(ItemPrefab prefab)
{
return prefab is T;
}
void IItemUseSystem.Use(ItemPrefab prefab, ref ItemData itemData, Entity user, Entity inventory)
{
Use((T)prefab, ref itemData, user, inventory);
}
bool IItemUseSystem.Validate(ItemPrefab prefab, Entity user, Entity inventory)
{
return Validate((T)prefab, user, inventory);
}
Sprite IItemUseSystem.GetItemIcon(ItemPrefab prefab)
{
return GetItemIcon((T)prefab);
}
public abstract ItemUseFlags Flags { get; }
public abstract ItemUseType UseType { get; }
public abstract bool IsAdditiveUsage { get; }
public abstract Sprite GetItemIcon(T prefab);
protected abstract void Use(T prefab, ref ItemData itemData, Entity user, Entity inventory);
protected abstract bool Validate(T prefab, Entity user, Entity inventory);
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0c6e2d007bec8d946aac933c54d94256
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: