commit 19d6bd934a7afa9ca7d91fe71d6e11f66b23ac7b Author: TheVVaS Date: Sat Apr 25 23:37:10 2026 +0200 init diff --git a/RPGCore.BackpackEquipment.meta b/RPGCore.BackpackEquipment.meta new file mode 100644 index 0000000..75fa9bc --- /dev/null +++ b/RPGCore.BackpackEquipment.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 246c7f468cf64a629c371b64c2e920e8 +timeCreated: 1773428848 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Editor.meta b/RPGCore.BackpackEquipment/Editor.meta new file mode 100644 index 0000000..5004bdf --- /dev/null +++ b/RPGCore.BackpackEquipment/Editor.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 846e226f291f4671be66417e772c98c5 +timeCreated: 1773428855 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Editor/RPGCore.BackpackEquipment.Editor.asmdef b/RPGCore.BackpackEquipment/Editor/RPGCore.BackpackEquipment.Editor.asmdef new file mode 100644 index 0000000..c932e1a --- /dev/null +++ b/RPGCore.BackpackEquipment/Editor/RPGCore.BackpackEquipment.Editor.asmdef @@ -0,0 +1,21 @@ +{ + "name": "RPGCore.BackpackEquipment.Editor", + "rootNamespace": "RPGCore.BackpackEquipment.Editor", + "references": [ + "RPGCore", + "RPGCore.Editor", + "RPGCore.BackpackEquipment", + "RPGCoreCommon.Helpers" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Editor/RPGCore.BackpackEquipment.Editor.asmdef.meta b/RPGCore.BackpackEquipment/Editor/RPGCore.BackpackEquipment.Editor.asmdef.meta new file mode 100644 index 0000000..94fae11 --- /dev/null +++ b/RPGCore.BackpackEquipment/Editor/RPGCore.BackpackEquipment.Editor.asmdef.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2576611464924f6f802336cafddc5977 +timeCreated: 1773428869 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime.meta b/RPGCore.BackpackEquipment/Runtime.meta new file mode 100644 index 0000000..0df1d4a --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8515b9a070ec44b58d2b7cbd621055e0 +timeCreated: 1773428859 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/Actions.meta b/RPGCore.BackpackEquipment/Runtime/Actions.meta new file mode 100644 index 0000000..d20999a --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/Actions.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5c5dabd4515f45fb96c7f15903844f14 +timeCreated: 1774103711 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/Actions/UseUsableAction.cs b/RPGCore.BackpackEquipment/Runtime/Actions/UseUsableAction.cs new file mode 100644 index 0000000..7b7a8f0 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/Actions/UseUsableAction.cs @@ -0,0 +1,46 @@ +using RPGCore.BackpackEquipment.Events; +using RPGCore.BackpackEquipment.ObjectModules.Content.Events; +using RPGCore.BackpackEquipment.Objects; +using RPGCore.ObjectModules.ActionObjectModule; + +namespace RPGCore.BackpackEquipment.Actions +{ + public class UseUsableAction : BaseActionParallel + { + private readonly UsableObject _usable; + + public UseUsableAction(UsableObject usable) + { + _usable = usable; + } + + public override void CanDoIt() + { + } + + protected override void OnDoIt() + { + var useEvent = new UseUsableEvent + { + unit = unit, + usable = _usable, + }; + + unit.events.InvokeBefore(useEvent); + _usable.events.InvokeBefore(useEvent); + + Check(!useEvent.isPrevented, ActionWasPreventedMessage); + + BeforePerform(); + AfterPerform(); + unit.events.InvokeAfter(useEvent); + _usable.events.InvokeAfter(useEvent); + + EndIt(); + } + + protected override void OnEndIt() { } + + protected override void OnCancelIt() { } + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/Actions/UseUsableAction.cs.meta b/RPGCore.BackpackEquipment/Runtime/Actions/UseUsableAction.cs.meta new file mode 100644 index 0000000..000a824 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/Actions/UseUsableAction.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: cb1ae2d4cdf64919807fcb9f305c8112 +timeCreated: 1764968523 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/Data.meta b/RPGCore.BackpackEquipment/Runtime/Data.meta new file mode 100644 index 0000000..036daa2 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/Data.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 613dac7e64bf4e00843b96715575183c +timeCreated: 1774104256 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/Data/ItemObjectData.cs b/RPGCore.BackpackEquipment/Runtime/Data/ItemObjectData.cs new file mode 100644 index 0000000..8d7b4ae --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/Data/ItemObjectData.cs @@ -0,0 +1,20 @@ +using System; +using RPGCore.BackpackEquipment.Objects; +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; +using UnityEngine; + +namespace RPGCore.BackpackEquipment.Data +{ + [Serializable] + public sealed class ItemObjectData : BaseData + { + [Header("Current state")] + public BaseObject carriedBy { get; set; } + + [Header("Stacking")] + [field: SerializeField] public bool stackable { get; private set; } = false; + [field: SerializeField] [Min(1)] public int stackSize { get; set; } = 1; + [field: SerializeField] [Min(1)] public int stackSizeMax { get; private set; } = 1; + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/Data/ItemObjectData.cs.meta b/RPGCore.BackpackEquipment/Runtime/Data/ItemObjectData.cs.meta new file mode 100644 index 0000000..dc8516e --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/Data/ItemObjectData.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7f4c99a92ec24e4188e68b383aafa544 +timeCreated: 1774024999 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/Events.meta b/RPGCore.BackpackEquipment/Runtime/Events.meta new file mode 100644 index 0000000..16987c2 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/Events.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4e5cdbb2c066404bb108b2b65d7b5532 +timeCreated: 1774103708 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/Events/UseUsableEvent.cs b/RPGCore.BackpackEquipment/Runtime/Events/UseUsableEvent.cs new file mode 100644 index 0000000..67870b9 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/Events/UseUsableEvent.cs @@ -0,0 +1,12 @@ +using RPGCore.BackpackEquipment.Objects; +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; + +namespace RPGCore.BackpackEquipment.Events +{ + public class UseUsableEvent : BasePreventableEvent + { + public UnitObject unit; + public UsableObject usable; + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/Events/UseUsableEvent.cs.meta b/RPGCore.BackpackEquipment/Runtime/Events/UseUsableEvent.cs.meta new file mode 100644 index 0000000..9011d42 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/Events/UseUsableEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c0cda7055098456787bdfe5e373e8c79 +timeCreated: 1764943310 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/InventorySettings.cs b/RPGCore.BackpackEquipment/Runtime/InventorySettings.cs new file mode 100644 index 0000000..432a530 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/InventorySettings.cs @@ -0,0 +1,10 @@ +using RPGCoreCommon.Settings; + +namespace RPGCore.BackpackEquipment.TheVVaS.RPGCore.BackpackEquipment.Runtime +{ + [CustomSettings("RPG Core/Inventory")] + public class InventorySettings : CustomSettingsSO + { + + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/InventorySettings.cs.meta b/RPGCore.BackpackEquipment/Runtime/InventorySettings.cs.meta new file mode 100644 index 0000000..a888435 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/InventorySettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 23152dde11934dc888fb1a826a8d9603 +timeCreated: 1774116804 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules.meta new file mode 100644 index 0000000..9232059 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 133e3213c71840b7affa92b9c12e1359 +timeCreated: 1773430576 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content.meta new file mode 100644 index 0000000..495d71f --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4d921d95879d44f0bd88e5c7f05450b1 +timeCreated: 1773479260 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Actions.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Actions.meta new file mode 100644 index 0000000..3572a69 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Actions.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5173c23cdfbb43fd80e5bb85342554b1 +timeCreated: 1774105224 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Actions/DropAction.cs b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Actions/DropAction.cs new file mode 100644 index 0000000..e963f47 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Actions/DropAction.cs @@ -0,0 +1,38 @@ +using RPGCore.BackpackEquipment.ObjectModules.Content.Events; +using RPGCore.BackpackEquipment.Objects; +using RPGCore.ObjectModules.ActionObjectModule; + +namespace RPGCore.BackpackEquipment.ObjectModules.Content.Actions +{ + public class DropAction : BaseAction + { + private readonly ItemObject _item; + + public DropAction(ItemObject item) + { + _item = item; + } + + public override void CanDoIt() + { + } + + protected override void OnDoIt() + { + var dropEvent = new DropEvent { unit = unit, item = _item }; + unit.events.InvokeBefore(dropEvent); + Check(!dropEvent.isPrevented, string.Format(ActionWasPreventedMessage, nameof(DropAction))); + unit.events.InvokeAfter(dropEvent); + + unit.GetComponent().Remove(_item); + } + + protected override void OnEndIt() + { + } + + protected override void OnCancelIt() + { + } + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Actions/DropAction.cs.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Actions/DropAction.cs.meta new file mode 100644 index 0000000..140f8c2 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Actions/DropAction.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 15a26990a9c14410b2131f6d8286ad18 +timeCreated: 1774104885 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Actions/TakeAction.cs b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Actions/TakeAction.cs new file mode 100644 index 0000000..908e74f --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Actions/TakeAction.cs @@ -0,0 +1,45 @@ +using RPGCore.BackpackEquipment.ObjectModules.Content.Events; +using RPGCore.BackpackEquipment.Objects; +using RPGCore.ObjectModules.ActionObjectModule; + +namespace RPGCore.BackpackEquipment.ObjectModules.Content.Actions +{ + public class TakeAction : BaseAction + { + private readonly IContentOwner _contentOwner; + private readonly ItemObject _item; + private readonly int _index; + + public TakeAction(IContentOwner contentOwner, ItemObject item, int index = -1) + { + _contentOwner = contentOwner; + _item = item; + _index = index; + } + + public override void CanDoIt() + { + _contentOwner.CanAdd(_item, _index); + } + + protected override void OnDoIt() + { + var takeEvent = new TakeEvent { unit = unit, item = _item }; + unit.events.InvokeBefore(takeEvent); + Check(!takeEvent.isPrevented, string.Format(ActionWasPreventedMessage, nameof(TakeAction))); + unit.events.InvokeAfter(takeEvent); + + var content = unit.GetComponent(); + content.Add(_item); + content.TransferTo(_contentOwner, _item, _index); + } + + protected override void OnEndIt() + { + } + + protected override void OnCancelIt() + { + } + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Actions/TakeAction.cs.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Actions/TakeAction.cs.meta new file mode 100644 index 0000000..1d3716c --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Actions/TakeAction.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e2df668c012544ff893888d9f5bcce9a +timeCreated: 1774104779 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/ContentModule.cs b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/ContentModule.cs new file mode 100644 index 0000000..d4f649e --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/ContentModule.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using RPGCore.BackpackEquipment.Data; +using RPGCore.BackpackEquipment.ObjectModules.Content.Events; +using RPGCore.BackpackEquipment.Objects; +using RPGCore.Core; +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule.Events; +using UnityEngine; + +namespace RPGCore.BackpackEquipment.ObjectModules.Content +{ + [Serializable] + [RequireComponent(typeof(BaseObject))] + public sealed class ContentModule : ObjectModule + { + // TODO: tutaj jakiś domyślny owner? + + private Dictionary _items = new(); + + public bool Add(ItemObject item) + { + if (item.data.Get().carriedBy) return false; + if (_items.ContainsKey(item)) return false; + + _items.TryAdd(item, null); + item.data.Get().carriedBy = parent; + parent.events.Invoke(new ContentAddEvent{obj = parent, item = item}); + item.events.Register(OnItemRemove); + + return true; + } + + public bool Remove(ItemObject item) + { + if (!_items.ContainsKey(item)) return false; + + _items[item]?.Remove_Internal(item); + _items.Remove(item); + item.data.Get().carriedBy = null; + parent.events.Invoke(new ContentAddEvent{obj = parent, item = item}); + item.events.Unregister(OnItemRemove); + + return true; + } + + public bool TransferTo(IContentOwner newOwner, ItemObject item, int index = -1) + { + if (parent.data.Get().carriedBy != parent) return false; + + if (!newOwner.CanAdd(item, index)) return false; + + _items.TryAdd(item, null); + _items[item]?.Remove_Internal(item); + _items[item] = newOwner; + newOwner.Add_Internal(item, index); + + return true; + } + + private void OnItemRemove(RemoveEvent removeEvent) + { + Remove(removeEvent.obj as ItemObject); + } + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/ContentModule.cs.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/ContentModule.cs.meta new file mode 100644 index 0000000..1e280f5 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/ContentModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 79108abbb1214cdca99dde30ae550ceb +timeCreated: 1773479273 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events.meta new file mode 100644 index 0000000..60ce54b --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3913c554eb1a4addbb26fffdcd349490 +timeCreated: 1773603441 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events/ContentAddEvent.cs b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events/ContentAddEvent.cs new file mode 100644 index 0000000..d72ffbc --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events/ContentAddEvent.cs @@ -0,0 +1,12 @@ +using RPGCore.BackpackEquipment.Objects; +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; + +namespace RPGCore.BackpackEquipment.ObjectModules.Content.Events +{ + public class ContentAddEvent : BaseEvent + { + public BaseObject obj; + public ItemObject item; + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events/ContentAddEvent.cs.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events/ContentAddEvent.cs.meta new file mode 100644 index 0000000..62c128a --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events/ContentAddEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 99499df3a233439c87e15c7aff0c5f7e +timeCreated: 1773603493 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events/ContentRemoveEvent.cs b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events/ContentRemoveEvent.cs new file mode 100644 index 0000000..eadc307 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events/ContentRemoveEvent.cs @@ -0,0 +1,12 @@ +using RPGCore.BackpackEquipment.Objects; +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; + +namespace RPGCore.BackpackEquipment.ObjectModules.Content.Events +{ + public class ContentRemoveEvent : BaseEvent + { + public BaseObject obj; + public ItemObject item; + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events/ContentRemoveEvent.cs.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events/ContentRemoveEvent.cs.meta new file mode 100644 index 0000000..e49a4f3 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events/ContentRemoveEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9475ae89a4184189aadc77e6efc7f86b +timeCreated: 1773603523 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events/DropEvent.cs b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events/DropEvent.cs new file mode 100644 index 0000000..bbca8e6 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events/DropEvent.cs @@ -0,0 +1,12 @@ +using RPGCore.BackpackEquipment.Objects; +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; + +namespace RPGCore.BackpackEquipment.ObjectModules.Content.Events +{ + public class DropEvent : BasePreventableEvent + { + public UnitObject unit; + public ItemObject item; + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events/DropEvent.cs.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events/DropEvent.cs.meta new file mode 100644 index 0000000..f08db45 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events/DropEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6d837632056f4104b980ea605bedf43a +timeCreated: 1774105017 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events/TakeEvent.cs b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events/TakeEvent.cs new file mode 100644 index 0000000..3da3d35 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events/TakeEvent.cs @@ -0,0 +1,12 @@ +using RPGCore.BackpackEquipment.Objects; +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; + +namespace RPGCore.BackpackEquipment.ObjectModules.Content.Events +{ + public class TakeEvent : BasePreventableEvent + { + public UnitObject unit; + public ItemObject item; + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events/TakeEvent.cs.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events/TakeEvent.cs.meta new file mode 100644 index 0000000..ae2cb1a --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/Events/TakeEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 59ccda71e50b47c1aa77c87b649fcbc6 +timeCreated: 1774104995 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/IContentOwner.cs b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/IContentOwner.cs new file mode 100644 index 0000000..773e3dd --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/IContentOwner.cs @@ -0,0 +1,18 @@ +using RPGCore.BackpackEquipment.Objects; + +namespace RPGCore.BackpackEquipment.ObjectModules.Content +{ + public interface IContentOwner + { + internal bool Add_Internal(ItemObject item, int index = -1) + { + return CanAdd(item, index) && Add(item, index); + } + + internal bool Remove_Internal(ItemObject item) => Remove(item); + + public bool CanAdd(ItemObject item, int index); + protected bool Add(ItemObject item, int index); + protected bool Remove(ItemObject item); + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/IContentOwner.cs.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/IContentOwner.cs.meta new file mode 100644 index 0000000..7a5eace --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/Content/IContentOwner.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 78febecbf5d31be469d6b9d3c816fd4d \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack.meta new file mode 100644 index 0000000..374d437 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: dd19ece4ebc44910a39c811850fd4193 +timeCreated: 1773430585 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events.meta new file mode 100644 index 0000000..db5ee54 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 44fa14edd1ea4bca85d9f05ac40e40ea +timeCreated: 1774105228 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackAddEvent.cs b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackAddEvent.cs new file mode 100644 index 0000000..727156f --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackAddEvent.cs @@ -0,0 +1,13 @@ +using RPGCore.BackpackEquipment.Objects; +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; + +namespace RPGCore.BackpackEquipment.ObjectModules.UnitBackpack.Events +{ + public class BackpackAddEvent : BaseEvent + { + public UnitObject unit; + public ItemObject item; + public int index; + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackAddEvent.cs.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackAddEvent.cs.meta new file mode 100644 index 0000000..a062a39 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackAddEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c6f6cc77ea14440495a47ca94593c621 +timeCreated: 1774105312 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackRemoveEvent.cs b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackRemoveEvent.cs new file mode 100644 index 0000000..2f392c6 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackRemoveEvent.cs @@ -0,0 +1,13 @@ +using RPGCore.BackpackEquipment.Objects; +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; + +namespace RPGCore.BackpackEquipment.ObjectModules.UnitBackpack.Events +{ + public class BackpackRemoveEvent : BaseEvent + { + public UnitObject unit; + public ItemObject item; + public int index; + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackRemoveEvent.cs.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackRemoveEvent.cs.meta new file mode 100644 index 0000000..80839b8 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackRemoveEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 71449b2a17364a648815c450a72a7b8a +timeCreated: 1774105327 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackResizeEvent.cs b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackResizeEvent.cs new file mode 100644 index 0000000..46810f3 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackResizeEvent.cs @@ -0,0 +1,12 @@ +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; + +namespace RPGCore.BackpackEquipment.ObjectModules.UnitBackpack.Events +{ + public class BackpackResizeEvent : BaseEvent + { + public UnitObject unit; + public int beforeSlotCount; + public int afterSlotCount; + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackResizeEvent.cs.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackResizeEvent.cs.meta new file mode 100644 index 0000000..aef3b46 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackResizeEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 78e21ee03af24c16b2227c490a8baf32 +timeCreated: 1774205953 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackSortEvent.cs b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackSortEvent.cs new file mode 100644 index 0000000..5c46012 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackSortEvent.cs @@ -0,0 +1,10 @@ +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; + +namespace RPGCore.BackpackEquipment.ObjectModules.UnitBackpack.Events +{ + public class BackpackSortEvent : BaseEvent + { + public UnitObject unit; + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackSortEvent.cs.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackSortEvent.cs.meta new file mode 100644 index 0000000..4296c42 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackSortEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a837a368926d42888b1a661e56cab0df +timeCreated: 1774129920 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackSwapEvent.cs b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackSwapEvent.cs new file mode 100644 index 0000000..32e08e2 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackSwapEvent.cs @@ -0,0 +1,17 @@ +using RPGCore.BackpackEquipment.Objects; +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; + +namespace RPGCore.BackpackEquipment.ObjectModules.UnitBackpack.Events +{ + public class BackpackSwapEvent : BaseEvent + { + public UnitObject unit; + + public int firstSlotIndex; + public ItemObject firstItem; + + public int secondSlotIndex; + public ItemObject secondItem; + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackSwapEvent.cs.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackSwapEvent.cs.meta new file mode 100644 index 0000000..693a563 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/Events/BackpackSwapEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4343d10da640435abbc163a2d255ddf2 +timeCreated: 1774206592 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/UnitBackpackModule.cs b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/UnitBackpackModule.cs new file mode 100644 index 0000000..ce0a185 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/UnitBackpackModule.cs @@ -0,0 +1,154 @@ +using System; +using System.Linq; +using RPGCore.BackpackEquipment.ObjectModules.Content; +using RPGCore.BackpackEquipment.ObjectModules.UnitBackpack.Events; +using RPGCore.BackpackEquipment.Objects; +using RPGCore.Core; +using RPGCore.Core.Objects; +using RPGCoreCommon.Helpers.PropertyAttributeDrawers; +using UnityEngine; + +namespace RPGCore.BackpackEquipment.ObjectModules.UnitBackpack +{ + [RequireComponent(typeof(UnitObject))] + [RequireComponent(typeof(ContentModule))] + [DisallowMultipleComponent] + public sealed class UnitBackpackModule : ObjectModule, IContentOwner + { + // TODO: implementacja stackowania tutaj + [SerializeField] private ItemObject[] _serializedItems; + [SerializeField] public bool isLimited = true; + [SerializeField] public int itemsLimit = 5; + [SerializeField] public int itemsPerChunk = 5; + [SerializeField] public int minimumChunks = 3; + [SerializeField] public int additionalChunks = 1; + + private ItemObject[] _items; + public ItemObject[] items => _items.ToArray(); + + private void Awake() + { + _items = _serializedItems.ToArray(); + Resize(); + } + + private void Start() + { + InitializeItems(); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + private void InitializeItems() + { + // TODO: inicjalizacja serializowanych itemkow + ich eventy + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + public bool CanAdd(ItemObject item, int index) + { + return !isLimited || _items.Any(i => i == null); + } + + bool IContentOwner.Add(ItemObject item, int index) + { + if (index < 0) index = Array.IndexOf(_items, false); + if (index < 0) return false; + if (isLimited && index >= itemsLimit) return false; + + _items[index] = item; + Resize(); + + parent.events.Invoke(new BackpackAddEvent { unit = parent, item = item, index = index }); + + return true; + } + + bool IContentOwner.Remove(ItemObject item) + { + var index = Array.IndexOf(_items, item); + if (index < 0) return false; + + _items[index] = null; + Resize(); + + parent.events.Invoke(new BackpackRemoveEvent { unit = parent, item = item, index = index }); + + return true; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + public void Swap(int firstItemIndex, int secondItemIndex) + { + var wantedSize = Math.Max(firstItemIndex, secondItemIndex) + 1; + + if (isLimited && wantedSize > itemsLimit) return; + + Resize(wantedSize); + + (items[firstItemIndex], items[secondItemIndex]) = (items[secondItemIndex], items[firstItemIndex]); + + parent.events.Invoke(new BackpackSwapEvent + { + unit = parent, + firstSlotIndex = firstItemIndex, + firstItem = items[firstItemIndex], + secondSlotIndex = secondItemIndex, + secondItem = items[secondItemIndex], + }); + } + + private void Resize(int wantedSize = 0) + { + if (isLimited) + { + // TODO: obsłużyć itemki w miejscach, które zaraz zostaną "ucięte" (przy zmniejszaniu slotów) - TYLKO w limitowanym plecaku + if (_items.Length != itemsLimit) + { + Array.Resize(ref _items, itemsLimit); + } + return; + } + + var limitBefore = items.Length; + var lastItemIndex = Array.FindLastIndex(items, item => item); + var limitMinimum = Mathf.Max(wantedSize, lastItemIndex, minimumChunks * itemsPerChunk); + var limitAfter = Mathf.CeilToInt((float)limitMinimum / itemsPerChunk + additionalChunks) * itemsPerChunk; + + // Size not changed, do nothing + if (limitBefore == limitAfter) return; + + // Resize backpack's arrays + Array.Resize(ref _items, limitAfter); + + parent.events.Invoke(new BackpackResizeEvent + { + unit = parent, + beforeSlotCount = limitBefore, + afterSlotCount = limitAfter + }); + } + + public void Sort(Func valueGetter, bool sortDescending = false) + { + Array.Sort(items, (item1, item2) => + { + // NULLS always to the end + if (!item1 && !item2) return 0; + if (!item1) return 1; + if (!item2) return -1; + + // Existing items sort by given value getter with given sort direction + var result = valueGetter(item1).CompareTo(valueGetter(item2)); + if (sortDescending) result *= - 1; + return result; + }); + + parent.events.Invoke(new BackpackSortEvent { unit = parent }); + + Resize(); + } + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/UnitBackpackModule.cs.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/UnitBackpackModule.cs.meta new file mode 100644 index 0000000..4ea9d03 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitBackpack/UnitBackpackModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e066d3b400674903a1d052f489460cbc +timeCreated: 1773430662 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment.meta new file mode 100644 index 0000000..41dae88 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9a81f86e2a5e4f37b06c93aa994bd84e +timeCreated: 1773430610 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Actions.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Actions.meta new file mode 100644 index 0000000..4aaeeb1 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Actions.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8bf7e79f48a548eb84e276eee5e5e625 +timeCreated: 1774105234 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Actions/EquipAction.cs b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Actions/EquipAction.cs new file mode 100644 index 0000000..f966755 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Actions/EquipAction.cs @@ -0,0 +1,29 @@ +using RPGCore.BackpackEquipment.ObjectModules.UnitEquipment.Objects; +using RPGCore.ObjectModules.ActionObjectModule; + +namespace RPGCore.BackpackEquipment.ObjectModules.UnitEquipment.Actions +{ + public class EquipAction : BaseAction + { + private readonly WearableObject _wearable; + private readonly int _index; + + public EquipAction(WearableObject wearable, int index = -1) + { + _wearable = wearable; + _index = index; + } + + public override void CanDoIt() + { + } + + protected override void OnDoIt() + { + } + + protected override void OnEndIt() { } + + protected override void OnCancelIt() { } + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Actions/EquipAction.cs.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Actions/EquipAction.cs.meta new file mode 100644 index 0000000..44843db --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Actions/EquipAction.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e7e7ce4fbec54ebfbe05f9cecae4a871 +timeCreated: 1774105374 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Actions/UnEquipAction.cs b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Actions/UnEquipAction.cs new file mode 100644 index 0000000..321c0bd --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Actions/UnEquipAction.cs @@ -0,0 +1,27 @@ +using RPGCore.ObjectModules.ActionObjectModule; + +namespace RPGCore.BackpackEquipment.ObjectModules.UnitEquipment.Actions +{ + public class UnEquipAction : BaseAction + { + public override void CanDoIt() + { + throw new System.NotImplementedException(); + } + + protected override void OnDoIt() + { + throw new System.NotImplementedException(); + } + + protected override void OnEndIt() + { + throw new System.NotImplementedException(); + } + + protected override void OnCancelIt() + { + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Actions/UnEquipAction.cs.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Actions/UnEquipAction.cs.meta new file mode 100644 index 0000000..1c39727 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Actions/UnEquipAction.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 48179d58af5844cb9ea6d3df49a151cb +timeCreated: 1774105416 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Data.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Data.meta new file mode 100644 index 0000000..9e861ea --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Data.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8935ac7ea78145d2bade1ab807dcf5ac +timeCreated: 1776013837 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Data/WearableObjectData.cs b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Data/WearableObjectData.cs new file mode 100644 index 0000000..c511f19 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Data/WearableObjectData.cs @@ -0,0 +1,19 @@ +using System; +using RPGCore.BackpackEquipment.ObjectModules.UnitEquipment.Objects; +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; +using RPGCoreCommon.Helpers.PropertyAttributeDrawers; +using UnityEngine; + +namespace RPGCore.BackpackEquipment.ObjectModules.UnitEquipment.Data +{ + [Serializable] + public sealed class WearableObjectData : BaseData + { + [Header("Current state")] + [field: SerializeField, ReadOnly] public UnitObject equippedBy { get; set; } + + [Header("WEARABLE")] + [field: SerializeField] public WearableTypeSO type { get; private set; } + } +} diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Data/WearableObjectData.cs.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Data/WearableObjectData.cs.meta new file mode 100644 index 0000000..eb34080 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Data/WearableObjectData.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5225f7b9b3fd4b15874ed6af5a887703 +timeCreated: 1775931397 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/EquipmentSchemaSO.cs b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/EquipmentSchemaSO.cs new file mode 100644 index 0000000..47352e2 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/EquipmentSchemaSO.cs @@ -0,0 +1,10 @@ +using UnityEngine; + +namespace RPGCore.BackpackEquipment.ObjectModules.UnitEquipment +{ + [CreateAssetMenu(menuName = "RPG Core/Equipment/Schema")] + public class EquipmentSchemaSO : ScriptableObject + { + public EquipmentSchemaSlot[] slots; + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/EquipmentSchemaSO.cs.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/EquipmentSchemaSO.cs.meta new file mode 100644 index 0000000..63b76ee --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/EquipmentSchemaSO.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1b6db097519240cdb57eb1a235eb6d00 +timeCreated: 1774117121 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/EquipmentSchemaSlot.cs b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/EquipmentSchemaSlot.cs new file mode 100644 index 0000000..54d31de --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/EquipmentSchemaSlot.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace RPGCore.BackpackEquipment.ObjectModules.UnitEquipment +{ + [Serializable] + public class EquipmentSchemaSlot + { + public string name; + public Texture2D icon; + public List validTypes; + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/EquipmentSchemaSlot.cs.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/EquipmentSchemaSlot.cs.meta new file mode 100644 index 0000000..ba72ad6 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/EquipmentSchemaSlot.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3c100a156e9e403888cab30f01b22b2e +timeCreated: 1774117160 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Events.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Events.meta new file mode 100644 index 0000000..80af261 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Events.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5a9185f4f6844784b7432d9353365f7f +timeCreated: 1774105234 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Events/EquipEvent.cs b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Events/EquipEvent.cs new file mode 100644 index 0000000..4936405 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Events/EquipEvent.cs @@ -0,0 +1,14 @@ +using RPGCore.BackpackEquipment.ObjectModules.UnitEquipment.Objects; +using RPGCore.BackpackEquipment.Objects; +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; + +namespace RPGCore.BackpackEquipment.ObjectModules.UnitEquipment.Events +{ + public class EquipEvent : BaseEvent + { + public UnitObject unit; + public WearableObject wearable; + public int index; + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Events/EquipEvent.cs.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Events/EquipEvent.cs.meta new file mode 100644 index 0000000..9cc3eea --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Events/EquipEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9c3da958a57e4b019de195f87cc032d7 +timeCreated: 1774105477 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Events/UnEquipEvent.cs b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Events/UnEquipEvent.cs new file mode 100644 index 0000000..7cc399d --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Events/UnEquipEvent.cs @@ -0,0 +1,14 @@ +using RPGCore.BackpackEquipment.ObjectModules.UnitEquipment.Objects; +using RPGCore.BackpackEquipment.Objects; +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; + +namespace RPGCore.BackpackEquipment.ObjectModules.UnitEquipment.Events +{ + public class UnEquipEvent : BaseEvent + { + public UnitObject unit; + public WearableObject wearable; + public int index; + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Events/UnEquipEvent.cs.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Events/UnEquipEvent.cs.meta new file mode 100644 index 0000000..dcbf18d --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Events/UnEquipEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b9b6c7062a844cb6bf556d76e7351410 +timeCreated: 1774105488 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Objects.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Objects.meta new file mode 100644 index 0000000..920e926 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Objects.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4f78116570fd4167a06bb18e9f0d585b +timeCreated: 1776013778 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Objects/WearableObject.cs b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Objects/WearableObject.cs new file mode 100644 index 0000000..18680b3 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Objects/WearableObject.cs @@ -0,0 +1,13 @@ +using System; +using RPGCore.BackpackEquipment.Objects; +using RPGCore.Core; +using RPGCoreCommon.DynamicValues; + +namespace RPGCore.BackpackEquipment.ObjectModules.UnitEquipment.Objects +{ + public class WearableObject : ItemObject + { + [DynamicValueProvider] + private ObjectModule UsableModuleProvider(Type moduleType) => GetComponent(moduleType) as ObjectModule; + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Objects/WearableObject.cs.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Objects/WearableObject.cs.meta new file mode 100644 index 0000000..14af80b --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/Objects/WearableObject.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c2ef6b5eaa38431bacb28adb8bb2739c +timeCreated: 1773430452 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/UnitEquipmentModule.cs b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/UnitEquipmentModule.cs new file mode 100644 index 0000000..f8095b7 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/UnitEquipmentModule.cs @@ -0,0 +1,78 @@ +using System; +using System.Linq; +using RPGCore.BackpackEquipment.ObjectModules.Content; +using RPGCore.BackpackEquipment.ObjectModules.UnitEquipment.Data; +using RPGCore.BackpackEquipment.ObjectModules.UnitEquipment.Events; +using RPGCore.BackpackEquipment.ObjectModules.UnitEquipment.Objects; +using RPGCore.BackpackEquipment.Objects; +using RPGCore.Core; +using RPGCore.Core.Objects; +using UnityEngine; + +namespace RPGCore.BackpackEquipment.ObjectModules.UnitEquipment +{ + [RequireComponent(typeof(UnitObject))] + [RequireComponent(typeof(ContentModule))] + [DisallowMultipleComponent] + public class UnitEquipmentModule : ObjectModule, IContentOwner + { + [SerializeField] private EquipmentSchemaSO _schema; + [SerializeField] private WearableObject[] _serializedItems; + + private WearableObject[] _items; + + private void Awake() + { + _items = new WearableObject[_schema.slots.Length]; + } + + private void Start() + { + InitializeItems(); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + private void InitializeItems() + { + // TODO: inicjalizacja serializowanych itemkow + ich eventy + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + public bool CanAdd(ItemObject item, int index) + { + if (item is not WearableObject wearable) return false; + + var slot = _schema.slots[index]; + if (slot == null) return false; + + if (!slot.validTypes.Contains(wearable.data.Get().type)) return false; + + return true; + } + + bool IContentOwner.Add(ItemObject item, int index) + { + var wearable = (WearableObject)item; + + parent.events.Invoke(new EquipEvent { unit = parent, wearable = wearable, index = index }); + + _items[index] = wearable; + return true; + } + + bool IContentOwner.Remove(ItemObject item) + { + var wearable = (WearableObject)item; + var index = Array.IndexOf(_items, wearable); + + parent.events.Invoke(new UnEquipEvent { unit = parent, wearable = wearable, index = index }); + + _items[index] = null; + return true; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////// + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/UnitEquipmentModule.cs.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/UnitEquipmentModule.cs.meta new file mode 100644 index 0000000..9d4c299 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/UnitEquipmentModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2daf6192d70b4fc798983932b68c28ea +timeCreated: 1773430702 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/WearableTypeSO.cs b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/WearableTypeSO.cs new file mode 100644 index 0000000..3cb9112 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/WearableTypeSO.cs @@ -0,0 +1,12 @@ +using RPGCoreCommon.Helpers.CustomTypes; +using UnityEngine; + +namespace RPGCore.BackpackEquipment.ObjectModules.UnitEquipment +{ + [CreateAssetMenu(menuName = "RPG Core/Equipment/Wearable Type")] + public class WearableTypeSO : ScriptableObject + { + public new string name; + public Texture2D icon; + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/WearableTypeSO.cs.meta b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/WearableTypeSO.cs.meta new file mode 100644 index 0000000..6d05b7a --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/ObjectModules/UnitEquipment/WearableTypeSO.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2c0e3d78b2374dfbb1b254cb9a9cef19 +timeCreated: 1774116782 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/Objects.meta b/RPGCore.BackpackEquipment/Runtime/Objects.meta new file mode 100644 index 0000000..a9d02f4 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/Objects.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 91c35ff45009487e8d5949bdd8a0e821 +timeCreated: 1773430417 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/Objects/ItemObject.cs b/RPGCore.BackpackEquipment/Runtime/Objects/ItemObject.cs new file mode 100644 index 0000000..46cd090 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/Objects/ItemObject.cs @@ -0,0 +1,13 @@ +using System; +using RPGCore.Core; +using RPGCore.Core.Objects; +using RPGCoreCommon.DynamicValues; + +namespace RPGCore.BackpackEquipment.Objects +{ + public class ItemObject : BaseObject + { + [DynamicValueProvider] + private ObjectModule ItemModuleProvider(Type moduleType) => GetComponent(moduleType) as ObjectModule; + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/Objects/ItemObject.cs.meta b/RPGCore.BackpackEquipment/Runtime/Objects/ItemObject.cs.meta new file mode 100644 index 0000000..02ebc91 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/Objects/ItemObject.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3a78a8ed91814b05aa7a0a34135d8edf +timeCreated: 1761863724 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/Objects/UsableObject.cs b/RPGCore.BackpackEquipment/Runtime/Objects/UsableObject.cs new file mode 100644 index 0000000..c33448c --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/Objects/UsableObject.cs @@ -0,0 +1,12 @@ +using System; +using RPGCore.Core; +using RPGCoreCommon.DynamicValues; + +namespace RPGCore.BackpackEquipment.Objects +{ + public class UsableObject : ItemObject + { + [DynamicValueProvider] + private ObjectModule UsableModuleProvider(Type moduleType) => GetComponent(moduleType) as ObjectModule; + } +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/Objects/UsableObject.cs.meta b/RPGCore.BackpackEquipment/Runtime/Objects/UsableObject.cs.meta new file mode 100644 index 0000000..11f91ea --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/Objects/UsableObject.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 517748b5c1324d10b16e239bbbc7ba3e +timeCreated: 1761863772 \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/RPGCore.BackpackEquipment.asmdef b/RPGCore.BackpackEquipment/Runtime/RPGCore.BackpackEquipment.asmdef new file mode 100644 index 0000000..a3ec45b --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/RPGCore.BackpackEquipment.asmdef @@ -0,0 +1,20 @@ +{ + "name": "RPGCore.BackpackEquipment", + "rootNamespace": "RPGCore.BackpackEquipment", + "references": [ + "RPGCore", + "RPGCore.StatusEffect", + "RPGCoreCommon.Settings", + "RPGCoreCommon.Helpers", + "RPGCoreCommon.DynamicValues" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/RPGCore.BackpackEquipment/Runtime/RPGCore.BackpackEquipment.asmdef.meta b/RPGCore.BackpackEquipment/Runtime/RPGCore.BackpackEquipment.asmdef.meta new file mode 100644 index 0000000..dcdf640 --- /dev/null +++ b/RPGCore.BackpackEquipment/Runtime/RPGCore.BackpackEquipment.asmdef.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a627f0df001c4795964985a7b361ac64 +timeCreated: 1773428871 \ No newline at end of file diff --git a/RPGCore.Movement.meta b/RPGCore.Movement.meta new file mode 100644 index 0000000..a8e7707 --- /dev/null +++ b/RPGCore.Movement.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bfd9def14cab4592814c2cf160e6f8f2 +timeCreated: 1772991224 \ No newline at end of file diff --git a/RPGCore.Movement/Editor.meta b/RPGCore.Movement/Editor.meta new file mode 100644 index 0000000..8796a13 --- /dev/null +++ b/RPGCore.Movement/Editor.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d2be1640179628a40821b132d8487517 +timeCreated: 1772973840 \ No newline at end of file diff --git a/RPGCore.Movement/Editor/Drawers.meta b/RPGCore.Movement/Editor/Drawers.meta new file mode 100644 index 0000000..3fe38fc --- /dev/null +++ b/RPGCore.Movement/Editor/Drawers.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9b47a45649f44855b50d7efd8637fd23 +timeCreated: 1768928367 \ No newline at end of file diff --git a/RPGCore.Movement/Editor/Drawers/UnitMovementModuleDrawer.cs b/RPGCore.Movement/Editor/Drawers/UnitMovementModuleDrawer.cs new file mode 100644 index 0000000..345f3c3 --- /dev/null +++ b/RPGCore.Movement/Editor/Drawers/UnitMovementModuleDrawer.cs @@ -0,0 +1,59 @@ +using RPGCore.Movement.ObjectModules.UnitMovement; +using UnityEditor; +using UnityEditor.UIElements; +using UnityEngine; +using UnityEngine.UIElements; + +namespace RPGCore.Movement.Editor.Drawers +{ + [CustomPropertyDrawer(typeof(UnitMovementModule))] + public class UnitMovementModuleDrawer : PropertyDrawer + { + public override VisualElement CreatePropertyGUI(SerializedProperty property) + { + var root = new VisualElement(); + + if (Application.isPlaying) root.Add(CreateDebugBox(property)); + root.Add(new PropertyField(property)); + + return root; + } + + private HelpBox CreateDebugBox(SerializedProperty property) + { + var debugBox = new HelpBox(); + debugBox.style.flexDirection = FlexDirection.Column; + debugBox.style.alignItems = Align.Stretch; + debugBox.SetEnabled(false); + + debugBox.Add(new Label("RUNTIME DEBUG:")); + + var groundSteepnessField = new FloatField(nameof(UnitMovementModule.groundSteepness)); + debugBox.Add(groundSteepnessField); + var isOnGroundField = new Toggle(nameof(UnitMovementModule.isOnGround)); + debugBox.Add(isOnGroundField); + var rotateYawField = new FloatField(nameof(UnitMovementModule.rotateYaw)); + debugBox.Add(rotateYawField); + var moveVectorField = new Vector3Field(nameof(UnitMovementModule.accelerationVector)); + debugBox.Add(moveVectorField); + var linearVelocityField = new Vector3Field(nameof(Rigidbody.linearVelocity)); + debugBox.Add(linearVelocityField); + var linearVelocityMagnitudeField = new FloatField(nameof(Rigidbody.linearVelocity.magnitude)); + debugBox.Add(linearVelocityMagnitudeField); + + + debugBox.schedule.Execute(() => + { + var module = property.boxedValue as UnitMovementModule; + groundSteepnessField.value = module.groundSteepness; + isOnGroundField.value = module.isOnGround; + rotateYawField.value = module.rotateYaw; + moveVectorField.value = module.accelerationVector; + linearVelocityField.value = module.parent.rigidbody.linearVelocity; + linearVelocityMagnitudeField.value = module.parent.rigidbody.linearVelocity.magnitude; + }).Every(100); + + return debugBox; + } + } +} \ No newline at end of file diff --git a/RPGCore.Movement/Editor/Drawers/UnitMovementModuleDrawer.cs.meta b/RPGCore.Movement/Editor/Drawers/UnitMovementModuleDrawer.cs.meta new file mode 100644 index 0000000..e2a8ea4 --- /dev/null +++ b/RPGCore.Movement/Editor/Drawers/UnitMovementModuleDrawer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3acb507069ca47ceb32fc3b5be9da459 +timeCreated: 1768928385 \ No newline at end of file diff --git a/RPGCore.Movement/Editor/RPGCore.Movement.Editor.asmdef b/RPGCore.Movement/Editor/RPGCore.Movement.Editor.asmdef new file mode 100644 index 0000000..6296e13 --- /dev/null +++ b/RPGCore.Movement/Editor/RPGCore.Movement.Editor.asmdef @@ -0,0 +1,21 @@ +{ + "name": "RPGCore.Movement.Editor", + "rootNamespace": "RPGCore.Movement.Editor", + "references": [ + "RPGCore", + "RPGCore.Editor", + "RPGCore.Movement", + "RPGCoreCommon.Helpers" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/RPGCore.Movement/Editor/RPGCore.Movement.Editor.asmdef.meta b/RPGCore.Movement/Editor/RPGCore.Movement.Editor.asmdef.meta new file mode 100644 index 0000000..4f2b551 --- /dev/null +++ b/RPGCore.Movement/Editor/RPGCore.Movement.Editor.asmdef.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 162316575de365d43817366fcbce56bf +timeCreated: 1772973849 \ No newline at end of file diff --git a/RPGCore.Movement/Runtime.meta b/RPGCore.Movement/Runtime.meta new file mode 100644 index 0000000..9dea39e --- /dev/null +++ b/RPGCore.Movement/Runtime.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7279c3bc406a2804bb2e7023c56f56cb +timeCreated: 1772973844 \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/MovementSettings.cs b/RPGCore.Movement/Runtime/MovementSettings.cs new file mode 100644 index 0000000..fd2ae06 --- /dev/null +++ b/RPGCore.Movement/Runtime/MovementSettings.cs @@ -0,0 +1,13 @@ +using RPGCore.StatusEffect.ObjectModules.StatusObjectModule; +using RPGCoreCommon.Settings; +using UnityEngine; + +namespace RPGCore.Movement +{ + [CustomSettings("RPG Core/Movement")] + public class MovementSettings : CustomSettingsSO + { + [Header("Statuses Definitions")] + public StatusDefinitionSO runStatusDefinitionSO; + } +} \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/MovementSettings.cs.meta b/RPGCore.Movement/Runtime/MovementSettings.cs.meta new file mode 100644 index 0000000..ca4f083 --- /dev/null +++ b/RPGCore.Movement/Runtime/MovementSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ed5576b120bd480796129f99e38965a5 +timeCreated: 1772991814 \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules.meta b/RPGCore.Movement/Runtime/ObjectModules.meta new file mode 100644 index 0000000..f2d7e56 --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7c3413a6703346cfb369fc7a8959562f +timeCreated: 1772991398 \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitAnimator.meta b/RPGCore.Movement/Runtime/ObjectModules/UnitAnimator.meta new file mode 100644 index 0000000..1a9382b --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitAnimator.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7dba86a6b4be4134866887f89495c479 +timeCreated: 1767463510 \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitAnimator/UnitAnimatorModule.cs b/RPGCore.Movement/Runtime/ObjectModules/UnitAnimator/UnitAnimatorModule.cs new file mode 100644 index 0000000..a49c7fc --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitAnimator/UnitAnimatorModule.cs @@ -0,0 +1,102 @@ +using System; +using RPGCore.Movement.ObjectModules.UnitMovement; +using RPGCore.Movement.ObjectModules.UnitMovement.Events; +using RPGCore.Core; +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; +using RPGCoreCommon.Helpers; +using UnityEngine; + +namespace RPGCore.Movement.ObjectModules.UnitAnimator +{ + [Serializable] + [RequireComponent(typeof(UnitObject))] + [RequireComponent(typeof(UnitMovementModule))] + public class UnitAnimatorModule : ObjectModule + { + // CONSTANT (defined in animator) + private static readonly int BaseLayer = 0; + private static readonly int VelocityMagnitude = Animator.StringToHash("VELOCITY_MAGNITUDE"); + private static readonly int DirectionX = Animator.StringToHash("DIRECTION_X"); + private static readonly int DirectionZ = Animator.StringToHash("DIRECTION_Z"); + private static readonly int MoveAnimSpeed = Animator.StringToHash("MOVE_ANIM_SPEED"); + private static readonly int JumpTrigger = Animator.StringToHash("JUMP_TRIGGER"); + private static readonly int IsOnGround = Animator.StringToHash("IS_ON_GROUND"); + + // SERIALIZED + [SerializeField] private Animator _animator; + + [Header("Movement animation speed - used for animation speed scaling")] + [SerializeField] private float _sprintSpeed = 6f; + [SerializeField] private float _runSpeed = 3f; + + [Header("Animation spine helper")] + [SerializeField] private bool _spineHelper; + [SerializeField] private Transform _hips; + [SerializeField] private Transform _spine; + [SerializeField] private Quaternion _spineRotation; + + private void OnValidate() + { + if (!_animator) + { + _animator = parent.GetComponentInChildren(); + UnityEditor.EditorUtility.SetDirty(parent.gameObject); + } + + if (_animator) + { + _hips = _animator.GetBoneTransform(HumanBodyBones.Hips); + _spine = _animator.GetBoneTransform(HumanBodyBones.Spine); + _spineRotation = _spine.localRotation; + } + } + + private void Awake() + { + parent.events.Register(_ => _animator.SetTrigger(JumpTrigger)); + parent.events.Register(_ => _animator.SetBool(IsOnGround, true)); + parent.events.Register(_ => _animator.SetBool(IsOnGround, false)); + } + + private void Start() + { + _animator.SetBool(IsOnGround, parent.GetComponent().isOnGround); + } + + private void LateUpdate() + { + if (_spineHelper) _spine.rotation = _hips.rotation * _spineRotation; + } + + private void FixedUpdate() + { + HandleMoveAnimation(); + } + + private void HandleMoveAnimation() + { + var unitMovement = parent.GetComponent(); + if (!unitMovement.isMoving) + { + _animator.SetFloat(VelocityMagnitude, 0f); + _animator.SetFloat(DirectionX, 0f); + _animator.SetFloat(DirectionZ, 0f); + _animator.SetFloat(MoveAnimSpeed, 1f); + return; + } + + // TODO: tutaj powinno jakoś fajnie brać prędkość TYLKO od ruchu, a nie całego velocity + var relVelocity = parent.transform.InverseTransformDirection(parent.rigidbody.linearVelocity.SetY(0)); + var moveAnimSpeed = relVelocity.magnitude < _runSpeed ? relVelocity.magnitude / _runSpeed + : relVelocity.magnitude > _sprintSpeed ? relVelocity.magnitude / _sprintSpeed + : 1f; + var moveRelativeDirection = relVelocity.normalized; + + _animator.SetFloat(VelocityMagnitude, relVelocity.magnitude); + _animator.SetFloat(DirectionX, moveRelativeDirection.x); + _animator.SetFloat(DirectionZ, moveRelativeDirection.z); + _animator.SetFloat(MoveAnimSpeed, moveAnimSpeed); + } + } +} \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitAnimator/UnitAnimatorModule.cs.meta b/RPGCore.Movement/Runtime/ObjectModules/UnitAnimator/UnitAnimatorModule.cs.meta new file mode 100644 index 0000000..112b099 --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitAnimator/UnitAnimatorModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2196f6792fb64519a9c02abec4cad026 +timeCreated: 1767463517 \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitMovement.meta b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement.meta new file mode 100644 index 0000000..54c0cc2 --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6a57c1cd622649c0ab87034a023c1ae6 +timeCreated: 1766851215 \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions.meta b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions.meta new file mode 100644 index 0000000..3628576 --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 46cdb0a558204291b86aab452972e23e +timeCreated: 1766851215 \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions/DirectionMoveAction.cs b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions/DirectionMoveAction.cs new file mode 100644 index 0000000..0899ff0 --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions/DirectionMoveAction.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections; +using RPGCore.Movement.ObjectModules.UnitMovement.Events; +using RPGCore.ObjectModules.ActionObjectModule; +using RPGCore.ObjectModules.EventObjectModule; +using RPGCore.StatusEffect.ObjectModules.StatusObjectModule; +using RPGCoreCommon.Settings; +using UnityEngine; + +namespace RPGCore.Movement.ObjectModules.UnitMovement.Actions +{ + public class DirectionMoveAction : BaseActionParallel + { + private readonly Func _directionGetter; + + private StatusDefinitionSO _runStatusDefinitionSO; + private StatusModule _unitStatus; + private UnitMovementModule _unitMovement; + + public DirectionMoveAction(Func directionGetter) + { + _directionGetter = directionGetter; + } + + public override void CanDoIt() + { + Check( + unit.GetComponent().IsControllable(), + UnitIsBusyMessage); + } + + protected override void OnDoIt() + { + _runStatusDefinitionSO = SettingsManager.Get().runStatusDefinitionSO; + _unitStatus = unit.GetComponent(); + _unitMovement = unit.GetComponent(); + + var moveStartEvent = new MoveStartEvent{ unit = unit }; + + unit.events.InvokeBefore(moveStartEvent); + Check(!moveStartEvent.isPrevented, ActionWasPreventedMessage); + unit.events.InvokeAfter(moveStartEvent); + + unit.StartCoroutine(MoveCoroutine()); + } + + private IEnumerator MoveCoroutine() + { + while (state == ActionState.Running) + { + _unitMovement.moveInput = _directionGetter(); + yield return new WaitForFixedUpdate(); + } + } + + protected override void OnEndIt() + { + _unitMovement.moveInput = Vector2.zero; + _unitStatus.Remove(_runStatusDefinitionSO); + unit.events.Invoke(new MoveEndEvent{ unit = unit }); + } + + protected override void OnCancelIt() + { + OnEndIt(); + } + } +} \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions/DirectionMoveAction.cs.meta b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions/DirectionMoveAction.cs.meta new file mode 100644 index 0000000..4cf153c --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions/DirectionMoveAction.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e1c38778027246d1afc2fa822bc9826b +timeCreated: 1766851215 \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions/JumpAction.cs b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions/JumpAction.cs new file mode 100644 index 0000000..69f4e76 --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions/JumpAction.cs @@ -0,0 +1,36 @@ +using RPGCore.Movement.ObjectModules.UnitMovement.Events; +using RPGCore.ObjectModules.ActionObjectModule; +using RPGCore.ObjectModules.EventObjectModule; +using RPGCore.StatusEffect.ObjectModules.StatusObjectModule; +using RPGCoreCommon.Helpers; + +namespace RPGCore.Movement.ObjectModules.UnitMovement.Actions +{ + public class JumpAction : BaseActionParallel + { + public override void CanDoIt() + { + Check( + unit.GetComponent().IsControllable(), + UnitIsBusyMessage); + Check( + unit.GetComponent().isOnGround, + "Unit is not on ground."); + } + + protected override void OnDoIt() + { + unit.rigidbody.linearVelocity = unit.rigidbody.linearVelocity.SetY(unit.GetComponent().jumpPower); + unit.events.Invoke(new JumpEvent { unit = unit }); + EndIt(); + } + + protected override void OnEndIt() + { + } + + protected override void OnCancelIt() + { + } + } +} \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions/JumpAction.cs.meta b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions/JumpAction.cs.meta new file mode 100644 index 0000000..a6f70a3 --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions/JumpAction.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: cc5b6c0c9dbe400ba3fb4f085bd3cc28 +timeCreated: 1767009824 \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions/PointMoveAction.cs b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions/PointMoveAction.cs new file mode 100644 index 0000000..cfc9a65 --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions/PointMoveAction.cs @@ -0,0 +1,82 @@ +using System.Collections; +using RPGCore.Movement.ObjectModules.UnitMovement.Events; +using RPGCore.ObjectModules.ActionObjectModule; +using RPGCore.ObjectModules.EventObjectModule; +using RPGCore.StatusEffect.ObjectModules.StatusObjectModule; +using UnityEngine; +using UnityEngine.AI; + +namespace RPGCore.Movement.ObjectModules.UnitMovement.Actions +{ + public class PointMoveAction : BaseActionParallel + { + private readonly Vector3 _destination; + + private UnitMovementModule _unitMovement; + + public PointMoveAction(Vector3 destination) + { + _destination = destination; + } + + public override void CanDoIt() + { + Check( + unit.GetComponent().IsControllable(), + UnitIsBusyMessage); + } + + protected override void OnDoIt() + { + _unitMovement = unit.GetComponent(); + + var moveStartEvent = new MoveStartEvent{ unit = unit }; + + unit.events.InvokeBefore(moveStartEvent); + Check(!moveStartEvent.isPrevented, ActionWasPreventedMessage); + unit.events.InvokeAfter(moveStartEvent); + + unit.StartCoroutine(MovePoint_Coroutine()); + } + + private IEnumerator MovePoint_Coroutine() + { + var agent = unit.GetComponent(); + agent.SetDestination(_destination); + + var lastPosition = agent.transform.position; + + while (state == ActionState.Running) + { + var speed = agent.speed = _unitMovement.moveMaxSpeed; + if (agent.remainingDistance <= speed * Time.fixedDeltaTime) + { + EndIt(); + yield break; + }; + + yield return new WaitForFixedUpdate(); + // unit.GetModule().Invoke(new MoveEvent + // { + // unit = unit, + // lastPosition = lastPosition, + // currentPosition = unit.transform.position + // }); + // + // lastPosition = unit.transform.position; + } + } + + protected override void OnEndIt() + { + unit.GetComponent().isStopped = true; + unit.GetComponent().enabled = false; + unit.events.Invoke(new MoveEndEvent{ unit = unit }); + } + + protected override void OnCancelIt() + { + OnEndIt(); + } + } +} \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions/PointMoveAction.cs.meta b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions/PointMoveAction.cs.meta new file mode 100644 index 0000000..aeb9971 --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions/PointMoveAction.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f3f6bf1842e54f00a5a385f9e2e4ba89 +timeCreated: 1766851215 \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions/RotateAction.cs b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions/RotateAction.cs new file mode 100644 index 0000000..74b96ad --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions/RotateAction.cs @@ -0,0 +1,121 @@ +using System.Collections; +using RPGCore.ObjectModules.ActionObjectModule; +using RPGCore.StatusEffect.ObjectModules.StatusObjectModule; +using UnityEngine; + +namespace RPGCore.Movement.ObjectModules.UnitMovement.Actions +{ + public class RotateAction : BaseActionParallel + { + private Coroutine _rotateCoroutine; + + private readonly bool _isEndless; + private float _targetYaw; + private readonly float _rotationSpeed; + private readonly bool _isForced; + + public RotateAction(float rotationSpeed = 0) + { + _isEndless = true; + _rotationSpeed = rotationSpeed; + } + + public RotateAction(float targetYaw, float rotationSpeed = 0, bool isForced = false) + { + _targetYaw = targetYaw; + _rotationSpeed = rotationSpeed; + _isForced = isForced; + } + + public RotateAction(Vector3 lookAt, float rotationSpeed = 0, bool isForced = false) + { + _targetYaw = Quaternion.LookRotation(lookAt - unit.transform.position).eulerAngles.y; + _rotationSpeed = rotationSpeed; + _isForced = isForced; + } + + public void SetYaw(float targetYaw) + { + if (!_isEndless) + { + Debug.LogWarning($"Usage {nameof(SetYaw)} available only when rotating is endless."); + return; + } + + _targetYaw = targetYaw; + } + + public override bool IsInRange() => true; + + public override void CanDoIt() + { + Check( + _isForced || unit.GetComponent().IsControllable(), + UnitIsBusyMessage); + } + + protected override void OnDoIt() + { + BeforePerform(); + + // Instant rotation + if (_rotationSpeed <= 0) + { + Rotate(_targetYaw); + + AfterPerform(); + EndIt(); + return; + } + + // Endless rotation + if (_isEndless) + { + _rotateCoroutine = unit.StartCoroutine(RotationEndlessCoroutine()); + return; + } + + // Simple rotation to given yaw + _rotateCoroutine = unit.StartCoroutine(RotationCoroutine()); + } + + private IEnumerator RotationCoroutine() + { + while (Mathf.Approximately(unit.transform.rotation.eulerAngles.y, _targetYaw) == false) + { + var deltaYaw = Mathf.DeltaAngle(unit.rigidbody.rotation.eulerAngles.y, _targetYaw); + var deltaYawClamped = Mathf.Sign(deltaYaw) * Mathf.Clamp(Mathf.Abs(deltaYaw), 0, Time.fixedDeltaTime * _rotationSpeed); + Rotate(unit.rigidbody.rotation.eulerAngles.y + deltaYawClamped); + yield return new WaitForFixedUpdate(); + } + + AfterPerform(); + EndIt(); + } + + private IEnumerator RotationEndlessCoroutine() + { + while (state is ActionState.Running) + { + var deltaYaw = Mathf.DeltaAngle(unit.rigidbody.rotation.eulerAngles.y, _targetYaw); + var deltaYawClamped = Mathf.Sign(deltaYaw) * Mathf.Clamp(Mathf.Abs(deltaYaw), 0, Time.fixedDeltaTime * _rotationSpeed); + Rotate(unit.rigidbody.rotation.eulerAngles.y + deltaYawClamped); + yield return new WaitForFixedUpdate(); + } + } + + private void Rotate(float yaw) + { + var targetRotation = unit.transform.rotation.eulerAngles; + targetRotation.y = yaw; + unit.rigidbody.MoveRotation(Quaternion.Euler(targetRotation)); + } + + protected override void OnEndIt() { } + + protected override void OnCancelIt() + { + if (_rotateCoroutine != null) unit.StopCoroutine(_rotateCoroutine); + } + } +} \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions/RotateAction.cs.meta b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions/RotateAction.cs.meta new file mode 100644 index 0000000..160a4c2 --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Actions/RotateAction.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4a1273895fb44296a471ede97605bd81 +timeCreated: 1764945728 \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events.meta b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events.meta new file mode 100644 index 0000000..84f1360 --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 841fa5826a24421b852fadaa4260f889 +timeCreated: 1767011733 \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/FallEvent.cs b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/FallEvent.cs new file mode 100644 index 0000000..aacbb9f --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/FallEvent.cs @@ -0,0 +1,10 @@ +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; + +namespace RPGCore.Movement.ObjectModules.UnitMovement.Events +{ + public class FallEvent : BaseEvent + { + public UnitObject unit; + } +} \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/FallEvent.cs.meta b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/FallEvent.cs.meta new file mode 100644 index 0000000..7a900ea --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/FallEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0b7fc3e61e8846d48c8868b8253e295d +timeCreated: 1767701919 \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/JumpEvent.cs b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/JumpEvent.cs new file mode 100644 index 0000000..91bd8df --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/JumpEvent.cs @@ -0,0 +1,10 @@ +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; + +namespace RPGCore.Movement.ObjectModules.UnitMovement.Events +{ + public class JumpEvent : BaseEvent + { + public UnitObject unit; + } +} \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/JumpEvent.cs.meta b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/JumpEvent.cs.meta new file mode 100644 index 0000000..0a02b4b --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/JumpEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: cc29c81dd0c64023aa5d8ba1608a5109 +timeCreated: 1767011739 \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/LandEvent.cs b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/LandEvent.cs new file mode 100644 index 0000000..1bb131f --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/LandEvent.cs @@ -0,0 +1,10 @@ +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; + +namespace RPGCore.Movement.ObjectModules.UnitMovement.Events +{ + public class LandEvent : BaseEvent + { + public UnitObject unit; + } +} \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/LandEvent.cs.meta b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/LandEvent.cs.meta new file mode 100644 index 0000000..e729a86 --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/LandEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 736b6bd7402549f3954c98dd4b77bd1a +timeCreated: 1767693252 \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/MoveEndEvent.cs b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/MoveEndEvent.cs new file mode 100644 index 0000000..a2473d0 --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/MoveEndEvent.cs @@ -0,0 +1,10 @@ +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; + +namespace RPGCore.Movement.ObjectModules.UnitMovement.Events +{ + public class MoveEndEvent : BaseEvent + { + public UnitObject unit; + } +} \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/MoveEndEvent.cs.meta b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/MoveEndEvent.cs.meta new file mode 100644 index 0000000..7808073 --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/MoveEndEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: af2ba162e26047babe441e19fa6a4919 +timeCreated: 1765976043 \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/MoveStartEvent.cs b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/MoveStartEvent.cs new file mode 100644 index 0000000..cfe2442 --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/MoveStartEvent.cs @@ -0,0 +1,10 @@ +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; + +namespace RPGCore.Movement.ObjectModules.UnitMovement.Events +{ + public class MoveStartEvent : BasePreventableEvent + { + public UnitObject unit; + } +} \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/MoveStartEvent.cs.meta b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/MoveStartEvent.cs.meta new file mode 100644 index 0000000..0950af0 --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/Events/MoveStartEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 95e49f3e87aa4cec98bd652309ba90c9 +timeCreated: 1765976027 \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/UnitMovementModule.cs b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/UnitMovementModule.cs new file mode 100644 index 0000000..e168ea9 --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/UnitMovementModule.cs @@ -0,0 +1,296 @@ +using System; +using RPGCore.Movement.ObjectModules.UnitMovement.Events; +using RPGCore.Movement.ObjectModules.UnitMovement.Actions; +using RPGCore.Core; +using RPGCore.Core.Objects; +using RPGCoreCommon.Helpers; +using RPGCoreCommon.Settings; +using UnityEngine; +using UnityEngine.AI; + +namespace RPGCore.Movement.ObjectModules.UnitMovement +{ + [Serializable] + [RequireComponent(typeof(UnitObject))] + [RequireComponent(typeof(CapsuleCollider))] + public class UnitMovementModule : ObjectModule + { + // SERIALIZED + [Header("General")] + [SerializeField] public float skin = 0.03f; + [SerializeField] public float groundDistance = 0.1f; + [SerializeField] public float groundFriction = 5f; + [Header("On Ground")] + [SerializeField] public float moveMaxSpeed = 3f; + [SerializeField] public float moveMaxSlope = 45f; + [SerializeField] public float groundAcceleration = 15f; + [SerializeField] public float sprintSpeedMultiplier = 2f; + [SerializeField] public float sprintMaxDeviation = 67.5f; + [SerializeField] public float jumpPower = 5f; + [Header("In Air")] + [SerializeField] public float airMaxSpeed = 3f; + [SerializeField] public float airAcceleration = 1.5f; + [SerializeField] public float gravity = 9.81f; + [SerializeField] public float fallMaxSpeed = 20f; + [Header("(optional) Rotation")] + [SerializeField] public float rotationSpeed = 180f; + [SerializeField] public UnitMovementRotateType rotateType; + + // RUNTIME + private RotateAction _rotateAction; + + public RaycastHit groundHit { get; private set; } + public float groundSteepness { get; private set; } + public float groundAngle { get; private set; } + public bool isOnGround { get; private set; } + public float rotateYaw { get; set; } + public Vector3 accelerationVector { get; private set; } + public Vector3 moveInput { get; set; } + public bool isMoving { get; private set; } + public bool isSprinting { get; set; } + + private void Awake() + { + var agent = parent.GetComponent(); + agent.enabled = false; + agent.speed = moveMaxSpeed; + agent.updateRotation = false; + + parent.events.RegisterAfter(OnMoveStart); + parent.events.Register(OnMoveEnd); + } + + private void FixedUpdate() + { + CheckGround(); + HandleGroundFriction(); + HandleMovement(); + HandleGravity(); + + HandleRotation(); + } + + private void HandleMovement() + { + if (moveInput == Vector3.zero) + { + isSprinting = false; + return; + } + + // TODO: ruch rampą w górę i zaczyna się pozioma podłoga - jeśli velocity.y podobne do accelerationVector.y to wtedy snapping? + + CheckForwardSprint(); + accelerationVector = moveInput * (GetSpeed() * Time.fixedDeltaTime); + MovementOnGroundNormal(); + MovementOnObstacle(); + + AddMoveVectorToVelocity(); + } + + private void CheckForwardSprint() + { + var unitYaw = parent.rigidbody.rotation.eulerAngles.y; + var moveYaw = Mathf.Atan2(moveInput.x, moveInput.z) * Mathf.Rad2Deg; + + if (Mathf.Abs(Mathf.DeltaAngle(unitYaw, moveYaw)) < sprintMaxDeviation) return; + + isSprinting = false; + } + + private float GetSpeed() + { + var speed = isOnGround ? groundAcceleration : airAcceleration; + if (isSprinting) speed *= sprintSpeedMultiplier; + return speed; + } + + private void MovementOnGroundNormal() + { + if (groundAngle > moveMaxSlope) return; + accelerationVector = Quaternion.FromToRotation(Vector3.up, groundHit.normal) * accelerationVector; + } + + private void MovementOnObstacle() + { + const int limit = 3; + + var currentPosition = parent.rigidbody.position; + var tempPosition = currentPosition; + var tempDirection = accelerationVector.normalized; + var tempDistance = accelerationVector.magnitude; + + for (var i = 1; i <= limit; i++) + { + var isHit = Physics.CapsuleCast( + tempPosition.AddY(parent.unitCollider.radius), + tempPosition.AddY(parent.unitCollider.height - parent.unitCollider.radius), + parent.unitCollider.radius, + tempDirection, + out var hit, + tempDistance, + 1 << SettingsManager.Get().staticLayer + ); + + if (!isHit) + { + // No obstacle found + accelerationVector = tempPosition + tempDirection * tempDistance - currentPosition; + return; + } + + tempPosition += tempDirection * (hit.distance - skin); + tempDistance -= hit.distance - skin; + + if (i == limit) + { + // Checks reached limit - dont check further + accelerationVector = tempPosition - currentPosition; + return; + } + + var planeNormal = hit.normal; + if (Vector3.Angle(hit.normal, Vector3.up) > moveMaxSlope) planeNormal = planeNormal.SetY(0).normalized; + var projectedVector = Vector3.ProjectOnPlane(tempDirection * tempDistance, planeNormal); + + tempDistance = projectedVector.magnitude; + tempDirection = projectedVector.normalized; + } + + throw new Exception($"{nameof(MovementOnObstacle)} - this should never be reached!"); + } + + private void AddMoveVectorToVelocity() + { + var speed = Vector3.Dot(parent.rigidbody.linearVelocity, accelerationVector.normalized); + var maxSpeed = isOnGround ? moveMaxSpeed : airMaxSpeed; + if (isSprinting) maxSpeed *= sprintSpeedMultiplier; + var possibleSpeed = maxSpeed - speed; + + if (possibleSpeed <= 0) return; + + var moveVectorMultiplier = Mathf.Min(possibleSpeed / accelerationVector.magnitude, 1f); + parent.rigidbody.linearVelocity += accelerationVector * moveVectorMultiplier; + } + + private void CheckGround() + { + var groundFound = Physics.SphereCast( + parent.transform.position.AddY(parent.unitCollider.radius), + parent.unitCollider.radius - skin, + Vector3.down, + out var hit, + skin + groundDistance, + 1 << SettingsManager.Get().staticLayer); + groundHit = hit; + + groundAngle = 90f; + groundSteepness = 1f; + + if (groundFound) + { + groundAngle = Vector3.Angle(groundHit.normal, Vector3.up); + groundSteepness = 0f; + + if (groundAngle > moveMaxSlope) + { + groundSteepness = Mathf.InverseLerp(0f, 90f, groundAngle); + groundFound = false; + } + } + + var wasOnGround = isOnGround; + isOnGround = groundFound; + + if (wasOnGround && !isOnGround) + parent.events.Invoke(new FallEvent { unit = parent }); + + if (!wasOnGround && isOnGround) + parent.events.Invoke(new LandEvent { unit = parent }); + } + + private void HandleGravity() + { + if (groundSteepness <= 0f) + { + // Ground below - push a little bit towards ground + parent.rigidbody.linearVelocity -= groundHit.normal * Time.fixedDeltaTime; + } + else + { + // Airborne - falling + var newVelocity = parent.rigidbody.linearVelocity.AddY(- gravity * Time.fixedDeltaTime); + newVelocity.y = Mathf.Max(newVelocity.y, - fallMaxSpeed); + parent.rigidbody.linearVelocity = newVelocity; + } + } + + private void HandleGroundFriction() + { + if (!isOnGround) return; + if (groundSteepness >= 0.99f) return; + + var velocity = parent.rigidbody.linearVelocity; + velocity -= velocity * (groundFriction * (1 - groundSteepness) * Time.fixedDeltaTime); + + if (Mathf.Abs(velocity.x) < 0.03f) velocity.x = 0f; + if (Mathf.Abs(velocity.y) < 0.03f) velocity.y = 0f; + if (Mathf.Abs(velocity.z) < 0.03f) velocity.z = 0f; + + parent.rigidbody.linearVelocity = velocity; + } + + private void HandleRotation() + { + // Rotation disabled - wasn't rotating before - do nothing + if (rotateType is UnitMovementRotateType.None && _rotateAction == null) return; + + // Rotation enabled - wasn't rotating before - start rotating + if (rotateType is not UnitMovementRotateType.None && _rotateAction == null) + { + _rotateAction = new RotateAction(rotationSpeed); + parent.actions.Execute(_rotateAction); + } + + // Rotating disabled - was rotating before - stop rotating + if (rotateType is UnitMovementRotateType.None && _rotateAction != null) + { + _rotateAction.CancelIt(); + _rotateAction = null; + } + + if (_rotateAction == null) return; + + switch (rotateType) + { + case UnitMovementRotateType.MoveDirection: + // Rotating enabled - was rotating before - update rotating yaw to movement direction + _rotateAction.SetYaw(Quaternion.LookRotation(accelerationVector).eulerAngles.y); + break; + case UnitMovementRotateType.CustomDirection: + // Rotating enabled - was rotating before - update rotating yaw to custom direction + _rotateAction.SetYaw(rotateYaw); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + public void OnMoveStart(MoveStartEvent ev) + { + isMoving = true; + } + + public void OnMoveEnd(MoveEndEvent ev) + { + isMoving = false; + accelerationVector = Vector3.zero; + + if (_rotateAction != null) + { + _rotateAction.CancelIt(); + _rotateAction = null; + } + } + } +} \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/UnitMovementModule.cs.meta b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/UnitMovementModule.cs.meta new file mode 100644 index 0000000..bbb71bb --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/UnitMovementModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ee3a8e7f717c4c93a0a50c4cc63dbfd8 +timeCreated: 1766851215 \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/UnitMovementRotateType.cs b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/UnitMovementRotateType.cs new file mode 100644 index 0000000..5964b40 --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/UnitMovementRotateType.cs @@ -0,0 +1,9 @@ +namespace RPGCore.Movement.ObjectModules.UnitMovement +{ + public enum UnitMovementRotateType + { + None, + MoveDirection, + CustomDirection + } +} \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/UnitMovementRotateType.cs.meta b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/UnitMovementRotateType.cs.meta new file mode 100644 index 0000000..0d23c3c --- /dev/null +++ b/RPGCore.Movement/Runtime/ObjectModules/UnitMovement/UnitMovementRotateType.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 08f3aae92c8a45a981b20fbdc3853995 +timeCreated: 1766851215 \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/RPGCore.Movement.asmdef b/RPGCore.Movement/Runtime/RPGCore.Movement.asmdef new file mode 100644 index 0000000..08e6aa9 --- /dev/null +++ b/RPGCore.Movement/Runtime/RPGCore.Movement.asmdef @@ -0,0 +1,21 @@ +{ + "name": "RPGCore.Movement", + "rootNamespace": "RPGCore.Movement", + "references": [ + "RPGCore", + "RPGCore.StatusEffect", + "RPGCoreCommon.Settings", + "RPGCoreCommon.Helpers", + "RPGCoreCommon.DynamicValues", + "Unity.InputSystem" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/RPGCore.Movement.asmdef.meta b/RPGCore.Movement/Runtime/RPGCore.Movement.asmdef.meta new file mode 100644 index 0000000..65360cf --- /dev/null +++ b/RPGCore.Movement/Runtime/RPGCore.Movement.asmdef.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 303c9d18d970e6d45b9e4c2e7463d65e +timeCreated: 1772973851 \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/SceneModules.meta b/RPGCore.Movement/Runtime/SceneModules.meta new file mode 100644 index 0000000..6a8cf33 --- /dev/null +++ b/RPGCore.Movement/Runtime/SceneModules.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 35a260cdc6714e458f1fd2a09a5b6c62 +timeCreated: 1772991392 \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/SceneModules/ActionController.meta b/RPGCore.Movement/Runtime/SceneModules/ActionController.meta new file mode 100644 index 0000000..159d610 --- /dev/null +++ b/RPGCore.Movement/Runtime/SceneModules/ActionController.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3e40e139c6f3461889e756cc52010af8 +timeCreated: 1766851215 \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/SceneModules/ActionController/ActionCameraModule.cs b/RPGCore.Movement/Runtime/SceneModules/ActionController/ActionCameraModule.cs new file mode 100644 index 0000000..d3a6dfd --- /dev/null +++ b/RPGCore.Movement/Runtime/SceneModules/ActionController/ActionCameraModule.cs @@ -0,0 +1,78 @@ +using System; +using RPGCore.Core; +using UnityEngine; +using UnityEngine.InputSystem; + +namespace RPGCore.Movement.SceneModules.ActionController +{ + [Serializable] + public class ActionCameraModule : SceneModule + { + [Header("Camera Rotate and Tilt")] + [SerializeField, Range(0.01f, 1f)] private float _rotateSensitivity = 0.1f; + [SerializeField, Range(0.01f, 1f)] private float _tiltSensitivity = 0.06f; + [SerializeField] private Vector2 _tiltLimit = new(20f, 85f); // 10 - 90 + + [Header("Camera Zoom")] + [SerializeField, Range(0.05f, 1f)] private float _zoomSensitivity = 0.3f; + [SerializeField] private Vector2 _zoomLimit = new(2f, 15f); // 1 - 30 + [SerializeField] private float _zoomCurrent = 8f; + + [Header("Input Actions")] + [SerializeField] private InputActionReference _rotateAndTiltInput; + [SerializeField] private InputActionReference _zoomInput; + + // RUNTIME + private Camera _camera; + + [Header("Camera target position")] + public Transform stickTo; + [SerializeField] private Vector3 _offset; + + private void Awake() + { + _camera = Camera.main; + Cursor.lockState = CursorLockMode.Locked; + } + + private void Update() + { + RotateAndTiltCamera(); + ZoomCamera(); + MoveCamera(); + } + + private void RotateAndTiltCamera() + { + if (!_rotateAndTiltInput || !_rotateAndTiltInput.action.inProgress) return; + + var delta = _rotateAndTiltInput.action.ReadValue(); + var tiltDelta = delta.y * _tiltSensitivity * -1; + var rotateDelta = delta.x * _rotateSensitivity; + + var previousEuler = _camera.transform.rotation.eulerAngles; + var nextEuler = previousEuler + new Vector3(tiltDelta, rotateDelta, 0); + + if (nextEuler.x < _tiltLimit.x) nextEuler.x = _tiltLimit.x; + if (nextEuler.x > _tiltLimit.y) nextEuler.x = _tiltLimit.y; + + _camera.transform.rotation = Quaternion.Euler(nextEuler); + } + + private void ZoomCamera() + { + if (!_zoomInput || !_zoomInput.action.inProgress) return; + + _zoomCurrent -= _zoomInput.action.ReadValue() * _zoomSensitivity; + + if (_zoomCurrent > _zoomLimit.y) _zoomCurrent = _zoomLimit.y; + if (_zoomCurrent < _zoomLimit.x) _zoomCurrent = _zoomLimit.x; + } + + private void MoveCamera() + { + var toPosition = stickTo.position - _camera.transform.forward * _zoomCurrent; + _camera.transform.position = toPosition + _camera.transform.TransformDirection(_offset); + } + } +} \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/SceneModules/ActionController/ActionCameraModule.cs.meta b/RPGCore.Movement/Runtime/SceneModules/ActionController/ActionCameraModule.cs.meta new file mode 100644 index 0000000..e5143c1 --- /dev/null +++ b/RPGCore.Movement/Runtime/SceneModules/ActionController/ActionCameraModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9460d10ec97244dbb73bb37ab1aec54e +timeCreated: 1766851215 \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/SceneModules/ActionController/ActionControllerModule.cs b/RPGCore.Movement/Runtime/SceneModules/ActionController/ActionControllerModule.cs new file mode 100644 index 0000000..ad0f852 --- /dev/null +++ b/RPGCore.Movement/Runtime/SceneModules/ActionController/ActionControllerModule.cs @@ -0,0 +1,66 @@ +using System; +using RPGCore.Movement.ObjectModules.UnitMovement; +using RPGCore.Core; +using RPGCore.Core.Objects; +using RPGCore.Movement.ObjectModules.UnitMovement.Actions; +using RPGCore.ObjectModules.ActionObjectModule; +using RPGCoreCommon.Helpers; +using UnityEngine; +using UnityEngine.InputSystem; + +namespace RPGCore.Movement.SceneModules.ActionController +{ + [Serializable] + [RequireComponent(typeof(ActionCameraModule))] + public class ActionControllerModule : SceneModule + { + [SerializeField] private UnitObject _unit; + [SerializeField] private InputActionReference _rotateInput; + [SerializeField] private InputActionReference _moveInput; + [SerializeField] private InputActionReference _moveFasterInput; + [SerializeField] private InputActionReference _jumpInput; + + private Camera _camera; + private BaseActionParallel _moveAction; + + private void Awake() + { + _camera = Camera.main; + } + + private void Start() + { + var movementModule = _unit.GetComponent(); + + _rotateInput.action.performed += _ => + { + movementModule.rotateYaw = _camera.transform.rotation.eulerAngles.y; + }; + + _moveInput.action.performed += _ => + { + _moveAction = new DirectionMoveAction(GetDirection); + _unit.actions.Execute(_moveAction); + }; + _moveInput.action.canceled += _ => + { + _moveAction?.CancelIt(); + _moveAction = null; + }; + + _moveFasterInput.action.performed += _ => movementModule.isSprinting = true; + _moveFasterInput.action.canceled += _ => movementModule.isSprinting = false; + + _jumpInput.action.performed += _ => _unit.actions.Execute(new JumpAction()); + + movementModule.rotateType = UnitMovementRotateType.CustomDirection; + } + + private Vector3 GetDirection() + { + var input = _moveInput.action.ReadValue(); + return _camera.transform.right.SetY(0).normalized * input.x + + _camera.transform.forward.SetY(0).normalized * input.y; + } + } +} \ No newline at end of file diff --git a/RPGCore.Movement/Runtime/SceneModules/ActionController/ActionControllerModule.cs.meta b/RPGCore.Movement/Runtime/SceneModules/ActionController/ActionControllerModule.cs.meta new file mode 100644 index 0000000..862c965 --- /dev/null +++ b/RPGCore.Movement/Runtime/SceneModules/ActionController/ActionControllerModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f54b0d5fd319467da310ffc54509377a +timeCreated: 1766851215 \ No newline at end of file diff --git a/RPGCore.Stats.meta b/RPGCore.Stats.meta new file mode 100644 index 0000000..f6e8f97 --- /dev/null +++ b/RPGCore.Stats.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 50543e480ae64a3eb8fcb859d3bac16e +timeCreated: 1773954571 \ No newline at end of file diff --git a/RPGCore.Stats/Editor.meta b/RPGCore.Stats/Editor.meta new file mode 100644 index 0000000..9217adf --- /dev/null +++ b/RPGCore.Stats/Editor.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ad8746ba38f04d719dd84d28f09a8512 +timeCreated: 1773954611 \ No newline at end of file diff --git a/RPGCore.Stats/Editor/RPGCore.Stats.Editor.asmdef b/RPGCore.Stats/Editor/RPGCore.Stats.Editor.asmdef new file mode 100644 index 0000000..83905c5 --- /dev/null +++ b/RPGCore.Stats/Editor/RPGCore.Stats.Editor.asmdef @@ -0,0 +1,20 @@ +{ + "name": "RPGCore.Stats.Editor", + "rootNamespace": "RPGCore.Stats.Editor", + "references": [ + "RPGCore", + "RPGCore.Stats", + "RPGCoreCommon.Helpers" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/RPGCore.Stats/Editor/RPGCore.Stats.Editor.asmdef.meta b/RPGCore.Stats/Editor/RPGCore.Stats.Editor.asmdef.meta new file mode 100644 index 0000000..9700d80 --- /dev/null +++ b/RPGCore.Stats/Editor/RPGCore.Stats.Editor.asmdef.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2aa3b7d8e0b448e7881e3964a0435cdd +timeCreated: 1773954617 \ No newline at end of file diff --git a/RPGCore.Stats/Runtime.meta b/RPGCore.Stats/Runtime.meta new file mode 100644 index 0000000..9a44a9f --- /dev/null +++ b/RPGCore.Stats/Runtime.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6e8966dae25541459432287ae898c630 +timeCreated: 1773954606 \ No newline at end of file diff --git a/RPGCore.Stats/Runtime/ObjectModules.meta b/RPGCore.Stats/Runtime/ObjectModules.meta new file mode 100644 index 0000000..aea32d3 --- /dev/null +++ b/RPGCore.Stats/Runtime/ObjectModules.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 81ee3e16a1644004b6c4988b06c0a6fd +timeCreated: 1773954672 \ No newline at end of file diff --git a/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule.meta b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule.meta new file mode 100644 index 0000000..6ffaf93 --- /dev/null +++ b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1d9e8c1e38314f68b12ff35c5d870faa +timeCreated: 1762712643 \ No newline at end of file diff --git a/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/Events.meta b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/Events.meta new file mode 100644 index 0000000..9d64ffb --- /dev/null +++ b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/Events.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 813519acd4a241f19fe7bec852b0acda +timeCreated: 1763840115 \ No newline at end of file diff --git a/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/Events/StatResourceChangeEvent.cs b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/Events/StatResourceChangeEvent.cs new file mode 100644 index 0000000..32ef9e5 --- /dev/null +++ b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/Events/StatResourceChangeEvent.cs @@ -0,0 +1,14 @@ +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; + +namespace RPGCore.Stats.ObjectModules.StatsObjectModule.Events +{ + public class StatResourceChangeEvent : BaseEvent + { + public BaseObject target; + public StatDefinitionSO statDefinition; + public int delta; + public int before; + public int after; + } +} \ No newline at end of file diff --git a/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/Events/StatResourceChangeEvent.cs.meta b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/Events/StatResourceChangeEvent.cs.meta new file mode 100644 index 0000000..7c9de82 --- /dev/null +++ b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/Events/StatResourceChangeEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c00f342fabcb4aa6adce19862d88212e +timeCreated: 1763840330 \ No newline at end of file diff --git a/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/Events/StatValueChangeEvent.cs b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/Events/StatValueChangeEvent.cs new file mode 100644 index 0000000..40d87c1 --- /dev/null +++ b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/Events/StatValueChangeEvent.cs @@ -0,0 +1,13 @@ +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; + +namespace RPGCore.Stats.ObjectModules.StatsObjectModule.Events +{ + public class StatValueChangeEvent : BaseEvent + { + public BaseObject target; + public StatDefinitionSO statDefinition; + public int before; + public int after; + } +} \ No newline at end of file diff --git a/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/Events/StatValueChangeEvent.cs.meta b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/Events/StatValueChangeEvent.cs.meta new file mode 100644 index 0000000..61ec43c --- /dev/null +++ b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/Events/StatValueChangeEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: baeb8bd8a9394f428240e3a7ca7b98b4 +timeCreated: 1763840139 \ No newline at end of file diff --git a/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatDefinitionSO.cs b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatDefinitionSO.cs new file mode 100644 index 0000000..6ca0767 --- /dev/null +++ b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatDefinitionSO.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using RPGCore.Core.Objects; +using RPGCoreCommon.DynamicValues; +using RPGCoreCommon.Helpers; +using RPGCoreCommon.Helpers.CustomTypes; +using RPGCoreCommon.Helpers.PropertyAttributeDrawers; +using RPGCoreCommon.Settings; +using UnityEngine; + +namespace RPGCore.Stats.ObjectModules.StatsObjectModule +{ + [CreateAssetMenu(menuName = "RPG Core/Object Stat Definition")] + public sealed class StatDefinitionSO : ScriptableObject + { + [SerializableType(typeof(BaseObject), allowAbstract: true)] public SerializableType attachedTo; + public StatType type; + public StatDefinitionSO overrides; + [ReadOnly(true)] public StatDefinitionSO[] dependencies = {}; + + [DynamicValue(DynamicValueType.ByDynamicTypes)] public DynamicValue dynamicValue = new(); + +#if UNITY_EDITOR + + private void OnValidate() + { + FixDynamicValueType(); + FixOverride(); + FixDependencies(); + CheckDependenciesLooping(); + } + + private void FixDynamicValueType() + { + dynamicValue.RemoveDynamicTypes(); + dynamicValue.SetDynamicType("object", attachedTo); + } + + private void FixOverride() + { + if (!overrides) return; + + // Without attachedTo selected we can't be sure if this overriding can be even done + if (attachedTo == null) + { + Debug.LogWarning($"{nameof(attachedTo)} is required before stat overriding"); + overrides = null; + return; + } + + // We can override only child of "attachedTo" object, otherwise it is pointless + if (overrides.attachedTo.type == attachedTo.type || + overrides.attachedTo.type.IsAssignableFrom(attachedTo.type) == false) + { + Debug.LogWarning($"When overriding this {nameof(attachedTo)} MUST BE child child type of {nameof(attachedTo)}"); + overrides = null; + return; + } + + name = overrides.name; + type = overrides.type; + } + + /// + /// has custom value provider that matches stats by their name. + /// We will match these names with marker's parameter to create list of other that this one uses. + /// Main purpose of dependencies is caching, specially when there is a lot of definitions and dependencies. + /// + private void FixDependencies() + { + var tempDependencies = new List(); + var allDefinitions = SettingsManager.Get().allStats; + + foreach (var marker in dynamicValue.GetMarkers()) + { + var members = marker.GetMembers(out var membersParameters); + for (var i = 0; i < members.Length; i++) + { + var member = members[i]; + var memberParameter = membersParameters[i]; + + // Dependencies are created only by StatsModule's StatValueProvider! + if (member.DeclaringType != typeof(StatsModule)) continue; + if (member.Name != nameof(StatsModule.StatValueProvider)) continue; + + var dependency = allDefinitions.FirstOrDefault(definition => + definition.name.Equals((string)memberParameter, StringComparison.OrdinalIgnoreCase)); + + if (dependency) + { + tempDependencies.Add(dependency.GetBaseDefinition()); + break; + } + + Debug.LogError($"Stat definition with name {(string)memberParameter} doesn't exist " + + $"or is not added to {nameof(StatsSettings)}!" + + $"Marker {marker.wholeMarker} is invalid!", this); + } + } + + dependencies = tempDependencies.Distinct().ToArray(); + } + + /// + /// Iterates via dependencies to check if none of them loops. + /// If looping is found then dependencies will be cleared, preventing application freeze! + /// + /// + private void CheckDependenciesLooping(List definitionsChain = null) + { + definitionsChain ??= new List(); + + if (definitionsChain.Contains(this)) + { + definitionsChain[0].dependencies = Array.Empty(); + var definitionsChainString = definitionsChain.Append(this).Select(d => d.name).StringJoin(" -> "); + Debug.LogError($"Looped dependencies found! {definitionsChainString}", this); + return; + } + + dependencies.ForEach(dependency => dependency.CheckDependenciesLooping(definitionsChain.Append(this).ToList())); + } + +#endif + + /// + /// Finds first element in this overriding chain. + /// Thanks to OnValidate its impossible to create endless overriding loop, it is possible to override only child object. + /// + /// Last overriden definition + public StatDefinitionSO GetBaseDefinition() + { + var tempDefinition = this; + while (tempDefinition.overrides) + tempDefinition = tempDefinition.overrides; + + return tempDefinition; + } + } +} \ No newline at end of file diff --git a/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatDefinitionSO.cs.meta b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatDefinitionSO.cs.meta new file mode 100644 index 0000000..3987111 --- /dev/null +++ b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatDefinitionSO.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ae9af538607d4890ba7d6e30b46efef7 +timeCreated: 1762712932 \ No newline at end of file diff --git a/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatType.cs b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatType.cs new file mode 100644 index 0000000..e260ca3 --- /dev/null +++ b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatType.cs @@ -0,0 +1,8 @@ +namespace RPGCore.Stats.ObjectModules.StatsObjectModule +{ + public enum StatType + { + Value, + Resource + } +} \ No newline at end of file diff --git a/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatType.cs.meta b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatType.cs.meta new file mode 100644 index 0000000..c9c45cd --- /dev/null +++ b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatType.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1800df1b40e6455abd599f5bb6808735 +timeCreated: 1762771772 \ No newline at end of file diff --git a/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatValue.cs b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatValue.cs new file mode 100644 index 0000000..f092e85 --- /dev/null +++ b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatValue.cs @@ -0,0 +1,109 @@ +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; +using RPGCore.Stats.ObjectModules.StatsObjectModule.Events; +using RPGCoreCommon.DynamicValues; +using UnityEngine; + +namespace RPGCore.Stats.ObjectModules.StatsObjectModule +{ + /// + /// You should never instantiate this by yourself! + /// Instantiated automatically by for every available . + /// + public sealed class StatValue + { + public readonly StatDefinitionSO definition; + private readonly BaseObject _parent; + public readonly DynamicValueSourceContext sourceContext = new(); + + /// + /// Base value defined in attached to . + /// Formula result will be added to this base value. + /// Default base value is ZERO. + /// + public int baseValue { get; private set; } + + /// + /// This value is calculated by in and can have two meanings:
+ /// 1. If - just simple value stat
+ /// 2. If - this is maximum value for that resource + ///
+ public int value { get; private set; } + + /// + /// Usable only when . is .
+ /// This value represent current resource of this stat. Always between and + ///
+ public int resource { get; private set; } + + internal StatValue(StatDefinitionSO definition, int baseValue, BaseObject parent) + { + this.definition = definition; + _parent = parent; + this.baseValue = baseValue; + } + + /// + /// Refreshes , by calculating formula again. + /// + internal void Refresh() + { + var previous = value; + value = baseValue + definition.dynamicValue.GetValue(sourceContext); + _parent.events.Invoke(new StatValueChangeEvent + { + after = value, + before = previous, + statDefinition = definition, + target = _parent + }); + } + + /// + /// Sets new and then do to recalculate whole + /// + /// New base value + public void SetBase(int amount) + { + baseValue = amount; + Refresh(); + } + + /// + /// Changes (or simpler - uses) of this stat value by given amount. + /// It just calls with: + + /// + /// Amount that will be added or subtracted from + public void ChangeResource(int amount) + { + SetResource(resource + amount); + } + + /// + /// Sets to given amount. Amount will be clamped between ZERO and . + /// + /// New amount + public void SetResource(int amount) + { + var old = resource; + resource = Mathf.Clamp(amount, 0, value); + _parent.events.Invoke(new StatResourceChangeEvent + { + delta = resource - old, + after = resource, + before = old, + statDefinition = definition, + target = _parent + }); + } + + /// + /// Sets to given percentage. Percentage will be clamped between ZERO and ONE. + /// + /// New percentage + public void SetResource(float percentage) + { + SetResource(Mathf.CeilToInt(Mathf.Clamp01(percentage) * value)); + } + } +} \ No newline at end of file diff --git a/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatValue.cs.meta b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatValue.cs.meta new file mode 100644 index 0000000..8e69e1b --- /dev/null +++ b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatValue.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e7012414211045ebbaf7f1d3b0cfc911 +timeCreated: 1763222304 \ No newline at end of file diff --git a/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatsModule.cs b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatsModule.cs new file mode 100644 index 0000000..a76b76c --- /dev/null +++ b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatsModule.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using RPGCore.Core; +using RPGCore.Core.Objects; +using RPGCoreCommon.DynamicValues; +using RPGCoreCommon.Helpers; +using RPGCoreCommon.Helpers.CustomTypes; +using RPGCoreCommon.Settings; +using UnityEngine; + +namespace RPGCore.Stats.ObjectModules.StatsObjectModule +{ + [Serializable] + public class StatsModule : ObjectModule + { + [SerializeField] + [SerializableDictionary("Stat Definition", "Base Value", isKeyEditable: false)] + private SerializableDictionary _serializedStats; + + private Dictionary _stats = new(); + private List _queue = new(); + +#if UNITY_EDITOR + + private void OnValidate() + { + FixSerializedStats(); + } + + private void FixSerializedStats() + { + // fixing only when variable is serialized (sometimes OnValidate can be called before deserializing on project open) + if (_serializedStats == null) return; + + // All stat definitions that should be added to this object... + var correctStats = SettingsManager.Get().allStats + .Where(stat => stat) + .Where(stat => stat.attachedTo.type.IsAssignableFrom(parent.GetType())) + .ToList(); + + //... but also remember that some of them can override other's, overriden ones should not be here + correctStats.Select(stat => stat.overrides) + .Where(overridenStat => overridenStat) + .ForEach(overridenStat => correctStats.Remove(overridenStat)); + + // ADD MISSING + var missingStats = correctStats.Except(_serializedStats.Keys).ToList(); + if (missingStats.Any()) + { + missingStats.ForEach(missingStat => _serializedStats.Add(missingStat, 0)); + var missingStatsString = string.Join(", ", missingStats.Select(s => s.name)); + Debug.LogWarning($"[StatsModule] automatically adding missing stats: {missingStatsString}", parent); + UnityEditor.EditorUtility.SetDirty(parent.gameObject); + } + + // REMOVE INVALID + var invalidStats = _serializedStats.Keys.Except(correctStats).ToList(); + if (invalidStats.Any()) + { + invalidStats.ForEach(invalidStat => _serializedStats.Remove(invalidStat)); + var invalidStatsString = string.Join(", ", invalidStats.Select(missingStat => missingStat.name)); + Debug.LogWarning($"[StatsModule] automatically removing invalid stats: {invalidStatsString}", parent); + UnityEditor.EditorUtility.SetDirty(parent.gameObject); + + } + } + +#endif + + [DynamicValueProvider] + internal StatValue StatValueProvider(string name) + { + return _stats.GetValueOrDefault(_stats.Keys.FirstOrDefault(def => def.name == name)); + } + + private void Awake() + { + // Create instances of all stats that will be used runtime + CreateStats(); + } + + private void Start() + { + // First stats refresh + _stats.Keys.ForEach(AddToQueueRefresh); + QueueRefresh(); + } + + private void FixedUpdate() + { + if (_queue.Count > 0) QueueRefresh(); + } + + /// + /// Really important part - we create stats for runtime usage. + /// can also override another one, in that case + /// uses main definition, but it is visible as that overriden one. + /// + private void CreateStats() + { + _serializedStats.DictForEach((statDefinition, baseValue) => + { + var baseDefinition = statDefinition.GetBaseDefinition(); + var statValue = new StatValue(statDefinition, baseValue, parent); + statValue.sourceContext.SetSource("object", parent); + _stats.Add(baseDefinition, statValue); + }); + } + + /// + /// Returns runtime values for given stat definition. + /// + /// Runtime stats will be found by this definition (or overriden definition if given) + /// Stat values (baseValue, value, resource) + public StatValue Get(StatDefinitionSO statDefinitionSO) + { +#if UNITY_EDITOR + if (!UnityEditor.EditorApplication.isPlaying) CreateStats(); +#endif + return _stats.GetValueOrDefault(statDefinitionSO.GetBaseDefinition()); + } + + /// + /// Refreshing stats, every stat only once even if queued multiple times. + /// To ensure that dependencies should be refreshed before definition that is using it. + /// + private void QueueRefresh() + { + _queue + .Select(def => Get(def).definition) + .Sort((d1, d2) => d2.dependencies.Contains(d1) ? - 1 : d1.dependencies.Contains(d2) ? 1 : 0) + .Select(Get) + .ForEach(stat => stat.Refresh()); + _queue.Clear(); + } + + /// + /// Select along with its dependencies to refresh next frame. + /// + public void AddToQueueRefresh(StatDefinitionSO statDefinitionSO) + { + statDefinitionSO = statDefinitionSO.GetBaseDefinition(); + + // Add definition to refresh queue + if (!_queue.Contains(statDefinitionSO)) _queue.Add(statDefinitionSO); + + // All definitions that uses this one as dependency should be refreshed too + _stats.Keys + .Where(otherStatDefinition => otherStatDefinition.dependencies.Contains(statDefinitionSO)) + .ForEach(AddToQueueRefresh); + } + } +} \ No newline at end of file diff --git a/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatsModule.cs.meta b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatsModule.cs.meta new file mode 100644 index 0000000..5c1f5ae --- /dev/null +++ b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatsModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d36660a0fd2e489aad1fb57b951038d9 +timeCreated: 1762712656 \ No newline at end of file diff --git a/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatsSettings.cs b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatsSettings.cs new file mode 100644 index 0000000..795db6a --- /dev/null +++ b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatsSettings.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using RPGCoreCommon.Settings; + +namespace RPGCore.Stats.ObjectModules.StatsObjectModule +{ + [CustomSettings("RPG Core/Statistics")] + public class StatsSettings : CustomSettingsSO + { + public List allStats = new(); + } +} \ No newline at end of file diff --git a/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatsSettings.cs.meta b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatsSettings.cs.meta new file mode 100644 index 0000000..9a939d2 --- /dev/null +++ b/RPGCore.Stats/Runtime/ObjectModules/StatsObjectModule/StatsSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 23bc82a39d2248aa9a78a75a5162e173 +timeCreated: 1762713013 \ No newline at end of file diff --git a/RPGCore.Stats/Runtime/RPGCore.Stats.asmdef b/RPGCore.Stats/Runtime/RPGCore.Stats.asmdef new file mode 100644 index 0000000..9e8a995 --- /dev/null +++ b/RPGCore.Stats/Runtime/RPGCore.Stats.asmdef @@ -0,0 +1,20 @@ +{ + "name": "RPGCore.Stats", + "rootNamespace": "RPGCore.Stats", + "references": [ + "RPGCore", + "RPGCoreCommon.Settings", + "RPGCoreCommon.Helpers", + "RPGCoreCommon.DynamicValues", + "Unity.InputSystem" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/RPGCore.Stats/Runtime/RPGCore.Stats.asmdef.meta b/RPGCore.Stats/Runtime/RPGCore.Stats.asmdef.meta new file mode 100644 index 0000000..eae0c26 --- /dev/null +++ b/RPGCore.Stats/Runtime/RPGCore.Stats.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6d6ef8d5372fc5544872a154e5063b07 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/RPGCore.StatusEffect.meta b/RPGCore.StatusEffect.meta new file mode 100644 index 0000000..1307a06 --- /dev/null +++ b/RPGCore.StatusEffect.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ccda1a0221e349cbb6b1781e1ae705f5 +timeCreated: 1772973749 \ No newline at end of file diff --git a/RPGCore.StatusEffect/Editor.meta b/RPGCore.StatusEffect/Editor.meta new file mode 100644 index 0000000..86617a2 --- /dev/null +++ b/RPGCore.StatusEffect/Editor.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 55debdd894df4bfeba2fb204d1998ab1 +timeCreated: 1772973840 \ No newline at end of file diff --git a/RPGCore.StatusEffect/Editor/Drawers.meta b/RPGCore.StatusEffect/Editor/Drawers.meta new file mode 100644 index 0000000..7d506b7 --- /dev/null +++ b/RPGCore.StatusEffect/Editor/Drawers.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b922caefac514b5ea200716720d102ee +timeCreated: 1773354906 \ No newline at end of file diff --git a/RPGCore.StatusEffect/Editor/Drawers/StatusModuleDrawer.cs b/RPGCore.StatusEffect/Editor/Drawers/StatusModuleDrawer.cs new file mode 100644 index 0000000..293fd60 --- /dev/null +++ b/RPGCore.StatusEffect/Editor/Drawers/StatusModuleDrawer.cs @@ -0,0 +1,47 @@ +using System.Linq; +using RPGCore.StatusEffect.ObjectModules.StatusObjectModule; +using UnityEditor; +using UnityEditor.UIElements; +using UnityEngine; +using UnityEngine.UIElements; + +namespace RPGCore.StatusEffect.Editor.Drawers +{ + [CustomPropertyDrawer(typeof(StatusModule))] + public class StatusModuleDrawer : PropertyDrawer + { + public override VisualElement CreatePropertyGUI(SerializedProperty property) + { + var root = new VisualElement(); + + if (Application.isPlaying) root.Add(CreateDebugBox(property)); + root.Add(new PropertyField(property)); + + return root; + } + + private HelpBox CreateDebugBox(SerializedProperty property) + { + var debugBox = new HelpBox(); + debugBox.style.flexDirection = FlexDirection.Column; + debugBox.style.alignItems = Align.Stretch; + debugBox.SetEnabled(false); + + debugBox.Add(new Label("RUNTIME DEBUG:")); + + var statusList = new VisualElement(); + debugBox.Add(statusList); + + debugBox.schedule.Execute(() => + { + var module = property.boxedValue as StatusModule; + + statusList.Clear(); + foreach (var status in module.statuses) + statusList.Add(new Label(status.definition.name)); + }).Every(100); + + return debugBox; + } + } +} \ No newline at end of file diff --git a/RPGCore.StatusEffect/Editor/Drawers/StatusModuleDrawer.cs.meta b/RPGCore.StatusEffect/Editor/Drawers/StatusModuleDrawer.cs.meta new file mode 100644 index 0000000..c3819f9 --- /dev/null +++ b/RPGCore.StatusEffect/Editor/Drawers/StatusModuleDrawer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: cc1db66de924411e8d07dea47af563c3 +timeCreated: 1773354908 \ No newline at end of file diff --git a/RPGCore.StatusEffect/Editor/RPGCore.StatusEffect.Editor.asmdef b/RPGCore.StatusEffect/Editor/RPGCore.StatusEffect.Editor.asmdef new file mode 100644 index 0000000..be0af8c --- /dev/null +++ b/RPGCore.StatusEffect/Editor/RPGCore.StatusEffect.Editor.asmdef @@ -0,0 +1,20 @@ +{ + "name": "RPGCore.StatusEffect.Editor", + "rootNamespace": "RPGCore.StatusEffect.Editor", + "references": [ + "RPGCore", + "RPGCore.StatusEffect", + "RPGCoreCommon.Helpers" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/RPGCore.StatusEffect/Editor/RPGCore.StatusEffect.Editor.asmdef.meta b/RPGCore.StatusEffect/Editor/RPGCore.StatusEffect.Editor.asmdef.meta new file mode 100644 index 0000000..e0d4d1f --- /dev/null +++ b/RPGCore.StatusEffect/Editor/RPGCore.StatusEffect.Editor.asmdef.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 67ce347e38e048b4922477b1733406e3 +timeCreated: 1772973849 \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime.meta b/RPGCore.StatusEffect/Runtime.meta new file mode 100644 index 0000000..ab7b9ba --- /dev/null +++ b/RPGCore.StatusEffect/Runtime.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8573345b7c004fc7a3e038ce235d4610 +timeCreated: 1772973844 \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/InternalsVisibleTo.cs b/RPGCore.StatusEffect/Runtime/InternalsVisibleTo.cs new file mode 100644 index 0000000..0db6fa6 --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/InternalsVisibleTo.cs @@ -0,0 +1,8 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("RPGCore.StatusEffect.Editor")] + +namespace RPGCore.StatusEffect +{ + +} \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/InternalsVisibleTo.cs.meta b/RPGCore.StatusEffect/Runtime/InternalsVisibleTo.cs.meta new file mode 100644 index 0000000..f1d9990 --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/InternalsVisibleTo.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e29a252ace124f5ba8afb1d172ca2120 +timeCreated: 1773355062 \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/ObjectModules.meta b/RPGCore.StatusEffect/Runtime/ObjectModules.meta new file mode 100644 index 0000000..76003bc --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/ObjectModules.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d08f53aeb92f4bcdae8e0c29370e948b +timeCreated: 1772998256 \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule.meta b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule.meta new file mode 100644 index 0000000..05f0259 --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 370696f1a9194fcc81f2462fb0fd3c75 +timeCreated: 1762633154 \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Effect.cs b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Effect.cs new file mode 100644 index 0000000..d895f75 --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Effect.cs @@ -0,0 +1,28 @@ +using System; +using RPGCore.Core.Objects; + +namespace RPGCore.StatusEffect.ObjectModules.StatusObjectModule +{ + /// + /// Extend this to make custom effect that can be used by . + /// + [Serializable] + public class Effect + { + public BaseObject obj { get; internal set; } + public Status status { get; internal set; } + + internal void OnApply_Internal() => OnApply(); + internal void OnEnd_Internal() => OnEnd(); + internal void OnRemove_Internal() => OnRemove(); + + protected virtual void OnApply() {} + protected virtual void OnEnd() {} + protected virtual void OnRemove() {} + + protected void EndStatus() + { + status.statusModule.End(status); + } + } +} \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Effect.cs.meta b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Effect.cs.meta new file mode 100644 index 0000000..880ac37 --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Effect.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 930348137c8044d5bbbb64dcf54ae953 +timeCreated: 1772974582 \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Effects.meta b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Effects.meta new file mode 100644 index 0000000..fa53b89 --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Effects.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3c6b215386e14a38afa090853d1e7e84 +timeCreated: 1772974553 \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Effects/NotControllableEffect.cs b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Effects/NotControllableEffect.cs new file mode 100644 index 0000000..ec84b85 --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Effects/NotControllableEffect.cs @@ -0,0 +1,6 @@ +namespace RPGCore.StatusEffect.ObjectModules.StatusObjectModule.Effects +{ + public class NotControllableEffect : Effect + { + } +} \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Effects/NotControllableEffect.cs.meta b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Effects/NotControllableEffect.cs.meta new file mode 100644 index 0000000..82f6618 --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Effects/NotControllableEffect.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: dccc3743dc3e4a67b738d8ac3c8e8347 +timeCreated: 1773175390 \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Events.meta b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Events.meta new file mode 100644 index 0000000..750df94 --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Events.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 74fcfad35dc74866831cc42cdcfbbe44 +timeCreated: 1764884979 \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Events/StatusEndEvent.cs b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Events/StatusEndEvent.cs new file mode 100644 index 0000000..bab57cf --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Events/StatusEndEvent.cs @@ -0,0 +1,14 @@ +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; + +namespace RPGCore.StatusEffect.ObjectModules.StatusObjectModule.Events +{ + /// + /// Executed when ends normally - by timer or by . + /// + public class StatusEndEvent : BaseEvent + { + public BaseObject target; + public Status status; + } +} \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Events/StatusEndEvent.cs.meta b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Events/StatusEndEvent.cs.meta new file mode 100644 index 0000000..96ef4e0 --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Events/StatusEndEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a41609619e254d8a98ce6805b3d3edf8 +timeCreated: 1762636552 \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Events/StatusRemoveEvent.cs b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Events/StatusRemoveEvent.cs new file mode 100644 index 0000000..690b221 --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Events/StatusRemoveEvent.cs @@ -0,0 +1,14 @@ +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; + +namespace RPGCore.StatusEffect.ObjectModules.StatusObjectModule.Events +{ + /// + /// Executed when ends forcefully - by something else than timer or . + /// + public class StatusRemoveEvent : BaseEvent + { + public BaseObject target; + public Status status; + } +} \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Events/StatusRemoveEvent.cs.meta b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Events/StatusRemoveEvent.cs.meta new file mode 100644 index 0000000..4d658e3 --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Events/StatusRemoveEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c16881cb8c65431b97b97cd8956ed455 +timeCreated: 1773264987 \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Events/StatusStartEvent.cs b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Events/StatusStartEvent.cs new file mode 100644 index 0000000..ee1849d --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Events/StatusStartEvent.cs @@ -0,0 +1,14 @@ +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; + +namespace RPGCore.StatusEffect.ObjectModules.StatusObjectModule.Events +{ + /// + /// Executed when is applied. + /// + public class StatusStartEvent : BaseEvent + { + public BaseObject target; + public Status status; + } +} \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Events/StatusStartEvent.cs.meta b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Events/StatusStartEvent.cs.meta new file mode 100644 index 0000000..2762aa8 --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Events/StatusStartEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e35d6b98b192496ea8853d49de0b0790 +timeCreated: 1762636360 \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Status.cs b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Status.cs new file mode 100644 index 0000000..c5c0754 --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Status.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace RPGCore.StatusEffect.ObjectModules.StatusObjectModule +{ + public sealed class Status + { + public StatusDefinitionSO definition { get; private set; } + public StatusModule statusModule { get; private set; } + + public float timeRemaining { get; private set; } + public List effects { get; private set; } + + internal Status(StatusDefinitionSO definition, StatusModule statusModule) + { + this.definition = definition; + this.statusModule = statusModule; + + timeRemaining = definition.time; + effects = definition.effects.Select(e => + { + var copy = JsonUtility.FromJson(JsonUtility.ToJson(e)); + copy.obj = statusModule.parent; + copy.status = this; + return copy; + }).ToList(); + } + + internal void UpdateTime_Internal(float deltaTime) + { + if (definition.permanent) return; + + timeRemaining -= deltaTime; + + if (timeRemaining <= 0) statusModule.End(this); + } + + internal void OnApply_Internal() => effects.ForEach(effect => effect.OnApply_Internal()); + + internal void OnEnd_Internal() => effects.ForEach(effect => effect.OnEnd_Internal()); + + internal void OnRemove_Internal() => effects.ForEach(effect => effect.OnRemove_Internal()); + } +} \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Status.cs.meta b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Status.cs.meta new file mode 100644 index 0000000..69a3cab --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/Status.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f4785e633dfa471082b97be16fb90522 +timeCreated: 1767359048 \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/StatusDefinitionSO.cs b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/StatusDefinitionSO.cs new file mode 100644 index 0000000..3dcf885 --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/StatusDefinitionSO.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using RPGCore.Core.Objects; +using RPGCore.StatusEffect.ObjectModules.StatusObjectModule.Effects; +using RPGCoreCommon.DynamicValues; +using RPGCoreCommon.Helpers.CustomTypes; +using UnityEngine; + +namespace RPGCore.StatusEffect.ObjectModules.StatusObjectModule +{ + [Serializable] + [CreateAssetMenu(menuName = "RPG Core/Status")] + public class StatusDefinitionSO : ScriptableObject + { + [Header("Connected to:")] + [SerializableType(typeof(BaseObject), allowAbstract: true)] public SerializableType forType; + + [Header("Display")] + public string displayName; + public bool hidden; + public Texture2D displayIcon; + [DynamicValue(DynamicValueType.ByDynamicTypes)] public DynamicValue description; + + [Header("Duration")] + public bool permanent; + [Min(0)] public float time; + + [Header("Effects")] + [SerializeReference] public List effects = new(); + + private void OnValidate() + { + description.RemoveDynamicTypes(); + description.SetDynamicType("object", forType); + } + } +} \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/StatusDefinitionSO.cs.meta b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/StatusDefinitionSO.cs.meta new file mode 100644 index 0000000..8be95c2 --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/StatusDefinitionSO.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9e1852531ea144a181ad7f23cfa40991 +timeCreated: 1762633180 \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/StatusModule.cs b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/StatusModule.cs new file mode 100644 index 0000000..9bc1017 --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/StatusModule.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using RPGCore.Core; +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; +using RPGCore.StatusEffect.ObjectModules.StatusObjectModule.Effects; +using RPGCore.StatusEffect.ObjectModules.StatusObjectModule.Events; +using UnityEngine; + +namespace RPGCore.StatusEffect.ObjectModules.StatusObjectModule +{ + [Serializable] + [RequireComponent(typeof(BaseObject))] + public class StatusModule : ObjectModule + { + internal List statuses { get; private set; } = new(); + [SerializeField] internal StatusUpdateType updateType; + + /// Checks if any has . + public virtual bool IsControllable() + { + return !statuses.Any(status => status.definition.effects.Any(effect => effect is NotControllableEffect)); + } + + /// Checks if any active that uses is present. + public bool Check(StatusDefinitionSO definition) + { + return statuses.Any(status => status.definition == definition); + } + + /// Adds new . + public Status Apply(StatusDefinitionSO definition) + { + var status = new Status(definition, this); + statuses.Add(status); + status.OnApply_Internal(); + parent.events.Invoke(new StatusStartEvent { status = status, target = parent }); + return status; + } + + /// Removes given forcefully. + public void Remove(Status status) + { + if (status == null) return; + if (!statuses.Contains(status)) return; + status.OnRemove_Internal(); + statuses.Remove(status); + parent.events.Invoke(new StatusRemoveEvent { status = status, target = parent }); + } + + /// Removes all es forcefully that uses . + public void Remove(StatusDefinitionSO definition) + { + GetStatuses(definition).ForEach(Remove); + } + + /// Executed internally when status ending itself (by timer or effect). + internal void End(Status status) + { + if (status == null) return; + if (!statuses.Contains(status)) return; + status.OnEnd_Internal(); + statuses.Remove(status); + parent.events.Invoke(new StatusEndEvent { status = status, target = parent }); + } + + /// Returns all active es. + public List GetStatuses() + { + return statuses.ToList(); + } + + /// Returns all active es that uses . + public List GetStatuses(StatusDefinitionSO definition) + { + return statuses.Where(status => status.definition == definition).ToList(); + } + + private void FixedUpdate() + { + if (updateType is StatusUpdateType.Automatically) + statuses.ToList().ForEach(status => status.UpdateTime_Internal(Time.fixedDeltaTime)); + } + + /// Update each status timer, decreases them by given seconds. + public void UpdateTime(float deltaTime) + { + if (updateType is not StatusUpdateType.Manually) + { + Debug.LogError($"Updating status time available only when: {nameof(StatusUpdateType)} = {nameof(StatusUpdateType.Manually)}"); + return; + } + + statuses.ForEach(status => status.UpdateTime_Internal(deltaTime)); + } + } +} \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/StatusModule.cs.meta b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/StatusModule.cs.meta new file mode 100644 index 0000000..9b15f37 --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/StatusModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0ce33596b3d549c7b86629c1d1e6532c +timeCreated: 1762633163 \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/StatusUpdateType.cs b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/StatusUpdateType.cs new file mode 100644 index 0000000..453de91 --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/StatusUpdateType.cs @@ -0,0 +1,8 @@ +namespace RPGCore.StatusEffect.ObjectModules.StatusObjectModule +{ + public enum StatusUpdateType + { + Automatically, + Manually, + } +} \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/StatusUpdateType.cs.meta b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/StatusUpdateType.cs.meta new file mode 100644 index 0000000..bc40093 --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/ObjectModules/StatusObjectModule/StatusUpdateType.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5585782dbfae4ea6bc631cb2038e51f1 +timeCreated: 1773176713 \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/RPGCore.StatusEffect.asmdef b/RPGCore.StatusEffect/Runtime/RPGCore.StatusEffect.asmdef new file mode 100644 index 0000000..3d63d75 --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/RPGCore.StatusEffect.asmdef @@ -0,0 +1,20 @@ +{ + "name": "RPGCore.StatusEffect", + "rootNamespace": "RPGCore.StatusEffect", + "references": [ + "RPGCore", + "RPGCoreCommon.Settings", + "RPGCoreCommon.Helpers", + "RPGCoreCommon.DynamicValues", + "Unity.InputSystem" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/RPGCore.StatusEffect/Runtime/RPGCore.StatusEffect.asmdef.meta b/RPGCore.StatusEffect/Runtime/RPGCore.StatusEffect.asmdef.meta new file mode 100644 index 0000000..3544fe8 --- /dev/null +++ b/RPGCore.StatusEffect/Runtime/RPGCore.StatusEffect.asmdef.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5173dd49ef4441a69ee4ad8069af2c60 +timeCreated: 1772973851 \ No newline at end of file diff --git a/RPGCore.meta b/RPGCore.meta new file mode 100644 index 0000000..27e36d0 --- /dev/null +++ b/RPGCore.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dd540953ee9fff44a91e136f4189712a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/RPGCore/Editor.meta b/RPGCore/Editor.meta new file mode 100644 index 0000000..9113bfa --- /dev/null +++ b/RPGCore/Editor.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 49335e95b3ea4fb7a07dbe4feb5ba86e +timeCreated: 1759057728 \ No newline at end of file diff --git a/RPGCore/Editor/Drawers.meta b/RPGCore/Editor/Drawers.meta new file mode 100644 index 0000000..639c49d --- /dev/null +++ b/RPGCore/Editor/Drawers.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e7fc7377b1d5469abc7437b0ae10b63e +timeCreated: 1761485555 \ No newline at end of file diff --git a/RPGCore/Editor/Drawers/ObjectModules.meta b/RPGCore/Editor/Drawers/ObjectModules.meta new file mode 100644 index 0000000..0e9e9f0 --- /dev/null +++ b/RPGCore/Editor/Drawers/ObjectModules.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 11f768f38d9c4fb18dc357fde085548a +timeCreated: 1761774372 \ No newline at end of file diff --git a/RPGCore/Editor/Drawers/ObjectModules/Event.meta b/RPGCore/Editor/Drawers/ObjectModules/Event.meta new file mode 100644 index 0000000..64f1a8b --- /dev/null +++ b/RPGCore/Editor/Drawers/ObjectModules/Event.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 67aaf260711d4718a2d97c29246a5ec7 +timeCreated: 1761919244 \ No newline at end of file diff --git a/RPGCore/Editor/Drawers/ObjectModules/Event/EventModuleDrawer.cs b/RPGCore/Editor/Drawers/ObjectModules/Event/EventModuleDrawer.cs new file mode 100644 index 0000000..b7cce96 --- /dev/null +++ b/RPGCore/Editor/Drawers/ObjectModules/Event/EventModuleDrawer.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using RPGCore.ObjectModules.EventObjectModule; +using RPGCoreCommon.Helpers; +using UnityEditor; +using UnityEditor.UIElements; +using UnityEngine.UIElements; + +namespace RPGCore.Editor.Drawers.SceneModules.Event +{ + [CustomEditor(typeof(EventModule))] + public class EventModuleDrawer : UnityEditor.Editor + { + private class DrawerContext + { + public SerializedObject obj; + public List events = new(); + public List preventableEvents = new(); + } + + public override VisualElement CreateInspectorGUI() + { + var root = new VisualElement(); + + var property = serializedObject.GetIterator(); + + var enterChildren = true; + while (property.NextVisible(enterChildren)) + { + root.Add(new PropertyField(property) { enabledSelf = property.name != "m_Script" }); + enterChildren = false; + } + + root.Add(CreateEventList()); + return root; + } + + private VisualElement CreateEventList() + { + if (!EditorApplication.isPlaying) + return new HelpBox("Subscribed events preview available only in play mode.", HelpBoxMessageType.Info); + + var wrapper = new VisualElement(); + + var list1 = new Foldout(); + list1.text = "Events registered:"; + list1.style.marginLeft = 12; + list1.Add(new Label("List empty.")); + wrapper.Add(list1); + + var list2 = new Foldout(); + list2.text = "Preventable Events (before) registered:"; + list2.style.marginLeft = 12; + list2.Add(new Label("List empty.")); + wrapper.Add(list2); + + var list3 = new Foldout(); + list3.text = "Preventable Events (after) registered:"; + list3.style.marginLeft = 12; + list3.Add(new Label("List empty.")); + wrapper.Add(list3); + + var context = new DrawerContext{obj = serializedObject}; + wrapper.schedule.Execute(() => Refresh(context, list1, list2, list3)).Every(1000); + + return wrapper; + } + + private void Refresh(DrawerContext context, VisualElement list, VisualElement beforeList, VisualElement afterList) + { + var eventModule = context.obj.targetObject as EventModule; + RefreshList(context.events, eventModule.events, list); + RefreshList(context.preventableEvents, eventModule.preventableEvents.ToDictionary(pair => pair.Key, pair => pair.Value[0]), beforeList); + RefreshList(context.preventableEvents, eventModule.preventableEvents.ToDictionary(pair => pair.Key, pair => pair.Value[1]), afterList); + + context.events = eventModule.events.Keys.ToList(); + context.preventableEvents = eventModule.preventableEvents.Keys.ToList(); + } + + private void RefreshList(List before, Dictionary after, VisualElement list) + { + var toRemove = before.Except(after.Keys).ToList(); + var toAdd = after.Keys.Except(before).ToList(); + + if (!toRemove.Any() && !toAdd.Any()) return; + + list.Clear(); + after.DictSelect((type, action) => + { + var row = new VisualElement(); + row.style.flexDirection = FlexDirection.Row; + row.Add(new HelpBox { text = type.Name }); + + var callers = action?.GetInvocationList().Select(a => $"{a.Target.GetType().Name} : {a.Method.Name}").StringJoin("\n"); + if (string.IsNullOrEmpty(callers)) callers = "No registered callers"; + row.Add(string.IsNullOrEmpty(callers) ? new Label() : new HelpBox { text = callers }); + + return row; + + }).ForEach(list.Add); + + if (!after.Any()) list.Add(new Label("List empty.")); + } + } +} \ No newline at end of file diff --git a/RPGCore/Editor/Drawers/ObjectModules/Event/EventModuleDrawer.cs.meta b/RPGCore/Editor/Drawers/ObjectModules/Event/EventModuleDrawer.cs.meta new file mode 100644 index 0000000..15cce99 --- /dev/null +++ b/RPGCore/Editor/Drawers/ObjectModules/Event/EventModuleDrawer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3379740cce21445b882d2175c6f699ce +timeCreated: 1761919852 \ No newline at end of file diff --git a/RPGCore/Editor/Drawers/SceneModules.meta b/RPGCore/Editor/Drawers/SceneModules.meta new file mode 100644 index 0000000..2139387 --- /dev/null +++ b/RPGCore/Editor/Drawers/SceneModules.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3d95afed367c4251b29cc8c3137f99dd +timeCreated: 1761774365 \ No newline at end of file diff --git a/RPGCore/Editor/Drawers/SceneModules/PathVisualizer.meta b/RPGCore/Editor/Drawers/SceneModules/PathVisualizer.meta new file mode 100644 index 0000000..f96e26c --- /dev/null +++ b/RPGCore/Editor/Drawers/SceneModules/PathVisualizer.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: fa8e75168dd14631a1776e9eb6f4b0fd +timeCreated: 1761839848 \ No newline at end of file diff --git a/RPGCore/Editor/Drawers/SceneModules/PathVisualizer/PathVisualizerModuleDrawer.cs b/RPGCore/Editor/Drawers/SceneModules/PathVisualizer/PathVisualizerModuleDrawer.cs new file mode 100644 index 0000000..b2abd76 --- /dev/null +++ b/RPGCore/Editor/Drawers/SceneModules/PathVisualizer/PathVisualizerModuleDrawer.cs @@ -0,0 +1,78 @@ +using System.Linq; +using RPGCore.SceneModules.PathVisualizerSceneModule; +using UnityEditor; +using UnityEditor.UIElements; +using UnityEngine.UIElements; + +namespace RPGCore.Editor.Drawers.SceneModules.PathVisualizer +{ + [CustomPropertyDrawer(typeof(PathVisualizerModule))] + public class PathVisualizerModuleDrawer : PropertyDrawer + { + public override VisualElement CreatePropertyGUI(SerializedProperty property) + { + var root = new VisualElement(); + + root.Add(new PropertyField(property)); + + if (EditorApplication.isPlaying) + { + root.Add(CreateList(property)); + } + else + { + root.Add(new HelpBox("Subscribed events preview available only in play mode.", HelpBoxMessageType.Info)); + } + + return root; + } + + private VisualElement CreateList(SerializedProperty property) + { + var wrapper = new VisualElement(); + + var helpBox = new HelpBox(); + helpBox.text = "Usable only runtime via script.
Below is list of currently managed paths."; + helpBox.messageType = HelpBoxMessageType.Info; + helpBox.style.marginTop = 15; + wrapper.Add(helpBox); + + var list = new VisualElement(); + list.schedule.Execute(() => RefreshList(property, list)).Every(2500); + list.Add(new Label("List empty.")); + wrapper.Add(list); + + RefreshList(property, list); + + return wrapper; + } + + private void RefreshList(SerializedProperty property, VisualElement list) + { + var pathVisualizers = (property.boxedValue as PathVisualizerModule).pathVisualizers; + + // No elements, only label with info + if (pathVisualizers.Count == 0 && list.Children().FirstOrDefault() is Label) return; + + // Nothing changed + if (pathVisualizers.Count == list.childCount && list.Children().FirstOrDefault() is not Label) return; + + list.Clear(); + + if (!pathVisualizers.Any()) + { + list.Add(new Label("List empty.")); + return; + } + + foreach (var pathVisualizer in pathVisualizers) + { + if (!pathVisualizer) continue; + var objectField = new ObjectField(); + objectField.value = pathVisualizer; + objectField.SetEnabled(false); + list.Add(objectField); + } + } + } +} \ No newline at end of file diff --git a/RPGCore/Editor/Drawers/SceneModules/PathVisualizer/PathVisualizerModuleDrawer.cs.meta b/RPGCore/Editor/Drawers/SceneModules/PathVisualizer/PathVisualizerModuleDrawer.cs.meta new file mode 100644 index 0000000..da9ef81 --- /dev/null +++ b/RPGCore/Editor/Drawers/SceneModules/PathVisualizer/PathVisualizerModuleDrawer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 774f2a8b09b7472c982b804adde32e41 +timeCreated: 1761839859 \ No newline at end of file diff --git a/RPGCore/Editor/RPGCore.Editor.asmdef b/RPGCore/Editor/RPGCore.Editor.asmdef new file mode 100644 index 0000000..144b3be --- /dev/null +++ b/RPGCore/Editor/RPGCore.Editor.asmdef @@ -0,0 +1,19 @@ +{ + "name": "RPGCore.Editor", + "rootNamespace": "RPGCore.Editor", + "references": [ + "RPGCore", + "RPGCoreCommon.Helpers" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/RPGCore/Editor/RPGCore.Editor.asmdef.meta b/RPGCore/Editor/RPGCore.Editor.asmdef.meta new file mode 100644 index 0000000..0095c9e --- /dev/null +++ b/RPGCore/Editor/RPGCore.Editor.asmdef.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 06fa85d8d22f490491ae2a4a024e353a +timeCreated: 1759057737 \ No newline at end of file diff --git a/RPGCore/Runtime.meta b/RPGCore/Runtime.meta new file mode 100644 index 0000000..c3321cd --- /dev/null +++ b/RPGCore/Runtime.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1b92b1f3ab7748eeaa2e25278725fa75 +timeCreated: 1759057688 \ No newline at end of file diff --git a/RPGCore/Runtime/Core.meta b/RPGCore/Runtime/Core.meta new file mode 100644 index 0000000..0db604d --- /dev/null +++ b/RPGCore/Runtime/Core.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 488b2a899d8449a9afedbbd05043acf9 +timeCreated: 1761773545 \ No newline at end of file diff --git a/RPGCore/Runtime/Core/CoreSettings.cs b/RPGCore/Runtime/Core/CoreSettings.cs new file mode 100644 index 0000000..b29bc61 --- /dev/null +++ b/RPGCore/Runtime/Core/CoreSettings.cs @@ -0,0 +1,17 @@ +using RPGCoreCommon.Helpers.PropertyAttributeDrawers; +using RPGCoreCommon.Settings; +using UnityEngine; + +namespace RPGCore.Core +{ + [CustomSettings("RPG Core/Main Settings")] + public class CoreSettings : CustomSettingsSO + { + [Header("Layers")] + [Layer] public int dynamicLayer; + [Layer] public int staticLayer; + [Layer] public int staticHideableLayer; + [Layer] public int triggerLayer; + [Layer] public int cameraLayer; + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/Core/CoreSettings.cs.meta b/RPGCore/Runtime/Core/CoreSettings.cs.meta new file mode 100644 index 0000000..0d960aa --- /dev/null +++ b/RPGCore/Runtime/Core/CoreSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ae66b654cdd34f0eb7cb566026a04553 +timeCreated: 1761916774 \ No newline at end of file diff --git a/RPGCore/Runtime/Core/GlobalModule.cs b/RPGCore/Runtime/Core/GlobalModule.cs new file mode 100644 index 0000000..d2c0b4d --- /dev/null +++ b/RPGCore/Runtime/Core/GlobalModule.cs @@ -0,0 +1,13 @@ +using System; +using UnityEngine; + +namespace RPGCore.Core +{ + /// + /// Extend this abstract class to create new module for global logic. + /// + [Serializable] + public abstract class GlobalModule : MonoBehaviour + { + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/Core/GlobalModule.cs.meta b/RPGCore/Runtime/Core/GlobalModule.cs.meta new file mode 100644 index 0000000..d458ed9 --- /dev/null +++ b/RPGCore/Runtime/Core/GlobalModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9bfe3de119af4cca916793ab7ab84f34 +timeCreated: 1761424144 \ No newline at end of file diff --git a/RPGCore/Runtime/Core/IRequirement.cs b/RPGCore/Runtime/Core/IRequirement.cs new file mode 100644 index 0000000..88e640f --- /dev/null +++ b/RPGCore/Runtime/Core/IRequirement.cs @@ -0,0 +1,15 @@ +using System; + +namespace RPGCore.Core +{ + /// + /// With this interface you can create your own list of requirements for specific (and its implementations). + /// returns TRUE if defined requirement is met, otherwise FALSE. + /// Thanks to this we can create list of reusable requirements that further can be used to gate logic. + /// + /// Type for which this requirement is + public interface IRequirement + { + public bool Check(T obj); + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/Core/IRequirement.cs.meta b/RPGCore/Runtime/Core/IRequirement.cs.meta new file mode 100644 index 0000000..8c63987 --- /dev/null +++ b/RPGCore/Runtime/Core/IRequirement.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e865880889b3491aa34c60bc2fbca102 +timeCreated: 1764886296 \ No newline at end of file diff --git a/RPGCore/Runtime/Core/ITrigger.cs b/RPGCore/Runtime/Core/ITrigger.cs new file mode 100644 index 0000000..db61cd9 --- /dev/null +++ b/RPGCore/Runtime/Core/ITrigger.cs @@ -0,0 +1,15 @@ +using RPGCore.Core.Objects; +using UnityEngine; + +namespace RPGCore.Core +{ + /// + /// This interface allow any to call and .
+ /// Setting 's to true is required!
+ ///
+ public interface ITrigger + { + public void OnEnter(BaseObject obj); + public void OnExit(BaseObject obj); + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/Core/ITrigger.cs.meta b/RPGCore/Runtime/Core/ITrigger.cs.meta new file mode 100644 index 0000000..dd68a63 --- /dev/null +++ b/RPGCore/Runtime/Core/ITrigger.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c44b68608de84013b92b61d898ea8e2a +timeCreated: 1761916614 \ No newline at end of file diff --git a/RPGCore/Runtime/Core/ObjectModule.cs b/RPGCore/Runtime/Core/ObjectModule.cs new file mode 100644 index 0000000..dadd0e4 --- /dev/null +++ b/RPGCore/Runtime/Core/ObjectModule.cs @@ -0,0 +1,39 @@ +using System; +using RPGCore.Core.Objects; +using UnityEngine; + +namespace RPGCore.Core +{ + /// + /// Extend this abstract class to create new module for <> object type.
+ ///
+ /// Type of object that this module will be attached to. Can be or any of its children. + [Serializable] + public abstract class ObjectModule : ObjectModule where T : BaseObject + { + public new T parent => (T)base.parent; + } + + /// + /// DO NOT EXTEND THIS, use instead! + /// + [Serializable] + public abstract class ObjectModule : MonoBehaviour + { + private BaseObject _parent; + internal BaseObject parent + { + get + { + if (!_parent) _parent = GetComponent(); + return _parent; + } + set => _parent = value; + } + + private protected ObjectModule() + { + + } + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/Core/ObjectModule.cs.meta b/RPGCore/Runtime/Core/ObjectModule.cs.meta new file mode 100644 index 0000000..0a343d2 --- /dev/null +++ b/RPGCore/Runtime/Core/ObjectModule.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3c6794c4f1c6dd149860a41f06978cad \ No newline at end of file diff --git a/RPGCore/Runtime/Core/Objects.meta b/RPGCore/Runtime/Core/Objects.meta new file mode 100644 index 0000000..338a3ac --- /dev/null +++ b/RPGCore/Runtime/Core/Objects.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 182b5998cfbb6644da7a90e3b1765485 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/RPGCore/Runtime/Core/Objects/BaseObject.cs b/RPGCore/Runtime/Core/Objects/BaseObject.cs new file mode 100644 index 0000000..31d6f38 --- /dev/null +++ b/RPGCore/Runtime/Core/Objects/BaseObject.cs @@ -0,0 +1,67 @@ +using System; +using RPGCore.ObjectModules.ActionObjectModule; +using RPGCore.ObjectModules.EventObjectModule; +using RPGCore.ObjectModules.EventObjectModule.Events; +using RPGCoreCommon.DynamicValues; +using RPGCoreCommon.Helpers; +using RPGCoreCommon.Helpers.PropertyAttributeDrawers; +using UnityEngine; + +namespace RPGCore.Core.Objects +{ + [SelectionBase] + [DisallowMultipleComponent] + [RequireComponent(typeof(Rigidbody))] + [RequireComponent(typeof(EventModule))] + [RequireComponent(typeof(ActionModule))] + [RequireComponent(typeof(DataModule))] + public abstract class BaseObject : MonoBehaviour + { + [field: SerializeField, ReadOnly] public new Rigidbody rigidbody { get; private set; } + [field: SerializeField, ReadOnly] public EventModule events { get; private set; } + [field: SerializeField, ReadOnly] public ActionModule actions { get; private set; } + [field: SerializeField, ReadOnly] public DataModule data { get; private set; } + + [DynamicValueProvider] + private ObjectModule BaseModuleProvider(Type moduleType) => GetComponent(moduleType) as ObjectModule; + + protected void Start() + { + GetComponent().Invoke(new SpawnEvent()); + } + + protected void OnValidate() + { + rigidbody = GetComponent(); + events = GetComponent(); + actions = GetComponent(); + data = GetComponent(); + GetComponents().ForEach(module => module.parent = this); + } + + /// Removes this object from game. + public void Remove() + { + events.Invoke(new RemoveEvent{ obj = this }); + Destroy(gameObject); + } + + /// It'll execute . when this object enter its collider. + private void OnTriggerEnter(Collider other) + { + other.GetComponentsInParent().ForEach(trigger => { + trigger.OnEnter(this); + events.Invoke(new TriggerEnterEvent { target = this, trigger = trigger }); + }); + } + + /// It'll execute . when this object exit its collider. + private void OnTriggerExit(Collider other) + { + other.GetComponentsInParent().ForEach(trigger => { + trigger.OnExit(this); + events.Invoke(new TriggerExitEvent { target = this, trigger = trigger }); + }); + } + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/Core/Objects/BaseObject.cs.meta b/RPGCore/Runtime/Core/Objects/BaseObject.cs.meta new file mode 100644 index 0000000..d22b36d --- /dev/null +++ b/RPGCore/Runtime/Core/Objects/BaseObject.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e2798185b793dc9498d74d746f680c1c \ No newline at end of file diff --git a/RPGCore/Runtime/Core/Objects/UnitObject.cs b/RPGCore/Runtime/Core/Objects/UnitObject.cs new file mode 100644 index 0000000..14d45fd --- /dev/null +++ b/RPGCore/Runtime/Core/Objects/UnitObject.cs @@ -0,0 +1,22 @@ +using System; +using RPGCoreCommon.DynamicValues; +using RPGCoreCommon.Helpers.PropertyAttributeDrawers; +using UnityEngine; + +namespace RPGCore.Core.Objects +{ + [RequireComponent(typeof(CapsuleCollider))] + public class UnitObject : BaseObject + { + [DynamicValueProvider] + private ObjectModule UnitModuleProvider(Type moduleType) => GetComponent(moduleType) as ObjectModule; + + [field: SerializeField, ReadOnly] public CapsuleCollider unitCollider { get; private set; } + + protected new void OnValidate() + { + base.OnValidate(); + unitCollider = GetComponent(); + } + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/Core/Objects/UnitObject.cs.meta b/RPGCore/Runtime/Core/Objects/UnitObject.cs.meta new file mode 100644 index 0000000..0c88272 --- /dev/null +++ b/RPGCore/Runtime/Core/Objects/UnitObject.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e0e44d2cfbb316343b9be0d7bee42909 \ No newline at end of file diff --git a/RPGCore/Runtime/Core/SceneModule.cs b/RPGCore/Runtime/Core/SceneModule.cs new file mode 100644 index 0000000..114e352 --- /dev/null +++ b/RPGCore/Runtime/Core/SceneModule.cs @@ -0,0 +1,13 @@ +using System; +using UnityEngine; + +namespace RPGCore.Core +{ + /// + /// Extend this abstract class to create new module for scene logic. + /// + [Serializable] + public abstract class SceneModule : MonoBehaviour + { + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/Core/SceneModule.cs.meta b/RPGCore/Runtime/Core/SceneModule.cs.meta new file mode 100644 index 0000000..2d7f0a5 --- /dev/null +++ b/RPGCore/Runtime/Core/SceneModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ee04853ad1f04cf097b8b6c946f67896 +timeCreated: 1761424233 \ No newline at end of file diff --git a/RPGCore/Runtime/GlobalModules.meta b/RPGCore/Runtime/GlobalModules.meta new file mode 100644 index 0000000..94c3143 --- /dev/null +++ b/RPGCore/Runtime/GlobalModules.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b96ac46c8c044213bc24947f701eba38 +timeCreated: 1761773609 \ No newline at end of file diff --git a/RPGCore/Runtime/GlobalModules/ProfileManagerGlobalModule.meta b/RPGCore/Runtime/GlobalModules/ProfileManagerGlobalModule.meta new file mode 100644 index 0000000..132c88e --- /dev/null +++ b/RPGCore/Runtime/GlobalModules/ProfileManagerGlobalModule.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: edd53e70728b4e699b060546ad967812 +timeCreated: 1761769944 \ No newline at end of file diff --git a/RPGCore/Runtime/GlobalModules/ProfileManagerGlobalModule/Profile.cs b/RPGCore/Runtime/GlobalModules/ProfileManagerGlobalModule/Profile.cs new file mode 100644 index 0000000..b798518 --- /dev/null +++ b/RPGCore/Runtime/GlobalModules/ProfileManagerGlobalModule/Profile.cs @@ -0,0 +1,42 @@ +using System; +using UnityEngine; + +namespace RPGCore.GlobalModules.ProfileManagerGlobalModule +{ + [Serializable] + public sealed class Profile : Profile where T : class + { + public new T data + { + set => base.data = value; + get => base.data as T; + } + + public Profile() : this(Environment.MachineName) + { + } + + public Profile(string profileName) + { + name = profileName; + } + } + + public abstract class Profile + { + private protected Profile() + { + + } + + public readonly string guid = Guid.NewGuid().ToString(); + public readonly string version = Application.version; + public string name; + public object data; + + public static bool operator ==(Profile obj1, Profile obj2) => obj1?.guid == obj2?.guid; + public static bool operator !=(Profile obj1, Profile obj2) => !(obj1 == obj2); + public override bool Equals(object obj) => obj is Profile other && guid == other.guid; + public override int GetHashCode() => guid.GetHashCode(); + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/GlobalModules/ProfileManagerGlobalModule/Profile.cs.meta b/RPGCore/Runtime/GlobalModules/ProfileManagerGlobalModule/Profile.cs.meta new file mode 100644 index 0000000..f12c322 --- /dev/null +++ b/RPGCore/Runtime/GlobalModules/ProfileManagerGlobalModule/Profile.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e6fd81ed96154f9c807c110c191c8cdc +timeCreated: 1761770134 \ No newline at end of file diff --git a/RPGCore/Runtime/GlobalModules/ProfileManagerGlobalModule/ProfileManagerModule.cs b/RPGCore/Runtime/GlobalModules/ProfileManagerGlobalModule/ProfileManagerModule.cs new file mode 100644 index 0000000..a5501b5 --- /dev/null +++ b/RPGCore/Runtime/GlobalModules/ProfileManagerGlobalModule/ProfileManagerModule.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using RPGCore.Core; +using UnityEngine; + +namespace RPGCore.GlobalModules.ProfileManagerGlobalModule +{ + [Serializable] + public class ProfileManagerModule : GlobalModule + { + // Paths + private static string directoryPath => Path.Combine(Application.persistentDataPath, "profiles"); + private static string fileNameTemplate => "{0}_{1}.profile"; + private static string fileNameMask => "*.profile"; + private static string fileNameWithDefaultProfile => "default"; + + // Runtime + private Profile _activeProfile; + public event Action OnProfileChange; + + public Profile LoadDefault() where T : class + { + var defaultPath = Path.Combine(directoryPath, fileNameWithDefaultProfile); + + // Default file not found + if (!File.Exists(defaultPath)) return null; + var guid = File.ReadAllText(defaultPath); + + // Profile not found, by guid from default file + var file = Directory.GetFiles(directoryPath, string.Format(fileNameTemplate, "*", guid)).FirstOrDefault(); + if (file == null) return null; + + return JsonUtility.FromJson>(File.ReadAllText(file)); + } + + /// + /// Gets currently active profile + /// + public Profile Get() where T : class + { + return _activeProfile as Profile; + } + + /// + /// Parse all profiles from files and returns them. + /// There is no caching, it will scan files everytime it is called. + /// + public List> LoadAll() where T : class + { + if (!Directory.Exists(directoryPath)) Directory.CreateDirectory(directoryPath); + + return Directory.GetFiles(directoryPath, fileNameMask) + .Select(File.ReadAllText) + .Select(JsonUtility.FromJson>) + .ToList(); + } + + /// + /// Creates new profile with given name and saves it as file. + /// + public Profile Create(string name) where T : class + { + if (!Directory.Exists(directoryPath)) Directory.CreateDirectory(directoryPath); + + var newProfile = Activator.CreateInstance>(); + newProfile.name = name; + Save(newProfile); + + return newProfile; + } + + /// + /// Removes given profile from files and if its currently active unselects it. + /// + /// + public void Delete(Profile playerProfile) where T : class + { + if (playerProfile == _activeProfile) Select(null); + + if (!Directory.Exists(directoryPath)) Directory.CreateDirectory(directoryPath); + + File.Delete(GetFullPathFor(playerProfile)); + } + + /// + /// Saves currently active profile as file. + /// + public void Save() + { + Save(_activeProfile); + } + + /// + /// Saves given profile as file. + /// + private void Save(Profile profile) + { + if (!Directory.Exists(directoryPath)) Directory.CreateDirectory(directoryPath); + File.WriteAllText(GetFullPathFor(profile), JsonUtility.ToJson(profile, true)); + } + + /// + /// Set active given profile. Will be selected automatically next time. + /// + public void Select(Profile playerProfile) where T : class + { + _activeProfile = playerProfile; + OnProfileChange?.Invoke(_activeProfile); + + // No profile found - create it for user + _activeProfile ??= Create("New Profile"); + + // Our selected profile will be default one when starting game again + File.WriteAllText(Path.Combine(directoryPath, fileNameWithDefaultProfile), _activeProfile.guid); + } + + private string GetFullPathFor(Profile playerProfile) + { + var fileName = string.Format(fileNameTemplate, playerProfile.name, playerProfile.guid); + return Path.Combine(directoryPath, fileName); + } + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/GlobalModules/ProfileManagerGlobalModule/ProfileManagerModule.cs.meta b/RPGCore/Runtime/GlobalModules/ProfileManagerGlobalModule/ProfileManagerModule.cs.meta new file mode 100644 index 0000000..f754f7d --- /dev/null +++ b/RPGCore/Runtime/GlobalModules/ProfileManagerGlobalModule/ProfileManagerModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 453d820269db447db331f632048a4215 +timeCreated: 1761769954 \ No newline at end of file diff --git a/RPGCore/Runtime/InternalsVisibleTo.cs b/RPGCore/Runtime/InternalsVisibleTo.cs new file mode 100644 index 0000000..078329e --- /dev/null +++ b/RPGCore/Runtime/InternalsVisibleTo.cs @@ -0,0 +1,8 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("RPGCore.Editor")] + +namespace RPGCore +{ + +} \ No newline at end of file diff --git a/RPGCore/Runtime/InternalsVisibleTo.cs.meta b/RPGCore/Runtime/InternalsVisibleTo.cs.meta new file mode 100644 index 0000000..1df9d23 --- /dev/null +++ b/RPGCore/Runtime/InternalsVisibleTo.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: dc35dedc7f3842f683276368e463c9cf +timeCreated: 1761496306 \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules.meta b/RPGCore/Runtime/ObjectModules.meta new file mode 100644 index 0000000..e21ed95 --- /dev/null +++ b/RPGCore/Runtime/ObjectModules.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: fc81f48411244970b9151551a021ad98 +timeCreated: 1761773601 \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/ActionObjectModule.meta b/RPGCore/Runtime/ObjectModules/ActionObjectModule.meta new file mode 100644 index 0000000..8771c1d --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/ActionObjectModule.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2f34e092f2964013863c9278745b7c45 +timeCreated: 1762607253 \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/ActionObjectModule/ActionErrorException.cs b/RPGCore/Runtime/ObjectModules/ActionObjectModule/ActionErrorException.cs new file mode 100644 index 0000000..7388747 --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/ActionObjectModule/ActionErrorException.cs @@ -0,0 +1,14 @@ +using System; + +namespace RPGCore.ObjectModules.ActionObjectModule +{ + public class ActionErrorException : Exception + { + public readonly BaseAction action; + + public ActionErrorException(BaseAction action, string message) : base(message) + { + this.action = action; + } + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/ActionObjectModule/ActionErrorException.cs.meta b/RPGCore/Runtime/ObjectModules/ActionObjectModule/ActionErrorException.cs.meta new file mode 100644 index 0000000..3fab1de --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/ActionObjectModule/ActionErrorException.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 65d26dcf19b44027b8ff0890bb8ab920 +timeCreated: 1762608145 \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/ActionObjectModule/ActionModule.cs b/RPGCore/Runtime/ObjectModules/ActionObjectModule/ActionModule.cs new file mode 100644 index 0000000..742cb7b --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/ActionObjectModule/ActionModule.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using RPGCore.Core; +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.ActionObjectModule.Events; +using RPGCore.ObjectModules.EventObjectModule; +using RPGCoreCommon.Helpers; +using UnityEngine; + +namespace RPGCore.ObjectModules.ActionObjectModule +{ + [Serializable] + public class ActionModule : ObjectModule + { + private List _actionParallels = new(); + private readonly List _actionQueue = new(); + private BaseAction _actionCurrent; + + public List actionParallels => _actionParallels.ToList(); + public List actionQueue => _actionQueue.ToList(); + public BaseAction actionCurrent => _actionCurrent; + + private void FixedUpdate() + { + if (_actionCurrent?.state is not ActionState.Running) NextAction(); + } + + /// + /// 1. Checks if the action can be executed outside the queue.
+ /// 2. If allowed, executes the action and handles potential errors. + ///
+ public void Execute(BaseActionParallel action) + { + try + { + var actionExecuteEvent = new ActionExecuteEvent { action = action }; + parent.events.InvokeBefore(actionExecuteEvent); + if (actionExecuteEvent.isPrevented) throw new ActionErrorException(action, "Action is prevented"); + parent.events.InvokeAfter(actionExecuteEvent); + + _actionParallels.Add(action); + action.unit = parent; + action.OnEnd += () => _actionParallels.Remove(action); + action.OnCancel += () => _actionParallels.Remove(action); + action.DoIt(); + } + catch (ActionErrorException e) + { + parent.events.Invoke(new ActionErrorEvent + { + unit = parent, + action = e.action, + message = e.Message + }); + } + } + + public void Stop() + { + _actionParallels + .Where(action => action.CanBeStopped()) + .ForEach(action => action.CancelIt()) + .ForEach(action => _actionParallels.Remove(action)); + } + + /// + /// 1. Adds given action to queue + /// 2. Starts it if queue is empty + /// + public void AddToQueue(BaseAction action) => AddToQueue(new List { action }); + + /// + /// 1. Adds given actions to queue + /// 2. Runs only when previous action is finished successfully + /// 3. Starts it if queue is empty + /// + public void AddToQueue(List actions) + { + actions.ForEach(action => action.unit = parent); + + actions.ForEach((index, action) => + { + if (index != 0) action.runAfterAction = actions[index - 1]; + _actionQueue.Add(action); + }); + + if (_actionCurrent == null) NextAction(); + } + + /// + /// 1. Clear whole action queue + /// 2. Cancel current action IF specified by argument + /// 3. Some actions cant be stopped once fired by normal means, BUT we can force stopping it + /// + public void StopQueue(bool stopCurrent = true, bool stopForced = false) + { + _actionQueue.Clear(); + + if (!stopCurrent) return; + if (!stopForced && _actionCurrent != null && !_actionCurrent.CanBeStopped()) return; + + _actionCurrent?.CancelIt(); + _actionCurrent = null; + } + + /// + /// 1. Gets next action to do + /// 2. If there is no more actions - do nothing + /// 3. Proceed to execute it + /// + private void NextAction() + { + _actionCurrent = _actionQueue.FirstOrDefault(); + _actionQueue.Remove(_actionCurrent); + + if (_actionCurrent == null) return; + + try + { + var actionExecuteEvent = new ActionExecuteEvent { action = _actionCurrent }; + parent.events.InvokeBefore(actionExecuteEvent); + if (actionExecuteEvent.isPrevented) throw new ActionErrorException(_actionCurrent, "Action is prevented"); + parent.events.InvokeAfter(actionExecuteEvent); + + _actionCurrent.DoIt(); + } + catch (ActionErrorException e) + { + parent.events.Invoke(new ActionErrorEvent + { + unit = parent, + action = e.action, + message = e.Message + }); + } + + if (_actionCurrent.state is ActionState.Ready) Debug.LogWarning($"Action {_actionCurrent.GetType().Name} is still ready after starting. Skipping."); + if (_actionCurrent.state is not ActionState.Running) NextAction(); + } + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/ActionObjectModule/ActionModule.cs.meta b/RPGCore/Runtime/ObjectModules/ActionObjectModule/ActionModule.cs.meta new file mode 100644 index 0000000..34ec909 --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/ActionObjectModule/ActionModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 62d81cd897cb4ad29751fab9b0ee8ac6 +timeCreated: 1762607269 \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/ActionObjectModule/BaseAction.cs b/RPGCore/Runtime/ObjectModules/ActionObjectModule/BaseAction.cs new file mode 100644 index 0000000..753a203 --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/ActionObjectModule/BaseAction.cs @@ -0,0 +1,203 @@ +using System; +using RPGCore.Core.Objects; +using UnityEditor; +using UnityEngine; + +namespace RPGCore.ObjectModules.ActionObjectModule +{ + public enum ActionState + { + Ready, + Running, + Finished, + Cancelled + } + + /// + /// Action for .
+ /// + /// Executing order when used:
+ ///
    + ///
  • + ///
  • + ///
  • + ///
  • Inside OnDoIt:
  • + ///
  • Inside OnDoIt: Action's logic here
  • + ///
  • Inside OnDoIt: - obligatory if action ends immediately
  • + ///
+ /// + /// Executing order when used:
+ ///
    + ///
  • + ///
  • Inside OnEndIt: - obligatory if not used in OnDoIt
  • + ///
  • + ///
+ /// + /// Executing order when used:
+ ///
    + ///
  • + ///
  • Inside OnCancelIt: - obligatory if not used in OnDoIt
  • + ///
  • + ///
+ ///
+ [Serializable] + public abstract class BaseAction + { + public const string ActionNotReadyMessage = "This action is not ready to execute."; + public const string PreviousActionNotFinishedMessage = "Previous required action not finished successfully."; + public const string NotInRangeMessage = "Target is out of range."; + public const string UnitIsBusyMessage = "Unit is busy."; + public const string ItemNotMovableMessage = "Item is not on ground."; + public const string ItemNotOnGroundMessage = "Item is not on ground."; + public const string ActionWasPreventedMessage = "{0} action was prevented."; + + /// + /// that started executing this action.
+ /// Filled automatically in /.
+ /// If you want to use it before executing action you need to fill yourself! + ///
+ public UnitObject unit; + + /// Run after checking and before executing action. + public event Action OnDo; + + /// Defined by referenced action. Usually right *before* main point of that action. + public event Action OnBeforePerform; + + /// Defined by referenced action. Usually right *after* main point of that action. + public event Action OnAfterPerform; + + /// Run after action ended. + public event Action OnEnd; + + /// Run after action ended forcefully. + public event Action OnCancel; + + /// Current state of action. + public ActionState state { get; protected set; } = ActionState.Ready; + + /// If given, current action will be executed only if given one is finished successfully + public BaseAction runAfterAction; + + /// Simple check if unit is in range to execute this action. + public virtual bool IsInRange() => true; + + /// Determines whether this action CAN be stopped early, by something else besides itself. + public virtual bool CanBeStopped() => true; + + /// + /// Action's checks if action can be executed. have to be used here.
+ /// Field this.unit may not be available here when called manually not via .
+ ///
+ public abstract void CanDoIt(); + + /// Action's logic. + protected abstract void OnDoIt(); + + /// Action's logic when whole action ends successfully. + protected abstract void OnEndIt(); + + /// Action's logic when whole action is forced to end. + protected abstract void OnCancelIt(); + + /// + public bool CanDoItBoolean() + { + try + { + CanDoIt(); + return true; + } + catch (ActionErrorException) + { + return false; + } + } + + /// + /// 1. Checking if action can be done by function in child:
+ /// 2. Executing main login of this action + ///
+ internal void DoIt() + { + Check( + state == ActionState.Ready, + ActionNotReadyMessage); + Check( + runAfterAction == null || runAfterAction.state == ActionState.Finished, + PreviousActionNotFinishedMessage); + Check( + IsInRange(), + NotInRangeMessage); + + CanDoIt(); + state = ActionState.Running; + OnDo?.Invoke(); + OnDoIt(); + } + + /// + /// Executed by action itself when everything is done correctly. + /// + protected void EndIt() + { + if (state is ActionState.Finished or ActionState.Cancelled) + { + Debug.LogWarning($"{ObjectNames.NicifyVariableName(GetType().Name)} is already finished. State: '{state}'"); + return; + } + + OnEndIt(); + state = ActionState.Finished; + OnEnd?.Invoke(); + } + + /// + /// Executed by external source. Stopping this action forcefully. + /// + public void CancelIt() + { + // Cancel events only when action really started otherwise there will be nothing to cancel + if (state == ActionState.Running) + { + OnCancelIt(); + OnCancel?.Invoke(); + } + + state = ActionState.Cancelled; + } + + /// + /// Should be executed from child right before main logic is started, usually in + /// + protected void BeforePerform() + { + OnBeforePerform?.Invoke(); + } + + /// + /// Should be executed from child right after main logic is done, usually in + /// + protected void AfterPerform() + { + OnAfterPerform?.Invoke(); + } + + /// + /// Execute if check is false + /// + protected void Check(bool condition, string elseErrorMessage) + { + if (!condition) Throw(elseErrorMessage); + } + + /// + /// Cancels this Action and then throw + /// + protected void Throw(string errorMessage) + { + CancelIt(); + throw new ActionErrorException(this, errorMessage); + } + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/ActionObjectModule/BaseAction.cs.meta b/RPGCore/Runtime/ObjectModules/ActionObjectModule/BaseAction.cs.meta new file mode 100644 index 0000000..9b04a52 --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/ActionObjectModule/BaseAction.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8ac7c378ad684142b41ceea5e99636eb +timeCreated: 1762607985 \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/ActionObjectModule/BaseActionParallel.cs b/RPGCore/Runtime/ObjectModules/ActionObjectModule/BaseActionParallel.cs new file mode 100644 index 0000000..22357ad --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/ActionObjectModule/BaseActionParallel.cs @@ -0,0 +1,7 @@ +namespace RPGCore.ObjectModules.ActionObjectModule +{ + public abstract class BaseActionParallel : BaseAction + { + + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/ActionObjectModule/BaseActionParallel.cs.meta b/RPGCore/Runtime/ObjectModules/ActionObjectModule/BaseActionParallel.cs.meta new file mode 100644 index 0000000..f234716 --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/ActionObjectModule/BaseActionParallel.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e46b8a02e3894ecb87b4455602287715 +timeCreated: 1762624491 \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/ActionObjectModule/Events.meta b/RPGCore/Runtime/ObjectModules/ActionObjectModule/Events.meta new file mode 100644 index 0000000..77fec7e --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/ActionObjectModule/Events.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: dbe46bc39ef7485cac06ad32831cac3a +timeCreated: 1764885371 \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/ActionObjectModule/Events/ActionErrorEvent.cs b/RPGCore/Runtime/ObjectModules/ActionObjectModule/Events/ActionErrorEvent.cs new file mode 100644 index 0000000..3891a29 --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/ActionObjectModule/Events/ActionErrorEvent.cs @@ -0,0 +1,12 @@ +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; + +namespace RPGCore.ObjectModules.ActionObjectModule.Events +{ + public class ActionErrorEvent : BaseEvent + { + public UnitObject unit; + public BaseAction action; + public string message; + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/ActionObjectModule/Events/ActionErrorEvent.cs.meta b/RPGCore/Runtime/ObjectModules/ActionObjectModule/Events/ActionErrorEvent.cs.meta new file mode 100644 index 0000000..897af0f --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/ActionObjectModule/Events/ActionErrorEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 48b0c69fc332472e87f34822bed20ffd +timeCreated: 1762611515 \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/ActionObjectModule/Events/ActionExecuteEvent.cs b/RPGCore/Runtime/ObjectModules/ActionObjectModule/Events/ActionExecuteEvent.cs new file mode 100644 index 0000000..33875de --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/ActionObjectModule/Events/ActionExecuteEvent.cs @@ -0,0 +1,11 @@ +using RPGCore.Core.Objects; +using RPGCore.ObjectModules.EventObjectModule; + +namespace RPGCore.ObjectModules.ActionObjectModule.Events +{ + public class ActionExecuteEvent : BasePreventableEvent + { + public UnitObject unit; + public BaseAction action; + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/ActionObjectModule/Events/ActionExecuteEvent.cs.meta b/RPGCore/Runtime/ObjectModules/ActionObjectModule/Events/ActionExecuteEvent.cs.meta new file mode 100644 index 0000000..c3b5d1e --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/ActionObjectModule/Events/ActionExecuteEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 414af8b649334795bb3e1bc83149fbc3 +timeCreated: 1772998772 \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/DataObjectModule.meta b/RPGCore/Runtime/ObjectModules/DataObjectModule.meta new file mode 100644 index 0000000..96be61c --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/DataObjectModule.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e8d01c287c954d278388eb561ce813cf +timeCreated: 1773604338 \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/DataObjectModule/BaseData.cs b/RPGCore/Runtime/ObjectModules/DataObjectModule/BaseData.cs new file mode 100644 index 0000000..fcb6587 --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/DataObjectModule/BaseData.cs @@ -0,0 +1,30 @@ +using System; +using RPGCore.Core.Objects; + +namespace RPGCore.ObjectModules.EventObjectModule +{ + /// + /// Extend this to create new type of data for <> type of object.
+ /// To retrieve this data from <> object use . + ///
+ /// (or any of its children) that this event can be attached to. + [Serializable] + public abstract class BaseData : BaseData where T : BaseObject + { + public new T parent => (T)base.parent; + } + + /// + /// DO NOT EXTEND THIS, use instead! + /// + [Serializable] + public abstract class BaseData + { + internal BaseObject parent; + + private protected BaseData() + { + + } + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/DataObjectModule/BaseData.cs.meta b/RPGCore/Runtime/ObjectModules/DataObjectModule/BaseData.cs.meta new file mode 100644 index 0000000..23b14f4 --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/DataObjectModule/BaseData.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a960c2eadeca4d4aa8d1c454daca552f +timeCreated: 1773604425 \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/DataObjectModule/Data.meta b/RPGCore/Runtime/ObjectModules/DataObjectModule/Data.meta new file mode 100644 index 0000000..a9f85fb --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/DataObjectModule/Data.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9970c419f4d94c22988563c8f8a50dc7 +timeCreated: 1774171193 \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/DataObjectModule/Data/BaseObjectData.cs b/RPGCore/Runtime/ObjectModules/DataObjectModule/Data/BaseObjectData.cs new file mode 100644 index 0000000..291066f --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/DataObjectModule/Data/BaseObjectData.cs @@ -0,0 +1,18 @@ +using System; +using RPGCore.Core.Objects; +using RPGCoreCommon.Helpers.PropertyAttributeDrawers; +using UnityEngine; + +namespace RPGCore.ObjectModules.EventObjectModule.Data +{ + [Serializable] + public class BaseObjectData : BaseData + { + [Header("Uniqueness")] + [field: SerializeField, ReadOnly] public string guid { get; private set; } = Guid.NewGuid().ToString(); + + [Header("Display")] + public string name; + public Texture2D icon; + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/DataObjectModule/Data/BaseObjectData.cs.meta b/RPGCore/Runtime/ObjectModules/DataObjectModule/Data/BaseObjectData.cs.meta new file mode 100644 index 0000000..f14242d --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/DataObjectModule/Data/BaseObjectData.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 53d2c35f3deb43588a3585e248d0a05e +timeCreated: 1774171200 \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/DataObjectModule/DataModule.cs b/RPGCore/Runtime/ObjectModules/DataObjectModule/DataModule.cs new file mode 100644 index 0000000..476cbe3 --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/DataObjectModule/DataModule.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using RPGCore.Core; +using RPGCore.Core.Objects; +using UnityEngine; + +namespace RPGCore.ObjectModules.EventObjectModule +{ + [Serializable] + [RequireComponent(typeof(BaseObject))] + public class DataModule : ObjectModule + { + // SERIALIZED + [SerializeReference] private List _dataList = new(); + + // RUNTIME + private Dictionary _dataDict; + + private void OnValidate() + { + if (!parent) return; + + // Remove invalid + if (_dataList.Any(data => data == null)) + _dataList = _dataList.Where(data => data != null).ToList(); + + // Remove duplicates + if (_dataList.GroupBy(data => data.GetType()).Any(g => g.Count() > 1)) + _dataList = _dataList.GroupBy(data => data.GetType()).Select(g => g.First()).ToList(); + + // Create missing datas + UnityEditor.TypeCache.GetTypesDerivedFrom() + .Append(typeof(BaseObject)) + .Where(t => t.IsAssignableFrom(parent.GetType())) + .Select(t => typeof(BaseData<>).MakeGenericType(t)) + .SelectMany(t => UnityEditor.TypeCache.GetTypesDerivedFrom(t)) + .Where(t => !_dataList.Select(data => data.GetType()).Contains(t)) + .ToList().ForEach(t => _dataList.Add(Activator.CreateInstance(t) as BaseData)); + + _dataList.ForEach(data => data.parent = parent); + } + + private void Awake() + { + _dataDict = _dataList.ToDictionary(data => data.GetType(), data => data); + } + + public T Get() where T : BaseData + { + return (T)_dataDict[typeof(T)]; + } + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/DataObjectModule/DataModule.cs.meta b/RPGCore/Runtime/ObjectModules/DataObjectModule/DataModule.cs.meta new file mode 100644 index 0000000..fae25d4 --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/DataObjectModule/DataModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: fa1c3e4ec0e74aa1a52278c024599a01 +timeCreated: 1773604350 \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/EventObjectModule.meta b/RPGCore/Runtime/ObjectModules/EventObjectModule.meta new file mode 100644 index 0000000..b22839e --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/EventObjectModule.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 850e39c8cad04b979fbb825dc7821c75 +timeCreated: 1761863862 \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/EventObjectModule/BaseEvent.cs b/RPGCore/Runtime/ObjectModules/EventObjectModule/BaseEvent.cs new file mode 100644 index 0000000..a99b677 --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/EventObjectModule/BaseEvent.cs @@ -0,0 +1,24 @@ +using RPGCore.Core.Objects; + +namespace RPGCore.ObjectModules.EventObjectModule +{ + /// + /// Extend this to create new type of event for <> type of object.

+ /// This event is called once by .: + ///
+ /// (or any of its children) that this event can be attached to. + /// + public abstract class BaseEvent : BaseEvent where T : BaseObject + { + } + + /// + /// DO NOT EXTEND THIS, use instead! + /// + public abstract class BaseEvent + { + protected internal BaseEvent() + { + } + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/EventObjectModule/BaseEvent.cs.meta b/RPGCore/Runtime/ObjectModules/EventObjectModule/BaseEvent.cs.meta new file mode 100644 index 0000000..6f9c84c --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/EventObjectModule/BaseEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 71103e95ef1449e096cf7e813cc339dc +timeCreated: 1761865102 \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/EventObjectModule/BasePreventableEvent.cs b/RPGCore/Runtime/ObjectModules/EventObjectModule/BasePreventableEvent.cs new file mode 100644 index 0000000..11b5d79 --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/EventObjectModule/BasePreventableEvent.cs @@ -0,0 +1,27 @@ +using RPGCore.Core.Objects; + +namespace RPGCore.ObjectModules.EventObjectModule +{ + /// + /// Extend this to create new type of preventable event for <> type of object.

+ /// This event can be called twice by : + ///
    + ///
  • + ///
  • - if not prevented in before
  • + ///
+ ///
+ /// (or any of its children) that this event can be attached to. + /// + public abstract class BasePreventableEvent : BasePreventableEvent where T : BaseObject + { + } + + public abstract class BasePreventableEvent + { + public bool isPrevented; + + protected internal BasePreventableEvent() + { + } + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/EventObjectModule/BasePreventableEvent.cs.meta b/RPGCore/Runtime/ObjectModules/EventObjectModule/BasePreventableEvent.cs.meta new file mode 100644 index 0000000..13368bb --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/EventObjectModule/BasePreventableEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ff4239f29db24fc787c11af5bc1fdaca +timeCreated: 1761865162 \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/EventObjectModule/EventModule.cs b/RPGCore/Runtime/ObjectModules/EventObjectModule/EventModule.cs new file mode 100644 index 0000000..ba8aaca --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/EventObjectModule/EventModule.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using RPGCore.Core; +using RPGCore.Core.Objects; + +namespace RPGCore.ObjectModules.EventObjectModule +{ + [Serializable] + public class EventModule : ObjectModule + { + // TODO: tutaj dodać serializowane eventy w postaci SerializableDictionary + // TODO: dodatkowo mozna zmienić preventableEvents na dwa osobne słowniki before i after + + internal readonly Dictionary events = new(); + internal readonly Dictionary preventableEvents = new(); + + public void Invoke(T baseEvent) where T : BaseEvent + { + events.TryAdd(typeof(T), null); + (events[typeof(T)] as Action)?.Invoke(baseEvent); + } + + public void Register(Action action) where T : BaseEvent + { + events.TryAdd(typeof(T), null); + var temp = (Action)events[typeof(T)]; + temp += action; + events[typeof(T)] = temp; + } + + public void Unregister(Action action) where T : BaseEvent + { + events.TryAdd(typeof(T), null); + var temp = (Action)events[typeof(T)]; + temp -= action; + events[typeof(T)] = temp; + } + + public void InvokeBefore(T basePreventableEvent) where T : BasePreventableEvent + { + preventableEvents.TryAdd(typeof(T), new Delegate[2]); + (preventableEvents[typeof(T)][0] as Action)?.Invoke(basePreventableEvent); + } + + public void RegisterBefore(Action action) where T : BasePreventableEvent + { + preventableEvents.TryAdd(typeof(T), new Delegate[2]); + var temp = (Action)preventableEvents[typeof(T)][0]; + temp += action; + preventableEvents[typeof(T)][0] = temp; + } + + public void UnregisterBefore(Action action) where T : BasePreventableEvent + { + preventableEvents.TryAdd(typeof(T), new Delegate[2]); + var temp = (Action)preventableEvents[typeof(T)][0]; + temp -= action; + preventableEvents[typeof(T)][0] = temp; + } + + public void InvokeAfter(T basePreventableEvent) where T : BasePreventableEvent + { + if (basePreventableEvent.isPrevented) throw new EventPreventedException("Event is prevented and can't be invoked!"); + preventableEvents.TryAdd(typeof(T), new Delegate[2]); + (preventableEvents[typeof(T)][1] as Action)?.Invoke(basePreventableEvent); + } + + public void RegisterAfter(Action action) where T : BasePreventableEvent + { + preventableEvents.TryAdd(typeof(T), new Delegate[2]); + var temp = (Action)preventableEvents[typeof(T)][1]; + temp += action; + preventableEvents[typeof(T)][1] = temp; + } + + public void UnregisterAfter(Action action) where T : BasePreventableEvent + { + preventableEvents.TryAdd(typeof(T), new Delegate[2]); + var temp = (Action)preventableEvents[typeof(T)][1]; + temp -= action; + preventableEvents[typeof(T)][1] = temp; + } + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/EventObjectModule/EventModule.cs.meta b/RPGCore/Runtime/ObjectModules/EventObjectModule/EventModule.cs.meta new file mode 100644 index 0000000..af282b7 --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/EventObjectModule/EventModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3fa533ce2d5945ec9f533cfd956a5394 +timeCreated: 1761863930 \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/EventObjectModule/EventPreventedException.cs b/RPGCore/Runtime/ObjectModules/EventObjectModule/EventPreventedException.cs new file mode 100644 index 0000000..3b23d61 --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/EventObjectModule/EventPreventedException.cs @@ -0,0 +1,11 @@ +using System; + +namespace RPGCore.ObjectModules.EventObjectModule +{ + public class EventPreventedException : Exception + { + public EventPreventedException(string message) : base(message) + { + } + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/EventObjectModule/EventPreventedException.cs.meta b/RPGCore/Runtime/ObjectModules/EventObjectModule/EventPreventedException.cs.meta new file mode 100644 index 0000000..ae8986b --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/EventObjectModule/EventPreventedException.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a647e5d4d4ed44c28fd6961d60943fe4 +timeCreated: 1761917482 \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/EventObjectModule/Events.meta b/RPGCore/Runtime/ObjectModules/EventObjectModule/Events.meta new file mode 100644 index 0000000..eed10ca --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/EventObjectModule/Events.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 579fbe50273b4fa78b63536a5c316b68 +timeCreated: 1762712676 \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/EventObjectModule/Events/RemoveEvent.cs b/RPGCore/Runtime/ObjectModules/EventObjectModule/Events/RemoveEvent.cs new file mode 100644 index 0000000..467c21b --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/EventObjectModule/Events/RemoveEvent.cs @@ -0,0 +1,9 @@ +using RPGCore.Core.Objects; + +namespace RPGCore.ObjectModules.EventObjectModule.Events +{ + public class RemoveEvent : BaseEvent + { + public BaseObject obj; + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/EventObjectModule/Events/RemoveEvent.cs.meta b/RPGCore/Runtime/ObjectModules/EventObjectModule/Events/RemoveEvent.cs.meta new file mode 100644 index 0000000..de3fc6d --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/EventObjectModule/Events/RemoveEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 11c3329262c8465b9a3010eea4f08e69 +timeCreated: 1761916133 \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/EventObjectModule/Events/SpawnEvent.cs b/RPGCore/Runtime/ObjectModules/EventObjectModule/Events/SpawnEvent.cs new file mode 100644 index 0000000..76d2f2c --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/EventObjectModule/Events/SpawnEvent.cs @@ -0,0 +1,9 @@ +using RPGCore.Core.Objects; + +namespace RPGCore.ObjectModules.EventObjectModule.Events +{ + public class SpawnEvent : BaseEvent + { + + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/EventObjectModule/Events/SpawnEvent.cs.meta b/RPGCore/Runtime/ObjectModules/EventObjectModule/Events/SpawnEvent.cs.meta new file mode 100644 index 0000000..cbde0c7 --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/EventObjectModule/Events/SpawnEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d57d2e777dd44799a419a6a81dc1558a +timeCreated: 1761913423 \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/EventObjectModule/Events/TriggerEnterEvent.cs b/RPGCore/Runtime/ObjectModules/EventObjectModule/Events/TriggerEnterEvent.cs new file mode 100644 index 0000000..c657e2b --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/EventObjectModule/Events/TriggerEnterEvent.cs @@ -0,0 +1,11 @@ +using RPGCore.Core; +using RPGCore.Core.Objects; + +namespace RPGCore.ObjectModules.EventObjectModule.Events +{ + public class TriggerEnterEvent : BaseEvent + { + public BaseObject target; + public ITrigger trigger; + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/EventObjectModule/Events/TriggerEnterEvent.cs.meta b/RPGCore/Runtime/ObjectModules/EventObjectModule/Events/TriggerEnterEvent.cs.meta new file mode 100644 index 0000000..1cd9c77 --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/EventObjectModule/Events/TriggerEnterEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3a95611010304d37ad43daf0b18dd30c +timeCreated: 1761916203 \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/EventObjectModule/Events/TriggerExitEvent.cs b/RPGCore/Runtime/ObjectModules/EventObjectModule/Events/TriggerExitEvent.cs new file mode 100644 index 0000000..8304dca --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/EventObjectModule/Events/TriggerExitEvent.cs @@ -0,0 +1,11 @@ +using RPGCore.Core; +using RPGCore.Core.Objects; + +namespace RPGCore.ObjectModules.EventObjectModule.Events +{ + public class TriggerExitEvent : BaseEvent + { + public BaseObject target; + public ITrigger trigger; + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/ObjectModules/EventObjectModule/Events/TriggerExitEvent.cs.meta b/RPGCore/Runtime/ObjectModules/EventObjectModule/Events/TriggerExitEvent.cs.meta new file mode 100644 index 0000000..2d955ba --- /dev/null +++ b/RPGCore/Runtime/ObjectModules/EventObjectModule/Events/TriggerExitEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d36459dce15b4f69b33ddcf21b6bdc3d +timeCreated: 1762710866 \ No newline at end of file diff --git a/RPGCore/Runtime/RPGCore.asmdef b/RPGCore/Runtime/RPGCore.asmdef new file mode 100644 index 0000000..9f7aaef --- /dev/null +++ b/RPGCore/Runtime/RPGCore.asmdef @@ -0,0 +1,19 @@ +{ + "name": "RPGCore", + "rootNamespace": "RPGCore", + "references": [ + "RPGCoreCommon.Settings", + "RPGCoreCommon.Helpers", + "RPGCoreCommon.DynamicValues", + "Unity.InputSystem" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/RPGCore/Runtime/RPGCore.asmdef.meta b/RPGCore/Runtime/RPGCore.asmdef.meta new file mode 100644 index 0000000..4dc87ed --- /dev/null +++ b/RPGCore/Runtime/RPGCore.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 91139c31a3a64b34786bf786ad0bafe6 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/RPGCore/Runtime/SceneModules.meta b/RPGCore/Runtime/SceneModules.meta new file mode 100644 index 0000000..58f9b81 --- /dev/null +++ b/RPGCore/Runtime/SceneModules.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f1b8f1cf4fa940859c0492e9733264fb +timeCreated: 1761773615 \ No newline at end of file diff --git a/RPGCore/Runtime/SceneModules/PathVisualizerSceneModule.meta b/RPGCore/Runtime/SceneModules/PathVisualizerSceneModule.meta new file mode 100644 index 0000000..90d59a4 --- /dev/null +++ b/RPGCore/Runtime/SceneModules/PathVisualizerSceneModule.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7d9da26ac20749b18818b4a4cefe65ea +timeCreated: 1761774471 \ No newline at end of file diff --git a/RPGCore/Runtime/SceneModules/PathVisualizerSceneModule/PathVisualizer.cs b/RPGCore/Runtime/SceneModules/PathVisualizerSceneModule/PathVisualizer.cs new file mode 100644 index 0000000..5df0736 --- /dev/null +++ b/RPGCore/Runtime/SceneModules/PathVisualizerSceneModule/PathVisualizer.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.AI; +using UnityEngine.Rendering; +using UnityEngine.Serialization; + +namespace RPGCore.SceneModules.PathVisualizerSceneModule +{ + public class PathVisualizer : MonoBehaviour + { + private Func> _pathGetter; + private LineRenderer _lineRenderer; + + private float _autoUpdateDelta; + + public bool autoUpdate; + public float autoUpdateTime; + public float verticalOffset; + + public float lineSize + { + get => _lineRenderer.startWidth; + set => _lineRenderer.startWidth = _lineRenderer.endWidth = value; + } + + public Material material + { + get => _lineRenderer.material; + set => _lineRenderer.material = value; + } + + public void SetPath(Vector3 start, Vector3 end, int navMeshAreaMask) + { + var path = new NavMeshPath(); + NavMesh.CalculatePath(start, end, navMeshAreaMask, path); + _pathGetter = () => path.corners; + UpdatePath(); + } + + public void SetPath(NavMeshAgent agent, Vector3 destination) + { + var path = new NavMeshPath(); + agent.CalculatePath(destination, path); + _pathGetter = () => path.corners; + UpdatePath(); + } + + public void SetPath(NavMeshPath path) + { + _pathGetter = () => path.corners; + UpdatePath(); + } + + public void SetPath(IEnumerable customPath) + { + _pathGetter = () => customPath.Select(t => t.position); + UpdatePath(); + } + + public void SetPath(IEnumerable customPath) + { + _pathGetter = () => customPath; + UpdatePath(); + } + + public void SetPath(Func> pathGetter) + { + _pathGetter = pathGetter; + UpdatePath(); + } + + private void Awake() + { + _lineRenderer = gameObject.AddComponent(); + _lineRenderer.enabled = true; + _lineRenderer.shadowCastingMode = ShadowCastingMode.Off; + _lineRenderer.numCapVertices = 3; + _lineRenderer.numCornerVertices = 3; + } + + private void FixedUpdate() + { + if (!autoUpdate) return; + _autoUpdateDelta += Time.fixedDeltaTime; + if (_autoUpdateDelta < autoUpdateTime) return; + _autoUpdateDelta = 0; + UpdatePath(); + } + + private void UpdatePath() + { + if (_pathGetter == null) return; + var path = _pathGetter().Select(pos => pos + Vector3.up * verticalOffset).ToArray(); + _lineRenderer.positionCount = path.Length; + _lineRenderer.SetPositions(path); + } + + public void Show() + { + _lineRenderer.enabled = true; + } + + public void Hide() + { + _lineRenderer.enabled = false; + } + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/SceneModules/PathVisualizerSceneModule/PathVisualizer.cs.meta b/RPGCore/Runtime/SceneModules/PathVisualizerSceneModule/PathVisualizer.cs.meta new file mode 100644 index 0000000..69aee28 --- /dev/null +++ b/RPGCore/Runtime/SceneModules/PathVisualizerSceneModule/PathVisualizer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6fdd2eabc020430e881b60cda5926a0a +timeCreated: 1761830900 \ No newline at end of file diff --git a/RPGCore/Runtime/SceneModules/PathVisualizerSceneModule/PathVisualizerModule.cs b/RPGCore/Runtime/SceneModules/PathVisualizerSceneModule/PathVisualizerModule.cs new file mode 100644 index 0000000..388b2e1 --- /dev/null +++ b/RPGCore/Runtime/SceneModules/PathVisualizerSceneModule/PathVisualizerModule.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using RPGCore.Core; +using UnityEngine; + +namespace RPGCore.SceneModules.PathVisualizerSceneModule +{ + [Serializable] + public class PathVisualizerModule : SceneModule + { + // Configuration + [SerializeField] private float _defaultAutoUpdateTime = 0.1f; + [SerializeField] private float _defaultLineSize = 0.05f; + [SerializeField] private float _defaultVerticalOffset = 0.1f; + [SerializeField] private Material _defaultMaterial; + + // References + internal List pathVisualizers = new(); + + public PathVisualizer Create() + { + var gameObject = new GameObject("PathVisualizer"); + gameObject.transform.parent = this.gameObject.transform; + + var pathVisualizer = gameObject.AddComponent(); + pathVisualizers.Add(pathVisualizer); + pathVisualizer.autoUpdateTime = _defaultAutoUpdateTime; + pathVisualizer.lineSize = _defaultLineSize; + pathVisualizer.verticalOffset = _defaultVerticalOffset; + pathVisualizer.material = _defaultMaterial; + return pathVisualizer; + } + } +} \ No newline at end of file diff --git a/RPGCore/Runtime/SceneModules/PathVisualizerSceneModule/PathVisualizerModule.cs.meta b/RPGCore/Runtime/SceneModules/PathVisualizerSceneModule/PathVisualizerModule.cs.meta new file mode 100644 index 0000000..31aa81c --- /dev/null +++ b/RPGCore/Runtime/SceneModules/PathVisualizerSceneModule/PathVisualizerModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6eeee4c859ea44119fd2347e9b778b72 +timeCreated: 1761830760 \ No newline at end of file diff --git a/RPGCoreCommon.meta b/RPGCoreCommon.meta new file mode 100644 index 0000000..584d69e --- /dev/null +++ b/RPGCoreCommon.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5f306724035b4beea38a456846628054 +timeCreated: 1759058825 \ No newline at end of file diff --git a/RPGCoreCommon/Debugger.meta b/RPGCoreCommon/Debugger.meta new file mode 100644 index 0000000..c1070a7 --- /dev/null +++ b/RPGCoreCommon/Debugger.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bcb9b22dd65d7324f920cbdbad57fb0a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/RPGCoreCommon/Debugger/Editor.meta b/RPGCoreCommon/Debugger/Editor.meta new file mode 100644 index 0000000..ced9525 --- /dev/null +++ b/RPGCoreCommon/Debugger/Editor.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5de987142cf530f4dbc778193b3cb9ab +timeCreated: 1776005920 \ No newline at end of file diff --git a/RPGCoreCommon/Debugger/Editor/RPGCoreCommon.Debugger.Editor.asmdef b/RPGCoreCommon/Debugger/Editor/RPGCoreCommon.Debugger.Editor.asmdef new file mode 100644 index 0000000..602c323 --- /dev/null +++ b/RPGCoreCommon/Debugger/Editor/RPGCoreCommon.Debugger.Editor.asmdef @@ -0,0 +1,16 @@ +{ + "name": "RPGCoreCommon.Debugger.Editor", + "rootNamespace": "RPGCoreCommon.Debugger", + "references": [ + "RPGCoreCommon.Debugger" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/RPGCoreCommon/Debugger/Editor/RPGCoreCommon.Debugger.Editor.asmdef.meta b/RPGCoreCommon/Debugger/Editor/RPGCoreCommon.Debugger.Editor.asmdef.meta new file mode 100644 index 0000000..d6387d7 --- /dev/null +++ b/RPGCoreCommon/Debugger/Editor/RPGCoreCommon.Debugger.Editor.asmdef.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 527334016fe26c649a09686dc0a7ba5d +timeCreated: 1776005962 \ No newline at end of file diff --git a/RPGCoreCommon/Debugger/Runtime.meta b/RPGCoreCommon/Debugger/Runtime.meta new file mode 100644 index 0000000..e3e0d45 --- /dev/null +++ b/RPGCoreCommon/Debugger/Runtime.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b5be5cfce8c2e47449c59b6d3ac62a1d +timeCreated: 1776005926 \ No newline at end of file diff --git a/RPGCoreCommon/Debugger/Runtime/RPGCoreCommon.Debugger.asmdef b/RPGCoreCommon/Debugger/Runtime/RPGCoreCommon.Debugger.asmdef new file mode 100644 index 0000000..3017649 --- /dev/null +++ b/RPGCoreCommon/Debugger/Runtime/RPGCoreCommon.Debugger.asmdef @@ -0,0 +1,14 @@ +{ + "name": "RPGCoreCommon.Debugger", + "rootNamespace": "RPGCoreCommon.Debugger", + "references": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/RPGCoreCommon/Debugger/Runtime/RPGCoreCommon.Debugger.asmdef.meta b/RPGCoreCommon/Debugger/Runtime/RPGCoreCommon.Debugger.asmdef.meta new file mode 100644 index 0000000..d469089 --- /dev/null +++ b/RPGCoreCommon/Debugger/Runtime/RPGCoreCommon.Debugger.asmdef.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0567806f31a0634458422c1f723e1a49 +timeCreated: 1776005940 \ No newline at end of file diff --git a/RPGCoreCommon/DropTable.meta b/RPGCoreCommon/DropTable.meta new file mode 100644 index 0000000..7676673 --- /dev/null +++ b/RPGCoreCommon/DropTable.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 56524ae74f554e0d9d7470f4cf9c338d +timeCreated: 1760521408 \ No newline at end of file diff --git a/RPGCoreCommon/DropTable/Editor.meta b/RPGCoreCommon/DropTable/Editor.meta new file mode 100644 index 0000000..95f8c33 --- /dev/null +++ b/RPGCoreCommon/DropTable/Editor.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4914a4d27525472aac1393e98ed6b8e2 +timeCreated: 1760521419 \ No newline at end of file diff --git a/RPGCoreCommon/DropTable/Editor/DropTableDrawer.cs b/RPGCoreCommon/DropTable/Editor/DropTableDrawer.cs new file mode 100644 index 0000000..c4bbf68 --- /dev/null +++ b/RPGCoreCommon/DropTable/Editor/DropTableDrawer.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using RPGCoreCommon.Helpers; +using UnityEditor; +using UnityEditor.UIElements; +using UnityEngine; +using UnityEngine.UIElements; +using Object = UnityEngine.Object; + +namespace RPGCoreCommon.DropTable.Editor +{ + [Serializable] + [CanEditMultipleObjects] + [CustomEditor(typeof(DropTableSO))] + public class DropTableDrawer : UnityEditor.Editor + { + [SerializeField] private VisualTreeAsset _groupVisualTreeAsset; + [SerializeField] private VisualTreeAsset _rowVisualTreeAsset; + public static VisualTreeAsset groupVisualTreeAsset { get; private set; } + public static VisualTreeAsset rowVisualTreeAsset { get; private set; } + + public override VisualElement CreateInspectorGUI() + { + groupVisualTreeAsset = _groupVisualTreeAsset; + rowVisualTreeAsset = _rowVisualTreeAsset; + + if (serializedObject.isEditingMultipleObjects) + return new HelpBox($"Multiple {nameof(DropTableSO)} editing is disabled.", HelpBoxMessageType.Warning); + + var property = serializedObject.FindProperty(nameof(DropTableSO.group)); + + var wrapper = new VisualElement(); + wrapper.schedule.Execute(() => + { + var mainInspector = wrapper.GetFirstAncestorOfType(); + mainInspector.style.paddingLeft = 4f; + mainInspector.style.paddingRight = 4f; + }); + + var resultBox = new HelpBox(); + resultBox.style.display = DisplayStyle.None; + resultBox.style.unityTextAlign = TextAnchor.MiddleCenter; + + var resultButton = new Button(); + resultButton.style.marginTop = 20f; + resultButton.clicked += () => PrintResult(resultBox, property.boxedValue as DropTableGroup); + resultButton.text = "Try your luck..."; + + wrapper.Add(new DropTableGroupElement(property)); + wrapper.Add(resultButton); + wrapper.Add(resultBox); + return wrapper; + } + + private void PrintResult(HelpBox resultBox, DropTableGroup value) + { + resultBox.Clear(); + resultBox.style.display = DisplayStyle.Flex; + var result = new Dictionary(); + value.Get(ref result); + result.DictForEach((item, count) => + { + var row = new VisualElement(); + row.style.flexDirection = FlexDirection.Row; + row.Add(new ObjectField{value = item, enabledSelf = false}); + row.Add(new Label($" -> {count}")); + resultBox.Add(row); + }); + } + } +} \ No newline at end of file diff --git a/RPGCoreCommon/DropTable/Editor/DropTableDrawer.cs.meta b/RPGCoreCommon/DropTable/Editor/DropTableDrawer.cs.meta new file mode 100644 index 0000000..c7c201a --- /dev/null +++ b/RPGCoreCommon/DropTable/Editor/DropTableDrawer.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 287610d3321e42ccb5dbad00b9b585e5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: + - _groupVisualTreeAsset: {fileID: 9197481963319205126, guid: 6d2d365fc9f0e0e4a93cee141a824492, type: 3} + - _rowVisualTreeAsset: {fileID: 9197481963319205126, guid: 0b23d9b3ec1017740933e19785b8964b, type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/RPGCoreCommon/DropTable/Editor/DropTableGroup.uss b/RPGCoreCommon/DropTable/Editor/DropTableGroup.uss new file mode 100644 index 0000000..f75934c --- /dev/null +++ b/RPGCoreCommon/DropTable/Editor/DropTableGroup.uss @@ -0,0 +1,85 @@ +#dt-config { + background-color: rgba(0, 0, 0, 0.39); + border-top-width: 0; + border-right-width: 0; + border-bottom-width: 0; + border-left-width: 0; +} + +#dt-config > * { + flex-grow: 0; + flex-shrink: 1; + -unity-text-align: middle-center; + margin-left: 1px; + margin-right: 1px; +} + +#dt-config > ToolbarSpacer { + flex-grow: 1; + flex-shrink: 0; +} + +#dt-config > #dt-add-row { + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; + border-left-color: rgb(26, 26, 26); + border-right-color: rgb(26, 26, 26); + border-top-color: rgb(26, 26, 26); + border-bottom-color: rgb(26, 26, 26); + -unity-text-align: middle-center; + font-size: 14px; + -unity-font-style: bold; +} + +#dt-config > #dt-chance-type { +} + +#dt-config > #dt-chance-type > VisualElement { + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + margin-left: 0; + padding-top: 0; + padding-right: 0; + padding-bottom: 0; + padding-left: 0; +} + +#dt-config > #dt-chance-type > VisualElement > TextElement { + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + margin-left: 0; + padding-right: 8px; + padding-left: 8px; +} + +#dt-list > ScrollView { + padding-bottom: 0; +} + +#unity-list-view__reorderable-item__container { + padding-left: 2px; + padding-right: 2px; + padding-bottom: 1px; + padding-top: 1px; +} + +#unity-list-view__reorderable-handle { + justify-content: center; + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + margin-left: 0; + padding-top: 0; + padding-right: 0; + padding-bottom: 0; + padding-left: 0; + display: none; +} diff --git a/RPGCoreCommon/DropTable/Editor/DropTableGroup.uss.meta b/RPGCoreCommon/DropTable/Editor/DropTableGroup.uss.meta new file mode 100644 index 0000000..ba6bfaa --- /dev/null +++ b/RPGCoreCommon/DropTable/Editor/DropTableGroup.uss.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f1b1bb265dde2264f9cb1caf449494f3 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 diff --git a/RPGCoreCommon/DropTable/Editor/DropTableGroup.uxml b/RPGCoreCommon/DropTable/Editor/DropTableGroup.uxml new file mode 100644 index 0000000..3f3cb20 --- /dev/null +++ b/RPGCoreCommon/DropTable/Editor/DropTableGroup.uxml @@ -0,0 +1,11 @@ + +