├── .gitattributes ├── .gitignore ├── CHANGELOG.md ├── CHANGELOG.md.meta ├── Documentation~ ├── Declaring a new Effect Type.md ├── Seting up a new Ability.md ├── images.meta └── images │ ├── Add abilities to entity.PNG │ ├── Create new Ability.png │ ├── EffectListOnAbility.png │ ├── EffectTypeDropDown.png │ ├── NewAbilityInspector.PNG │ └── NewEffectType.png ├── Editor.meta ├── Editor ├── AbilityUiLinkEditor.cs ├── AbilityUiLinkEditor.cs.meta ├── PropertyDrawers.meta ├── PropertyDrawers │ ├── AbilityUiLink.cs │ └── AbilityUiLink.cs.meta ├── Resources.meta ├── Resources │ ├── ScriptableAbilityEditor.uss │ ├── ScriptableAbilityEditor.uss.meta │ ├── ScriptableAbilityEditor.uxml │ └── ScriptableAbilityEditor.uxml.meta ├── ScriptTemplates.meta ├── ScriptTemplates │ ├── CostType.txt │ ├── CostType.txt.meta │ ├── EffectType.txt │ ├── EffectType.txt.meta │ ├── ScriptTemplates.cs │ └── ScriptTemplates.cs.meta ├── ScriptableAbilityEditor.cs ├── ScriptableAbilityEditor.cs.meta ├── WaynGames.Mgm.Ability.Editor.asmdef └── WaynGames.Mgm.Ability.Editor.asmdef.meta ├── LICENSE.md ├── LICENSE.md.meta ├── README.md ├── README.md.meta ├── Runtime.meta ├── Runtime ├── Scripts.meta ├── Scripts │ ├── AbilityHelper.cs │ ├── AbilityHelper.cs.meta │ ├── Authoring.meta │ ├── Authoring │ │ ├── AbilitiesMapIndex.cs │ │ ├── AbilitiesMapIndex.cs.meta │ │ ├── AbilityAuthoring.cs │ │ ├── AbilityAuthoring.cs.meta │ │ ├── AbilityUIRequiereUIBootstrapSystem.cs │ │ ├── AbilityUIRequiereUIBootstrapSystem.cs.meta │ │ ├── AbilityVFX.cs │ │ ├── AbilityVFX.cs.meta │ │ ├── PresentaionPrefab.cs │ │ ├── PresentaionPrefab.cs.meta │ │ ├── PresentaionPrefabInitSystem.cs │ │ ├── PresentaionPrefabInitSystem.cs.meta │ │ ├── RequiereUIBootstrap.cs │ │ ├── RequiereUIBootstrap.cs.meta │ │ ├── VFXControler.cs │ │ └── VFXControler.cs.meta │ ├── DataStructures.meta │ ├── DataStructures │ │ ├── Ability.cs │ │ ├── Ability.cs.meta │ │ ├── AbilityBuffer.cs │ │ ├── AbilityBuffer.cs.meta │ │ ├── AbilityCastResult.cs │ │ ├── AbilityCastResult.cs.meta │ │ ├── AbilityInput.cs │ │ ├── AbilityInput.cs.meta │ │ ├── AbilityState.cs │ │ ├── AbilityState.cs.meta │ │ ├── AbilityUiLink.cs │ │ ├── AbilityUiLink.cs.meta │ │ ├── EffectData.cs │ │ ├── EffectData.cs.meta │ │ ├── IEffect.cs │ │ ├── IEffect.cs.meta │ │ ├── IEffectBufferElement.cs │ │ ├── IEffectBufferElement.cs.meta │ │ ├── MultiMap.cs │ │ ├── MultiMap.cs.meta │ │ ├── NewTestCoponent.cs │ │ ├── NewTestCoponent.cs.meta │ │ ├── ScriptableAbility.cs │ │ ├── ScriptableAbility.cs.meta │ │ ├── Target.cs │ │ ├── Target.cs.meta │ │ ├── Timing.cs │ │ └── Timing.cs.meta │ ├── Systems.meta │ ├── Systems │ │ ├── AbilityCostCheckInitializationSystem.cs │ │ ├── AbilityCostCheckInitializationSystem.cs.meta │ │ ├── AbilityCostCheckerSystem.cs │ │ ├── AbilityCostCheckerSystem.cs.meta │ │ ├── AbilityCostConsumerSystem.cs │ │ ├── AbilityCostConsumerSystem.cs.meta │ │ ├── AbilityEffectConsumerSystems.cs │ │ ├── AbilityEffectConsumerSystems.cs.meta │ │ ├── AbilityEffectTriggerSystems.cs │ │ ├── AbilityEffectTriggerSystems.cs.meta │ │ ├── AbilitySystemGroup.cs │ │ ├── AbilitySystemGroup.cs.meta │ │ ├── AbilityTimingsCache.cs │ │ ├── AbilityTimingsCache.cs.meta │ │ ├── AbilityUpdateRangeSystem.cs │ │ ├── AbilityUpdateRangeSystem.cs.meta │ │ ├── AbilityUpdateStateAndTimingsSystem.cs │ │ ├── AbilityUpdateStateAndTimingsSystem.cs.meta │ │ ├── AddressableAbilityCatalogSystem.cs │ │ ├── AddressableAbilityCatalogSystem.cs.meta │ │ ├── CooldownRestrictionSystem.cs │ │ ├── CooldownRestrictionSystem.cs.meta │ │ ├── CurrentlyCasting.cs │ │ ├── CurrentlyCasting.cs.meta │ │ ├── ICacheComponent.cs │ │ ├── ICacheComponent.cs.meta │ │ ├── IEffectContext.cs │ │ ├── IEffectContext.cs.meta │ │ ├── IEffectContextWriter.cs │ │ ├── IEffectContextWriter.cs.meta │ │ ├── SquaredRangeCache.cs │ │ └── SquaredRangeCache.cs.meta │ ├── UI.meta │ ├── UI │ │ ├── AbilityBookUIElement.cs │ │ ├── AbilityBookUIElement.cs.meta │ │ ├── AbilityUIElement.cs │ │ ├── AbilityUIElement.cs.meta │ │ ├── AbilityUITooltip.cs │ │ ├── AbilityUITooltip.cs.meta │ │ ├── AbilityUiLink.asset │ │ ├── AbilityUiLink.asset.meta │ │ ├── AbilityUiPrefab.prefab │ │ ├── AbilityUiPrefab.prefab.meta │ │ ├── ActionSlot.cs │ │ ├── ActionSlot.cs.meta │ │ ├── CastBar.cs │ │ ├── CastBar.cs.meta │ │ ├── EntityOwnedUpdatableVisualElement.cs │ │ ├── EntityOwnedUpdatableVisualElement.cs.meta │ │ ├── PanelSettings.asset │ │ ├── PanelSettings.asset.meta │ │ ├── ProgressBar.cs │ │ ├── ProgressBar.cs.meta │ │ ├── Resources.meta │ │ ├── Resources │ │ │ ├── AbilityBar.uss │ │ │ ├── AbilityBar.uss.meta │ │ │ ├── AbilityBar.uxml │ │ │ ├── AbilityBar.uxml.meta │ │ │ ├── AbilityBookUIElement.uss │ │ │ ├── AbilityBookUIElement.uss.meta │ │ │ ├── AbilityBookUIElement.uxml │ │ │ ├── AbilityBookUIElement.uxml.meta │ │ │ ├── AbilityUIElement.uss │ │ │ ├── AbilityUIElement.uss.meta │ │ │ ├── AbilityUIElement.uxml │ │ │ ├── AbilityUIElement.uxml.meta │ │ │ ├── AbilityUiTooltip.uxml │ │ │ ├── AbilityUiTooltip.uxml.meta │ │ │ ├── ActionSlot.uxml │ │ │ ├── ActionSlot.uxml.meta │ │ │ ├── CastBar.uxml │ │ │ ├── CastBar.uxml.meta │ │ │ ├── ProgressBar.uxml │ │ │ └── ProgressBar.uxml.meta │ │ ├── UpdateUIManager.cs │ │ ├── UpdateUIManager.cs.meta │ │ ├── VisualElementDragger.cs │ │ └── VisualElementDragger.cs.meta │ ├── WaynGames.Mgm.Ability.Runtime.asmdef │ └── WaynGames.Mgm.Ability.Runtime.asmdef.meta ├── Systems.meta └── Systems │ ├── AbilityEffectConsumerSystems.cs │ └── AbilityEffectConsumerSystems.cs.meta ├── Tests.meta ├── Tests ├── Editor.meta ├── Editor │ ├── WaynGroup.Mgm.Ability.Editor.Tests.asmdef │ └── WaynGroup.Mgm.Ability.Editor.Tests.asmdef.meta ├── Runtime.meta └── Runtime │ ├── Performance.meta │ ├── WaynGroup.Mgm.Ability.Tests.asmdef │ └── WaynGroup.Mgm.Ability.Tests.asmdef.meta ├── Third Party Notices.md ├── Third Party Notices.md.meta ├── package.json └── package.json.meta /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This .gitignore file should be placed at the root of your Unity project directory 2 | # 3 | # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore 4 | # 5 | /[Ll]ibrary/ 6 | /[Tt]emp/ 7 | /[Oo]bj/ 8 | /[Bb]uild/ 9 | /[Bb]uilds/ 10 | /[Ll]ogs/ 11 | /[Mm]emoryCaptures/ 12 | 13 | # Never ignore Asset meta data 14 | !/[Aa]ssets/**/*.meta 15 | 16 | # Uncomment this line if you wish to ignore the asset store tools plugin 17 | # /[Aa]ssets/AssetStoreTools* 18 | 19 | # Autogenerated Jetbrains Rider plugin 20 | [Aa]ssets/Plugins/Editor/JetBrains* 21 | 22 | # Visual Studio cache directory 23 | .vs/ 24 | 25 | # Gradle cache directory 26 | .gradle/ 27 | 28 | # Autogenerated VS/MD/Consulo solution and project files 29 | ExportedObj/ 30 | .consulo/ 31 | *.csproj 32 | *.unityproj 33 | *.sln 34 | *.suo 35 | *.tmp 36 | *.user 37 | *.userprefs 38 | *.pidb 39 | *.booproj 40 | *.svd 41 | *.pdb 42 | *.mdb 43 | *.opendb 44 | *.VC.db 45 | 46 | # Unity3D generated meta files 47 | *.pidb.meta 48 | *.pdb.meta 49 | *.mdb.meta 50 | 51 | # Unity3D generated file on crash reports 52 | sysinfo.txt 53 | 54 | # Builds 55 | *.apk 56 | *.unitypackage 57 | 58 | # Crashlytics generated file 59 | crashlytics-build.properties 60 | 61 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this package will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) 5 | and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). 6 | 7 | ## [0.4.0] - Unreleased 8 | 9 | ### Informations 10 | 11 | - This version requires UNITY 2020.2.0a15 or higher, for the UI to work (in editor) 12 | - Bug have been reported to unity for the zero sized UI panel in 2020.1 and non working cutom UI Element in 2020.1 and 2020.2 alpha 13 | 14 | ### Added 15 | 16 | - Simple ability UI support (this feature is highly experimental and uses the unity runtime package for UI Elements (UI Toolkit)) it does not work in builds yet (see informations). 17 | 18 | ### Changed 19 | 20 | - Updated package dependency 21 | - **License** (see [LICENSE.md](./LICENSE.md)) 22 | 23 | ## [0.3.0] - 05/07/2020 24 | 25 | ### Added 26 | 27 | - Support for cost constraint and consumtion on skill 28 | - Support for simple target selection from skill (self or target) 29 | - System groups to organize systems update order 30 | 31 | ### Changed 32 | 33 | - ![](https://upload.wikimedia.org/wikipedia/commons/thumb/f/f6/OOjs_UI_icon_alert-destructive.svg/20px-OOjs_UI_icon_alert-destructive.svg.png) BREAKING CHANGE - Rename all occurences of "Skill" to "Ability" and "Skills" to "Abilities".![](https://upload.wikimedia.org/wikipedia/commons/thumb/f/f6/OOjs_UI_icon_alert-destructive.svg/20px-OOjs_UI_icon_alert-destructive.svg.png) 34 | - Trigger system won't do anything if it's consumer counter part won't run. This avoid creating the native stream, which in turn avoid any risk a memory leak so there is no need for the consumer to always update to do the clean up. 35 | 36 | ### Code Test Coverage 37 | 38 | - Started monitoring the code coverage of the package and switched to system behavior test strategy instead of a world test strategy. 39 | 40 | | Name | Covered | Uncovered | Coverable | Total | Line coverage | 41 | |------------------------------|---------|-----------|-----------|-------|---------------| 42 | | WaynGroup.Mgm.Ability | 233 | 72 | 305 | 951 | 76.3% | 43 | | WaynGroup.Mgm.Ability.Editor | 0 | 137 | 137 | 546 | 0% | 44 | 45 | 46 | - CRAP score is currenlty wrong, it show 2 false positive CRAP method. 47 | 48 | ## [0.2.0] - 09/06/2020 49 | 50 | ### Added 51 | 52 | - Support for Min and Max range constraint on skill 53 | 54 | ### Changed 55 | 56 | - Update to com.unity.entities 0.11.0-preview.7 (no impact) 57 | 58 | ## [0.1.2] - 08/06/2020 59 | 60 | ### Fixed 61 | 62 | - [#3 Possible memory leak](https://github.com/WAYNGROUP/MGM-Skill/issues/3) 63 | - [#4 Error with JobsDebugger enabled](https://github.com/WAYNGROUP/MGM-Skill/issues/4) 64 | - [#5 Trigger context entity description is a OR, should be an AND](https://github.com/WAYNGROUP/MGM-Skill/issues/5) 65 | 66 | 67 | ## [0.1.1] - 07/06/2020 68 | 69 | ### Fixed 70 | 71 | - [#1 unused loop variable](https://github.com/WAYNGROUP/MGM-Skill/pull/1) 72 | 73 | ## [0.1.0] - 31/05/2020 74 | 75 | ### This is the first release of *\*. 76 | 77 | This first realease provides a simple skill system that can be authored by Scriptable Object. 78 | For now, it allows the definition of single target skill that are subject to a cast time and cooldown time. 79 | Its allows to define any custom type of custom direct effect and comes with a Simple Skill sample that demontrate how to define a simple direct damage skill. 80 | -------------------------------------------------------------------------------- /CHANGELOG.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 69ccd5a71559bd143bbc1d378862e7d3 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Documentation~/Declaring a new Effect Type.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # Declaring a new Effect Type 5 | 6 | Note : The code snipet explained below are generated in a single file through the 'Create > MGM > Effect Type' menu. 7 | You only need to update the parts of the file where there is a '// YOUR CODE : ' comment. 8 | There should be no reason fo you to edit the generated code. (except for the NAMESPACE) 9 | 10 | ![Create > MGM > Effect Type](../Documentation~/images/NewEffectType.png) 11 | 12 | 13 | ## The effect declaration 14 | ```C# 15 | public struct NewEffect : IEffect 16 | { 17 | // YOUR CODE : delcare all necesasry data inherant to the effect consumption, could be a the effect power, damage type,... 18 | 19 | 20 | 21 | // Mandatory for Authoring, do not edit 22 | public void Convert(Entity entity, EntityManager dstManager, int skillIndex) 23 | { 24 | EffectUtility.AddEffect(entity, dstManager, skillIndex, this); 25 | } 26 | } 27 | ``` 28 | This struct contains all the data ncessary to define the skill. It may be the power of the skill, the type of damage it deals and so on. 29 | The "Convert" method is used by the converion system to register the effect in the appropriate buffer on the entity. 30 | This is delageted to the struct because it allow the conversion code to not be dependant on the type of effect it handles. 31 | 32 | 33 | ## The effect buffer 34 | ```C# 35 | // Mandatory for Authoring, do not edit 36 | public struct NewEffectBuffer : IEffectBufferElement 37 | { 38 | public int SkillIndex { get; set; } 39 | public NewEffect Effect { get; set; } 40 | } 41 | ``` 42 | To store all the effect that can be trigerred by an entity at runtime MGM Skill uses a dynamic buffer for each effect type. 43 | So when you declare a new effect, we need to declare the associated buffer to store the effects and the index of hte skill they belongs to. 44 | 45 | 46 | ## The effect context 47 | ```C# 48 | public struct NewEffectContext : IEffectContext 49 | { 50 | // YOUR CODE : delcare all necesasry contextual data for the effect consumption, could be a position, attack power,... 51 | 52 | // Mandatory for Authoring, do not edit 53 | public Entity Target { get; set; } 54 | public NewEffect Effect { get; set; } 55 | } 56 | ``` 57 | When trigerring an effect, the effect is written to a native stream allog with the targeted entity. 58 | The effect and target are the minimal parameters for any effect trigger. 59 | Additionnaly, you can add context data specific to the event type you are declaring. 60 | Generaly speaking this additional context it the data belonging to the caster and that affect the effect application like it's position or attack power. 61 | 62 | 63 | 64 | ## The trigger system 65 | ```C# 66 | [UpdateBefore(typeof(NewEffectConsumerSystem))] 67 | public class NewEffectTriggerSystem : EffectTriggerSystem 68 | { 69 | 70 | [BurstCompile] 71 | public struct TargetEffectWriter : IEffectContextWriter 72 | { 73 | // YOUR CODE : declare the public [ReadOnly] component data chunk accessor and the private [ReadOnly] native array to cache the component data 74 | 75 | /// 76 | /// Cache the component data array needed to write the effect context. 77 | /// 78 | /// 79 | public void PrepareChunk(ArchetypeChunk chunk) 80 | { 81 | // YOUR CODE : cache the component data array in a private [ReadOnly] field on the struct 82 | } 83 | 84 | /// 85 | /// Write the contextualized effect to it's corresponding consumer stream. 86 | /// 87 | /// The casting entity. 88 | /// The corresponding effect consumer stream. 89 | /// The effect to contextualize. 90 | public void WriteContextualizedEffect(int entityIndex, ref NativeStream.Writer consumerWriter, NewEffect effect, Entity target) 91 | { 92 | consumerWriter.Write(new NewEffectContext() { 93 | Target = target, 94 | Effect = effect 95 | // YOUR CODE : populate the effect context with additonal contextual data. 96 | }); 97 | } 98 | } 99 | 100 | 101 | protected override TargetEffectWriter GetContextWriter() 102 | { 103 | return new TargetEffectWriter() 104 | { 105 | // YOUR CODE : populate the component data chunk accessor 106 | }; 107 | } 108 | 109 | /* Optional 110 | protected override EntityQueryDesc GetEffectContextEntityQueryDesc() 111 | { 112 | return new EntityQueryDesc() 113 | { 114 | All = new ComponentType[] 115 | { 116 | // YOUR CODE : declare all required component type for populating the context of the effect. 117 | } 118 | }; 119 | } 120 | */ 121 | } 122 | ``` 123 | The trigger system is a class extending EffectTriggerSystem that is in charge of writing the trigerred effect and there context to the native stream. 124 | Your system's goal is to create and populate the effect context before writing it to the native stream. 125 | This is done though a struct implementing IEffectContextWriter. 126 | This iterface declare two method one for caching the component data array of the entity chunks (PrepareChunk), one to accualy write the context(WriteContextualizedEffect). 127 | The logic shared by all effect trigger system is handled by the base EffectTriggerSystem. 128 | It will take care of checking which skill are active, which target are affected and ensure the that the trigger job finishes before the consumer jib start. 129 | Then for each active skill and target it will call the WriteContextualizedEffect method. 130 | 131 | The necessary component data chunk accessor need to be declared when creating the writer struct. 132 | This is done in the GetContextWriter method. This method is called by the base class whenever the trigger job contained within it is scheduled. 133 | 134 | If you don't need additional context data for your effect, you have noting to change. 135 | If you need additional data, let's say the position, you need to declare the necessary component data on hte entity in the GetEffectContextEntityQueryDesc method. 136 | 137 | ## The consumer system 138 | ```C# 139 | [UpdateAfter(typeof(NewEffectTriggerSystem))] 140 | public class NewEffectConsumerSystem : EffectConsumerSystem 141 | { 142 | protected override void Consume() 143 | { 144 | NativeMultiHashMap effects = Effects; 145 | Entities.WithReadOnly(effects).ForEach((ref Entity targetEntity/* YOUR CODE : component on the target that are nedded to apply the effect*/) => 146 | { 147 | NativeMultiHashMap.Enumerator effectEnumerator = effects.GetValuesForKey(targetEntity); 148 | 149 | 150 | while (effectEnumerator.MoveNext()) 151 | { 152 | // YOUR CODE : Consume the effect 153 | } 154 | 155 | }).WithBurst() 156 | .ScheduleParallel(); 157 | } 158 | } 159 | ``` 160 | The consumer system is where you declare the actual impact of the effect on the targeted entity. 161 | For performance reason, you don't have access to the native stream you wrote to in the trigger system, you are instead provided with a nativemultihashmapp where the key is the targeted entity. 162 | That mapping is done by the base implementation of the EffectConsumerSystem. 163 | Your system need to iterated over all the entity that could potentially be affected by the effect (matching all component data necessary to aply the effect). 164 | Then for each iteration of the job, you check if the entity currently porcessed is targetd by the effect. If so you iterate and apply all the effect affecting this entity. 165 | 166 | -------------------------------------------------------------------------------- /Documentation~/Seting up a new Ability.md: -------------------------------------------------------------------------------- 1 | # Setting up a new Ability 2 | 3 | 4 | ## Creating the scriptable asset 5 | 6 | To create a new ability you need to create a new scriptable ability asset using the Create > MGM > Ability menu. 7 | 8 | ![Create > MGM > Ability](../Documentation~/images/Create%20new%20Ability.png) 9 | 10 | ## Authoring the ability 11 | 12 | By clicking on the scriptable ability asset you just created you should be able to see it's content in the inspector. 13 | 14 | ![Ability inspector](../Documentation~/images/NewAbilityInspector.PNG) 15 | 16 | You can edit the name of the ability, it's cooldown (time needed to recharge the ability) and it's cast time (time needed between the castign of the ability and it's activation). 17 | You will also see a list of all the effect type declared in your porject. 18 | 19 | ![Effect list](../Documentation~/images/EffectTypeDropDown.png) 20 | 21 | Selecting an effect in the list and clicking the 'Add' button will add it to the ability's effect. 22 | 23 | ![Effect on ability](../Documentation~/images/EffectListOnAbility.png) 24 | 25 | ## Add the ability to an entity 26 | 27 | On a game object in the hierary, add the Ability Auhtoring component and populate the list of ability with the scriptable ability assets. 28 | 29 | ![Ability on entity](../Documentation~/images/Add%20abilities%20to%20entity.PNG) 30 | 31 | 32 | # Known issue 33 | 34 | Removing or renaming an effect will cause an error in the deserialization porcess of the scriptable ability. 35 | To restore the scriptable ability asset you can edit the asset with a text editor and change / remove the concerned effect. 36 | 37 | -------------------------------------------------------------------------------- /Documentation~/images.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2a8f33eef0c10e8469c6fbc89ab6db7e 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Documentation~/images/Add abilities to entity.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaynGames/MGM-Ability/18e572f548f4a8579c86476391f3f16c93ac19e8/Documentation~/images/Add abilities to entity.PNG -------------------------------------------------------------------------------- /Documentation~/images/Create new Ability.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaynGames/MGM-Ability/18e572f548f4a8579c86476391f3f16c93ac19e8/Documentation~/images/Create new Ability.png -------------------------------------------------------------------------------- /Documentation~/images/EffectListOnAbility.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaynGames/MGM-Ability/18e572f548f4a8579c86476391f3f16c93ac19e8/Documentation~/images/EffectListOnAbility.png -------------------------------------------------------------------------------- /Documentation~/images/EffectTypeDropDown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaynGames/MGM-Ability/18e572f548f4a8579c86476391f3f16c93ac19e8/Documentation~/images/EffectTypeDropDown.png -------------------------------------------------------------------------------- /Documentation~/images/NewAbilityInspector.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaynGames/MGM-Ability/18e572f548f4a8579c86476391f3f16c93ac19e8/Documentation~/images/NewAbilityInspector.PNG -------------------------------------------------------------------------------- /Documentation~/images/NewEffectType.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaynGames/MGM-Ability/18e572f548f4a8579c86476391f3f16c93ac19e8/Documentation~/images/NewEffectType.png -------------------------------------------------------------------------------- /Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6cbd6af8d431b0640a52b84883bf645a 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/AbilityUiLinkEditor.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEditor.AddressableAssets; 3 | using UnityEditor.AddressableAssets.Settings; 4 | 5 | [CustomEditor(typeof(AbilityUiLink))] 6 | public class AbilityUiLinkEditor : Editor 7 | { 8 | #region Public Methods 9 | 10 | public void OnEnable() 11 | { 12 | RegisterAsAddressable((AbilityUiLink)target); 13 | } 14 | 15 | public void RegisterAsAddressable(AbilityUiLink uiLink) 16 | { 17 | string Guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(target)); 18 | 19 | if (string.IsNullOrEmpty(Guid)) return; 20 | 21 | AddressableAssetSettings settings = AddressableAssetSettingsDefaultObject.Settings; 22 | 23 | if (!settings.GetLabels().Contains(AbilityHelper.ADDRESSABLE_UiLink_LABEL)) 24 | { 25 | settings.AddLabel(AbilityHelper.ADDRESSABLE_UiLink_LABEL); 26 | } 27 | 28 | uint GuidHash = AbilityHelper.ComputeIdFromGuid(Guid); 29 | AddressableAssetEntry entry = settings.FindAssetEntry(Guid); 30 | 31 | if (entry != null) 32 | { 33 | if (GuidHash != uiLink.Id) 34 | { 35 | uiLink.Id = GuidHash; 36 | AssetDatabase.SaveAssets(); 37 | } 38 | return; 39 | } 40 | 41 | AddressableAssetGroup grp = settings.FindGroup("MGM-Abilities"); 42 | if (grp == null) 43 | { 44 | grp = settings.CreateGroup("MGM-Abilities", false, false, false, settings.DefaultGroup.Schemas); 45 | } 46 | 47 | entry = settings.CreateOrMoveEntry(Guid, grp); 48 | if (entry != null) 49 | { 50 | entry.labels.Add(AbilityHelper.ADDRESSABLE_UiLink_LABEL); 51 | entry.address = target.name; 52 | uiLink.Id = GuidHash; 53 | //You'll need these to run to save the changes! 54 | settings.SetDirty(AddressableAssetSettings.ModificationEvent.EntryMoved, entry, true); 55 | } 56 | AssetDatabase.SaveAssets(); 57 | } 58 | 59 | #endregion Public Methods 60 | } -------------------------------------------------------------------------------- /Editor/AbilityUiLinkEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 472b1746863c41942b46927bef467fcc 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/PropertyDrawers.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: abe4ec6530ccb2945b3f7f33d7209335 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/PropertyDrawers/AbilityUiLink.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | 3 | [CustomPropertyDrawer(typeof(AbilityUiLink), true)] 4 | public class AbilityUiLinkPropertyDrawer : ExtendedScriptableObjectDrawer 5 | { 6 | } -------------------------------------------------------------------------------- /Editor/PropertyDrawers/AbilityUiLink.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c84223ad354e2f94fba1a791c9c9a501 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Resources.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 206e2acec6633d042a1f8344ffb8535a 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Resources/ScriptableAbilityEditor.uss: -------------------------------------------------------------------------------- 1 | .header { 2 | -unity-font-style:bold 3 | } 4 | .container { 5 | -unity-font-style:normal 6 | } 7 | #id-property{ 8 | -unity-text-align: middle-right; 9 | font-size: 10px; 10 | color: rgba(143, 143, 143, 255); 11 | } -------------------------------------------------------------------------------- /Editor/Resources/ScriptableAbilityEditor.uss.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 57209550bcd7bd344a2906bc2bf24eb6 3 | ScriptedImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 2 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} 11 | disableValidation: 0 12 | -------------------------------------------------------------------------------- /Editor/Resources/ScriptableAbilityEditor.uxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Editor/Resources/ScriptableAbilityEditor.uxml.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f6ca2340770b2e0459be95e09a63041c 3 | ScriptedImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 2 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0} 11 | -------------------------------------------------------------------------------- /Editor/ScriptTemplates.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d8f207d7f9d8be647b563c993ad0bea9 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/ScriptTemplates/CostType.txt: -------------------------------------------------------------------------------- 1 | using Unity.Entities; 2 | 3 | using _NAMESPACE_; 4 | 5 | using WaynGroup.Mgm.Ability; 6 | 7 | [assembly: RegisterGenericJobType(typeof(AbilityCostCheckerSystem<#SCRIPTNAME#, _RESOURCE_, #SCRIPTNAME#Handler>.CostHandlerJob))] 8 | [assembly: RegisterGenericJobType(typeof(AbilityCostConsumerSystem<#SCRIPTNAME#, _RESOURCE_, #SCRIPTNAME#Handler>.CostHandlerJob))] 9 | 10 | namespace _NAMESPACE_ 11 | { 12 | public struct #SCRIPTNAME# : IAbilityCost 13 | { 14 | public float Cost; 15 | } 16 | 17 | public struct #SCRIPTNAME#Handler : ICostHandler<#SCRIPTNAME#, _RESOURCE_> 18 | { 19 | public void ConsumeCost(#SCRIPTNAME# cost, ref _RESOURCE_ resource) 20 | { 21 | resource.Value -= cost.Cost; 22 | } 23 | 24 | public bool HasEnougthResourceLeft(#SCRIPTNAME# cost, in _RESOURCE_ resource) 25 | { 26 | return resource.Value >= cost.Cost; 27 | } 28 | } 29 | 30 | public class #SCRIPTNAME#CheckerSystem : AbilityCostCheckerSystem<#SCRIPTNAME#, Mana, #SCRIPTNAME#Handler> 31 | { 32 | } 33 | public class #SCRIPTNAME#ConsumerSystem : AbilityCostConsumerSystem<#SCRIPTNAME#, Mana, #SCRIPTNAME#Handler> 34 | { 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Editor/ScriptTemplates/CostType.txt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9c16ccc220cc01743b0d811af20236c5 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor/ScriptTemplates/EffectType.txt: -------------------------------------------------------------------------------- 1 | using Unity.Collections; 2 | using Unity.Entities; 3 | using UnityEngine; 4 | 5 | using _NAMESPACE_; 6 | 7 | using WaynGroup.Mgm.Ability; 8 | 9 | // Mandatory for Burst to work 10 | [assembly: RegisterGenericJobType(typeof(AbilityEffectTriggerSystem<#SCRIPTNAME#, #SCRIPTNAME#ConsumerSystem, #SCRIPTNAME#TriggerSystem.EffectWriter,#SCRIPTNAME#Context>.TriggerJob))] 11 | 12 | 13 | namespace _NAMESPACE_ 14 | { 15 | public struct #SCRIPTNAME# : IEffect 16 | { 17 | [field: SerializeField] 18 | public TargetingMode Affects { get; set; } 19 | [field: SerializeField] 20 | public ActivationPhase Phase { get; set; } 21 | } 22 | 23 | public struct #SCRIPTNAME#Context : IEffectContext 24 | { 25 | } 26 | 27 | public class #SCRIPTNAME#TriggerSystem : AbilityEffectTriggerSystem<#SCRIPTNAME#, #SCRIPTNAME#ConsumerSystem, #SCRIPTNAME#TriggerSystem.EffectWriter, #SCRIPTNAME#Context> 28 | { 29 | public struct EffectWriter : IEffectContextWriter<#SCRIPTNAME#Context> 30 | { 31 | public void PrepareChunk(ArchetypeChunk chunk) 32 | { 33 | } 34 | 35 | public #SCRIPTNAME#Context BuildEffectContext(int entityIndex) 36 | { 37 | return default; 38 | } 39 | } 40 | 41 | } 42 | 43 | public class #SCRIPTNAME#ConsumerSystem : AbilityEffectConsumerSystem<#SCRIPTNAME#, #SCRIPTNAME#Context> 44 | { 45 | 46 | protected override void Consume() 47 | { 48 | NativeMultiHashMap effects = _effects; 49 | Entities.WithReadOnly(effects).ForEach((ref Entity targetEntity) => 50 | { 51 | if (effects.CountValuesForKey(targetEntity) <= 0) return; 52 | NativeMultiHashMap.Enumerator effectEnumerator = effects.GetValuesForKey(targetEntity); 53 | while (effectEnumerator.MoveNext()) 54 | { 55 | 56 | } 57 | }).WithBurst() 58 | .ScheduleParallel(); 59 | } 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /Editor/ScriptTemplates/EffectType.txt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2a8074b050a36b4498e7d35f6b765b24 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor/ScriptTemplates/ScriptTemplates.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using UnityEditor; 3 | using UnityEngine; 4 | 5 | namespace WaynGroup.Mgm.Ability 6 | { 7 | internal class ScriptTemplates 8 | { 9 | #region Public Fields 10 | 11 | public static string TemplatesRoot = UnityEditor.PackageManager.PackageInfo.FindForAssembly(Assembly.GetAssembly(typeof(ScriptTemplates))).resolvedPath; 12 | 13 | #endregion Public Fields 14 | 15 | #region Public Methods 16 | 17 | [MenuItem("Assets/Create/MGM/Effect Type")] 18 | public static void CreateAbilityEffectType() 19 | { 20 | ProjectWindowUtil.CreateScriptAssetFromTemplateFile( 21 | $"{TemplatesRoot}/Editor/ScriptTemplates/EffectType.txt", 22 | "NewEffect.cs"); 23 | } 24 | 25 | [MenuItem("Assets/Create/MGM/Cost Type")] 26 | public static void CreateAbilityCostType() 27 | { 28 | ProjectWindowUtil.CreateScriptAssetFromTemplateFile( 29 | $"{TemplatesRoot}/Editor/ScriptTemplates/CostType.txt", 30 | "NewCost.cs"); 31 | } 32 | 33 | #endregion Public Methods 34 | } 35 | } -------------------------------------------------------------------------------- /Editor/ScriptTemplates/ScriptTemplates.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7002d688226ceb34ba5a5ec26aec7c53 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/ScriptableAbilityEditor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | 6 | using UnityEditor; 7 | using UnityEditor.AddressableAssets; 8 | using UnityEditor.AddressableAssets.Settings; 9 | using UnityEditor.UIElements; 10 | 11 | using UnityEngine; 12 | using UnityEngine.UIElements; 13 | 14 | using WaynGroup.Mgm.Ability; 15 | 16 | [CustomEditor(typeof(ScriptableAbility))] 17 | public class ScriptableAbilityEditor : Editor 18 | { 19 | #region Private Fields 20 | 21 | private readonly string[] _costStirngParams = new string[] { "costs-container", "Undefined ability cost type on {0} cost.", "Undefined ability cost type to remove" }; 22 | private readonly string[] _effectStirngParams = new string[] { "effects-container", "Undefined ability effect type on {0} effect.", "Undefined effect type to remove" }; 23 | private VisualElement root; 24 | 25 | private List EffectTypes; 26 | private List CostTypes; 27 | 28 | private PopupField effectDropDown; 29 | 30 | private PopupField costDropDown; 31 | 32 | private Type SelectedEffectType; 33 | 34 | private Type SelectedCostType; 35 | 36 | private SerializedProperty EffectsProperty; 37 | 38 | private SerializedProperty CostsProperty; 39 | 40 | #endregion Private Fields 41 | 42 | #region Public Methods 43 | 44 | 45 | public override VisualElement CreateInspectorGUI() 46 | { 47 | Initialization(); 48 | 49 | Cache(); 50 | 51 | LoadBaseLayout(); 52 | MakeCostTypePicker(); 53 | 54 | MakeEffectTypePicker(); 55 | 56 | Display(EffectsProperty, EffectTypes, _effectStirngParams); 57 | Display(CostsProperty, CostTypes, _costStirngParams); 58 | 59 | finishedDefaultHeaderGUI += SaveAsset; 60 | return root; 61 | } 62 | 63 | private void SaveAsset(Editor obj) 64 | { 65 | AssetDatabase.SaveAssetIfDirty(target); 66 | } 67 | 68 | public void RegisterAsAddressable(ScriptableAbility ability) 69 | { 70 | string Guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(target)); 71 | 72 | if (string.IsNullOrEmpty(Guid)) return; 73 | 74 | AddressableAssetSettings settings = AddressableAssetSettingsDefaultObject.Settings; 75 | 76 | if (!settings.GetLabels().Contains(AbilityHelper.ADDRESSABLE_ABILITY_LABEL)) 77 | { 78 | settings.AddLabel(AbilityHelper.ADDRESSABLE_ABILITY_LABEL); 79 | } 80 | 81 | uint GuidHash = AbilityHelper.ComputeIdFromGuid(Guid); 82 | AddressableAssetEntry entry = settings.FindAssetEntry(Guid); 83 | 84 | if (entry != null) 85 | { 86 | if (GuidHash != ability.Id) 87 | { 88 | ability.Id = GuidHash; 89 | } 90 | return; 91 | } 92 | 93 | AddressableAssetGroup grp = settings.FindGroup("MGM-Abilities"); 94 | if (grp == null) 95 | { 96 | grp = settings.CreateGroup("MGM-Abilities", false, false, false, settings.DefaultGroup.Schemas); 97 | } 98 | 99 | entry = settings.CreateOrMoveEntry(Guid, grp); 100 | if (entry != null) 101 | { 102 | entry.labels.Add(AbilityHelper.ADDRESSABLE_ABILITY_LABEL); 103 | entry.address = ability.name; 104 | ability.Id = GuidHash; 105 | //You'll need these to run to save the changes! 106 | settings.SetDirty(AddressableAssetSettings.ModificationEvent.EntryMoved, entry, true); 107 | } 108 | } 109 | 110 | // This method allow to dynamicaly override the preview icon bath in hte inspector window and the project view to the ability ingame icon. 111 | // In the porject window, if the view is to small it will default to the unity scriptable object icon. 112 | // If the ability in game icon is not set, it will default to the unity scriptable object icon. 113 | public override Texture2D RenderStaticPreview(string assetPath, UnityEngine.Object[] subAssets, int width, int height) 114 | { 115 | ScriptableAbility ability = (ScriptableAbility)target; 116 | 117 | if (ability == null || ability.Icon == null) 118 | return null; 119 | 120 | Texture2D tex = new Texture2D(width, height); 121 | EditorUtility.CopySerialized(ability.Icon, tex); 122 | 123 | return tex; 124 | } 125 | 126 | #endregion Public Methods 127 | 128 | #region Private Methods 129 | 130 | private void Initialization() 131 | { 132 | ScriptableAbility ability = (ScriptableAbility)target; 133 | Undo.RecordObject(ability, "Ability Change"); 134 | RegisterAsAddressable(ability); 135 | } 136 | 137 | private void Cache() 138 | { 139 | EffectsProperty = serializedObject.FindProperty("Effects"); 140 | var types = TypeCache.GetTypesDerivedFrom().ToList(); 141 | types.Remove(typeof(SpawnEffect)); 142 | EffectTypes = types; 143 | 144 | CostsProperty = serializedObject.FindProperty("Costs"); 145 | 146 | 147 | CostTypes = TypeCache.GetTypesDerivedFrom().ToList(); 148 | } 149 | 150 | private void LoadBaseLayout() 151 | { 152 | root = new VisualElement(); 153 | // Import UXML 154 | VisualTreeAsset visualTree = Resources.Load("ScriptableAbilityEditor"); 155 | TemplateContainer uxmlVe = visualTree.CloneTree(); 156 | root.Add(uxmlVe.contentContainer); 157 | root.Bind(serializedObject); 158 | 159 | // A stylesheet can be added to a VisualElement. 160 | // The style will be applied to the VisualElement and all of its children. 161 | StyleSheet styleSheet = Resources.Load("ScriptableAbilityEditor"); 162 | root.styleSheets.Add(styleSheet); 163 | } 164 | 165 | private void MakeEffectTypePicker() 166 | { 167 | VisualElement effectPickerContainer = root.Query("effect-picker-container").First(); 168 | if (EffectTypes.Count == 0) 169 | { 170 | effectPickerContainer.Add(new HelpBox("Your project does not define any effect types.", HelpBoxMessageType.Warning)); 171 | return; 172 | } 173 | effectDropDown = new PopupField("Effect Type", EffectTypes, 0, (Type t) => t.Name, (Type t) => t.Name); 174 | SelectedEffectType = effectDropDown.value; 175 | effectDropDown.RegisterValueChangedCallback(ChangeSelectedEffectType); 176 | Button addbuton = new Button(() => Add(EffectsProperty, EffectTypes, _effectStirngParams, SelectedEffectType)) 177 | { 178 | text = "Add" 179 | }; 180 | effectDropDown.Add(addbuton); 181 | effectPickerContainer.Add(effectDropDown); 182 | } 183 | 184 | private void MakeCostTypePicker() 185 | { 186 | VisualElement costPickerContainer = root.Query("cost-picker-container").First(); 187 | if (CostTypes.Count == 0) 188 | { 189 | costPickerContainer.Add(new HelpBox("Your project does not define any cost types.", HelpBoxMessageType.Warning)); 190 | return; 191 | } 192 | 193 | costDropDown = new PopupField("Cost Type", CostTypes, 0, (Type t) => t.Name, (Type t) => t.Name); 194 | SelectedCostType = costDropDown.value; 195 | costDropDown.RegisterValueChangedCallback(ChangeSelectedCostType); 196 | Button addbuton = new Button(() => Add(CostsProperty, CostTypes, _costStirngParams, SelectedCostType)) 197 | { 198 | text = "Add" 199 | }; 200 | costDropDown.Add(addbuton); 201 | costPickerContainer.Add(costDropDown); 202 | } 203 | 204 | private void ChangeSelectedCostType(ChangeEvent evt) 205 | { 206 | SelectedCostType = evt.newValue; 207 | } 208 | 209 | private void ChangeSelectedEffectType(ChangeEvent evt) 210 | { 211 | SelectedEffectType = evt.newValue; 212 | } 213 | 214 | private void Add(SerializedProperty listProperty, List types, string[] stringParams, Type selectedType) 215 | { 216 | serializedObject.Update(); 217 | listProperty.arraySize++; 218 | serializedObject.ApplyModifiedProperties(); 219 | serializedObject.Update(); 220 | listProperty.GetArrayElementAtIndex(listProperty.arraySize - 1).managedReferenceValue = Activator.CreateInstance(selectedType); 221 | serializedObject.ApplyModifiedProperties(); 222 | Display(listProperty, types, stringParams); 223 | } 224 | 225 | private void Display(SerializedProperty listPorperty, List types, string[] paramStrings) 226 | { 227 | VisualElement container = root.Query(paramStrings[0]).First(); 228 | container.Clear(); 229 | 230 | for (int i = 0; i < listPorperty.arraySize; ++i) 231 | { 232 | int index = i; 233 | SerializedProperty sp = listPorperty.GetArrayElementAtIndex(index); 234 | Type type = types.Where(t => $"{t.Assembly.GetName().Name} {t.FullName}".Equals(sp.managedReferenceFullTypename)).FirstOrDefault(); 235 | if (type == null) 236 | { 237 | Debug.LogWarning(string.Format(paramStrings[1], serializedObject.targetObject.name)); 238 | container.Add(new Button(() => { Remove(index, listPorperty, types, paramStrings); }) 239 | { 240 | text = paramStrings[2] 241 | }); 242 | } 243 | else 244 | { 245 | VisualElement ve = new VisualElement(); 246 | VisualElement foldout = BuildGenericElement(type, sp); 247 | ve.style.flexDirection = FlexDirection.Row; 248 | foldout.style.flexGrow = 1; 249 | ve.Add(foldout); 250 | Button b = new Button(() => { Remove(index, listPorperty, types, paramStrings); }) 251 | { 252 | text = "-" 253 | }; 254 | b.style.height = 12; 255 | ve.Add(b); 256 | container.Add(ve); 257 | } 258 | } 259 | } 260 | 261 | private VisualElement BuildGenericElement(Type type, SerializedProperty sp) 262 | { 263 | Foldout foldout = new Foldout() 264 | { 265 | text = type.Name 266 | }; 267 | foreach (PropertyInfo property in type.GetProperties().Where(p => p.DeclaringType.Equals(type))) 268 | { 269 | SerializedProperty local_sp = sp.FindPropertyRelative($"<{property.Name}>k__BackingField"); 270 | Debug.Log($"{sp.name}.<{property.Name}>k__BackingField was found{local_sp != null}"); 271 | if (local_sp == null) continue; 272 | PropertyField propField = new PropertyField(local_sp, property.Name) 273 | { 274 | bindingPath = local_sp.propertyPath 275 | }; 276 | propField.Bind(serializedObject); 277 | foldout.Add(propField); 278 | } 279 | foreach (FieldInfo property in type.GetFields().Where(p => p.DeclaringType.Equals(type))) 280 | { 281 | SerializedProperty local_sp = sp.FindPropertyRelative(property.Name); 282 | if (local_sp == null) continue; 283 | PropertyField propField = new PropertyField(local_sp) 284 | { 285 | bindingPath = local_sp.propertyPath 286 | }; 287 | propField.Bind(serializedObject); 288 | foldout.Add(propField); 289 | } 290 | return foldout; 291 | } 292 | 293 | private void Remove(int index, SerializedProperty listPorperty, List types, string[] paramStrings) 294 | { 295 | serializedObject.Update(); 296 | listPorperty.DeleteArrayElementAtIndex(index); 297 | serializedObject.ApplyModifiedPropertiesWithoutUndo(); 298 | Display(listPorperty, types, paramStrings); 299 | } 300 | 301 | #endregion Private Methods 302 | } -------------------------------------------------------------------------------- /Editor/ScriptableAbilityEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6482d947ece0daa41875de5916d05554 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/WaynGames.Mgm.Ability.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "WaynGames.Mgm.Ability.Editor", 3 | "rootNamespace": "", 4 | "references": [ 5 | "GUID:734d92eba21c94caba915361bd5ac177", 6 | "GUID:69448af7b92c7f342b298e06a37122aa", 7 | "GUID:9e24947de15b9834991c9d8411ea37cf", 8 | "GUID:eec0964c48f6f4e40bc3ec2257ccf8c5", 9 | "GUID:709f50f6df67d954dacc4b3c142ab558", 10 | "GUID:6844ddcdb94ee44488ef59a17960fc59" 11 | ], 12 | "includePlatforms": [ 13 | "Editor" 14 | ], 15 | "excludePlatforms": [], 16 | "allowUnsafeCode": false, 17 | "overrideReferences": false, 18 | "precompiledReferences": [], 19 | "autoReferenced": true, 20 | "defineConstraints": [], 21 | "versionDefines": [], 22 | "noEngineReferences": false 23 | } -------------------------------------------------------------------------------- /Editor/WaynGames.Mgm.Ability.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fcd7030d9c087774d9fb2a75d920dc1a 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Licensed under the Unity Companion License for Unity-dependent projects--see [Unity Companion License](https://unity3d.com/legal/licenses/Unity_Companion_License). 2 | 3 | Unless expressly provided otherwise, the Software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. Please review the license for details on these and other terms and conditions. 4 | -------------------------------------------------------------------------------- /LICENSE.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a039930789b8dee4b9ae83db7381704a 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/M4M8UEQP8) 2 | 3 | 4 | This package contains a performant and disigner friendly skill system. 5 | It allows the definition of custom effects that can be composed to form any kind of skill. 6 | 7 | ## Key features are : 8 | - Custom effects with prefifined template to minimize typing 9 | - ScriptableObject base skill composition 10 | - Skill support cooldown and cast time 11 | - Skill range cosntraint 12 | - Skill ressource constraint 13 | 14 | ## Next features on the list : 15 | 16 | - Support for over time skill 17 | - Support for area of effect skill 18 | - More samples (hopefully with VFX and sounds at some point) 19 | 20 | ## Documentation 21 | [Seting up a new Ability](./Documentation~/Seting%20up%20a%20new%20Ability.md) 22 | 23 | [Declaring a new Effect Type](./Documentation~/Declaring%20a%20new%20Effect%20Type.md) 24 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7db2b2476442e3c418b44432a569855d 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9b8c6e281f6bdce468eb21833a34c92b 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 28753ca96dacc2b4a8329d8a961e653f 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Scripts/AbilityHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | using Unity.Entities; 5 | 6 | using WaynGroup.Mgm.Ability; 7 | 8 | public static class AbilityHelper 9 | { 10 | #region Public Fields 11 | 12 | public const string ADDRESSABLE_ABILITY_LABEL = "Ability"; 13 | public const string ADDRESSABLE_UiLink_LABEL = "UiLink"; 14 | 15 | #endregion Public Fields 16 | 17 | #region Public Methods 18 | 19 | public static uint ComputeIdFromGuid(string Guid) 20 | { 21 | return BitConverter.ToUInt32(Encoding.ASCII.GetBytes(Guid), 0); 22 | } 23 | 24 | #endregion Public Methods 25 | } -------------------------------------------------------------------------------- /Runtime/Scripts/AbilityHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e30a4fe90ed22cc4f8e401eb44be83fe 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Authoring.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7bac99ffe16dab24cb27d96c953f9268 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Scripts/Authoring/AbilitiesMapIndex.cs: -------------------------------------------------------------------------------- 1 | using Unity.Entities; 2 | 3 | public struct AbilitiesMapIndex : IComponentData 4 | { 5 | #region Public Fields 6 | 7 | public BlobAssetReference> guidToIndex; 8 | public BlobAssetReference> indexToGuid; 9 | 10 | #endregion Public Fields 11 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Authoring/AbilitiesMapIndex.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: db1f053c79769be41a4ce3b9cab7f8b1 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Authoring/AbilityAuthoring.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Unity.Collections; 4 | using Unity.Entities; 5 | using Unity.Transforms; 6 | using UnityEditor; 7 | using UnityEngine; 8 | using UnityEngine.AddressableAssets; 9 | using WaynGroup.Mgm.Ability; 10 | 11 | [DisallowMultipleComponent] 12 | public partial class AbilityAuthoring : MonoBehaviour, IConvertGameObjectToEntity,IDeclareReferencedPrefabs 13 | { 14 | #region Public Fields 15 | 16 | [Tooltip("List of Scriptable Ability addressable asset reference.")] 17 | public List Abilities; 18 | 19 | [Tooltip("Optional : Data bout the UI that control this entity.")] 20 | public AbilityUiLink AbilityUiLink; 21 | 22 | public GameObject PresentationPrefab; 23 | 24 | private Dictionary Spawnables; 25 | 26 | private List orederedList; 27 | 28 | #endregion Public Fields 29 | 30 | #region Public Methods 31 | 32 | public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem) 33 | { 34 | // Ordering abilities to generate the same blobasset for the same set of ability whatever 35 | // the authoring order. Can't sort the array in place or it will affect the authoring order. 36 | 37 | 38 | foreach (var spawnable in Spawnables.Keys) 39 | { 40 | var e = conversionSystem.GetPrimaryEntity(spawnable); 41 | dstManager.AddComponentData(e, new AddressablePrefab() 42 | { 43 | key = Spawnables[spawnable] 44 | }); 45 | } 46 | 47 | // Whatever the authoring order if 2 entities have the same set of abilities, ordering them 48 | // makes sure that we won't duplciate the blobasset refrence and that both entites will have 49 | // the same index for the same abilities. 50 | dstManager.AddComponentData(entity, CreateAbilitiesBlobMap(conversionSystem, orederedList)); 51 | 52 | 53 | LinkUI(entity, dstManager, conversionSystem); 54 | dstManager.AddComponentData(entity, new PresentaionPrefab() { prefab = PresentationPrefab }); 55 | } 56 | 57 | public void DeclareReferencedPrefabs(List referencedPrefabs) 58 | { 59 | 60 | Spawnables = new Dictionary(); 61 | orederedList = Abilities.OrderBy(item => item.Id).ToList(); 62 | 63 | foreach (var ab in orederedList) 64 | { 65 | foreach(var sp in ab.Effects) 66 | { 67 | if (typeof(SpawnableData).Equals(sp.GetType())) 68 | { 69 | var assetKey = AbilityHelper.ComputeIdFromGuid(((SpawnableData)sp).PrefabRef.AssetGUID); 70 | var asset = ((SpawnableData)sp).PrefabRef.editorAsset; 71 | 72 | Debug.LogWarning($"Assigning {assetKey} for {asset.name} "); 73 | if (asset != null) { 74 | Spawnables.Add(asset, assetKey); 75 | } 76 | } 77 | } 78 | } 79 | referencedPrefabs.AddRange(Spawnables.Keys); 80 | 81 | } 82 | 83 | 84 | #endregion Public Methods 85 | 86 | #region Private Methods 87 | 88 | /// 89 | /// Create a Blob Map of abilities to easily reference the index of an ability in a buffer from 90 | /// it's guid. 91 | /// 92 | /// Used to ensure blob unicity and asset dependancy. 93 | /// A component containg the blob map asset reference. 94 | private AbilitiesMapIndex CreateAbilitiesBlobMap(GameObjectConversionSystem conversionSystem, List orederedList) 95 | { 96 | AbilitiesMapIndex AbilitiesMapIndex = new AbilitiesMapIndex(); 97 | 98 | 99 | 100 | using (BlobBuilder bb = new BlobBuilder(Allocator.Temp)) 101 | { 102 | var guidIndexMapBuilder = new BlobHashMapBuilder(bb); 103 | for (int i = 0; i < orederedList.Count; i++) 104 | { 105 | guidIndexMapBuilder.Add(orederedList[i].Id, i); 106 | #if UNITY_EDITOR 107 | // Declares a dependancy on hte ability asset so that if it is changed, the entity 108 | // will be reconverted to take the changed int account both in subscenes and play mode. 109 | conversionSystem.DeclareAssetDependency(gameObject, Abilities[i]); 110 | 111 | #endif 112 | } 113 | BlobAssetReference> guidToIndex = guidIndexMapBuilder.CreateBlobAssetReference(Allocator.Persistent); 114 | conversionSystem.BlobAssetStore.AddUniqueBlobAsset(ref guidToIndex); 115 | AbilitiesMapIndex.guidToIndex = guidToIndex; 116 | } 117 | 118 | using (BlobBuilder bb = new BlobBuilder(Allocator.Temp)) 119 | { 120 | var indexToGuidMapBuilder = new BlobHashMapBuilder(bb); 121 | for (int i = 0; i < orederedList.Count; i++) 122 | { 123 | indexToGuidMapBuilder.Add(i, orederedList[i].Id); 124 | } 125 | BlobAssetReference> indexToGuid = indexToGuidMapBuilder.CreateBlobAssetReference(Allocator.Persistent); 126 | 127 | conversionSystem.BlobAssetStore.AddUniqueBlobAsset(ref indexToGuid); 128 | AbilitiesMapIndex.indexToGuid = indexToGuid; 129 | } 130 | 131 | return AbilitiesMapIndex; 132 | } 133 | 134 | /// 135 | /// Add a reference to the UI associated with thi entity. 136 | /// 137 | /// 138 | /// 139 | /// Used to ensure asset dependancy. 140 | private void LinkUI(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem) 141 | { 142 | if (AbilityUiLink != null) 143 | { 144 | #if UNITY_EDITOR 145 | conversionSystem.DeclareAssetDependency(gameObject, AbilityUiLink); 146 | #endif 147 | dstManager.AddComponentData(entity, new RequiereUIBootstrap() 148 | { 149 | uiAssetGuid = AbilityUiLink.Id 150 | }); 151 | } 152 | } 153 | 154 | #endregion Private Methods 155 | } 156 | 157 | public struct AddressablePrefab : IComponentData 158 | { 159 | public uint key; 160 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Authoring/AbilityAuthoring.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2b57754c26436134496339728b43cb2b 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Authoring/AbilityUIRequiereUIBootstrapSystem.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Unity.Collections; 3 | using Unity.Entities; 4 | 5 | using UnityEngine; 6 | using UnityEngine.AddressableAssets; 7 | using UnityEngine.UIElements; 8 | 9 | using WaynGroup.Mgm.Ability; 10 | using WaynGroup.Mgm.Ability.UI; 11 | 12 | [UpdateInGroup(typeof(InitializationSystemGroup))] 13 | [UpdateAfter(typeof(AddressableAbilityCatalogSystem))] 14 | public struct AbilitiesInitializationSystem : ISystem 15 | { 16 | #region Private Fields 17 | 18 | private EntityQuery _newEntityWithAbilities; 19 | private EntityQuery _cache; 20 | 21 | #endregion Private Fields 22 | 23 | #region Public Methods 24 | 25 | public void OnCreate(ref SystemState state) 26 | { 27 | _newEntityWithAbilities = state.EntityManager.CreateEntityQuery(new EntityQueryDesc() 28 | { 29 | All = new ComponentType[] { ComponentType.ReadOnly() }, 30 | None = new ComponentType[] { ComponentType.ReadOnly() } 31 | }); 32 | _cache = state.GetEntityQuery(ComponentType.ReadOnly(typeof(AbilityTimingsCache))); 33 | state.RequireSingletonForUpdate(); 34 | } 35 | 36 | public void OnDestroy(ref SystemState state) 37 | { 38 | } 39 | 40 | public void OnUpdate(ref SystemState state) 41 | { 42 | EntityCommandBuffer ecb = state.World.GetOrCreateSystem().CreateCommandBuffer(); 43 | AbilityTimingsCache cache = _cache.GetSingleton(); 44 | 45 | state.Dependency = new InitializeAbilityCooldownJob() 46 | { 47 | Cache = cache.Cache, 48 | AbilityMapChunk = state.GetComponentTypeHandle(true), 49 | EntityChunk = state.GetEntityTypeHandle(), 50 | Ecb = ecb.AsParallelWriter() 51 | }.ScheduleSingle(_newEntityWithAbilities, state.Dependency); 52 | state.World.GetOrCreateSystem().AddJobHandleForProducer(state.Dependency); 53 | } 54 | 55 | #endregion Public Methods 56 | 57 | #region Public Structs 58 | 59 | public struct InitializeAbilityCooldownJob : IJobChunk 60 | { 61 | #region Public Fields 62 | 63 | [ReadOnly] public BlobAssetReference> Cache; 64 | [ReadOnly] public ComponentTypeHandle AbilityMapChunk; 65 | [ReadOnly] public EntityTypeHandle EntityChunk; 66 | 67 | public EntityCommandBuffer.ParallelWriter Ecb; 68 | 69 | #endregion Public Fields 70 | 71 | #region Public Methods 72 | 73 | public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) 74 | { 75 | NativeArray inputArray = chunk.GetNativeArray(AbilityMapChunk); 76 | NativeArray entitiesArray = chunk.GetNativeArray(EntityChunk); 77 | 78 | ref var cacheMap = ref Cache.Value; 79 | 80 | for (int entityIndex = 0; entityIndex < chunk.Count; ++entityIndex) 81 | { 82 | AbilitiesMapIndex entityAbilities = inputArray[entityIndex]; 83 | ref BlobMultiHashMap indexToGuid = ref entityAbilities.indexToGuid.Value; 84 | 85 | int abilityCount = indexToGuid.ValueCount.Value; 86 | 87 | NativeArray abilityBuffer = new NativeArray(abilityCount, Allocator.Temp); 88 | for (int i = 0; i < abilityCount; i++) 89 | { 90 | abilityBuffer[i] = new AbilityCooldownBufferElement() 91 | { 92 | CooldownTime = cacheMap.GetValuesForKey(indexToGuid.GetValuesForKey(i)[0])[0].CoolDown 93 | }; 94 | } 95 | 96 | DynamicBuffer buffer = Ecb.AddBuffer(entityIndex, entitiesArray[entityIndex]); 97 | buffer.AddRange(abilityBuffer); 98 | 99 | Ecb.AddComponent(entityIndex, entitiesArray[entityIndex], new CurrentlyCasting() { castTime = float.NaN }); 100 | if (indexToGuid.ValueCount.Value > 0) 101 | Ecb.AddComponent(entityIndex, entitiesArray[entityIndex], new AbilityInput(indexToGuid.GetValuesForKey(0)[0])); 102 | } 103 | } 104 | 105 | #endregion Public Methods 106 | } 107 | 108 | #endregion Public Structs 109 | } 110 | 111 | internal partial class AbilityUIRequiereUIBootstrapSystem : SystemBase 112 | { 113 | #region Private Fields 114 | 115 | private Dictionary uiMap; 116 | 117 | private UIDocument uiDoc; 118 | 119 | #endregion Private Fields 120 | 121 | #region Public Methods 122 | 123 | public void LinkUiToEntity() 124 | { 125 | Addressables.LoadAssetsAsync(new AssetLabelReference() 126 | { 127 | labelString = AbilityHelper.ADDRESSABLE_UiLink_LABEL 128 | }, null, false).Completed += objects => 129 | { 130 | if (objects.Result == null) return; 131 | uiMap = new Dictionary(); 132 | foreach (AbilityUiLink uiLink in objects.Result) 133 | { 134 | uiMap.Add(uiLink.Id, uiLink); 135 | } 136 | 137 | Enabled = true; 138 | }; ; 139 | } 140 | 141 | #endregion Public Methods 142 | 143 | #region Protected Methods 144 | 145 | protected override void OnCreate() 146 | { 147 | base.OnCreate(); 148 | Enabled = false; 149 | EntityManager.World.GetOrCreateSystem().OnAbilityUpdate += BootstrapUi; 150 | var uiDocs = Object.FindObjectsOfType(); 151 | if (uiDocs != null && uiDocs.Length > 0) 152 | { 153 | uiDoc = Object.FindObjectsOfType()[0]; 154 | } 155 | } 156 | 157 | protected override void OnUpdate() 158 | { 159 | Entities.WithStructuralChanges().ForEach((Entity entity, ref RequiereUIBootstrap boostrap) => 160 | { 161 | //Debug.Log($"Boostrapping entity UI {entity.Index}:{entity.Version}"); 162 | 163 | if (uiMap.TryGetValue(boostrap.uiAssetGuid, out var link)) 164 | { 165 | if (uiDoc != null) 166 | { 167 | //Debug.Log($"Instantiated UI Document"); 168 | uiDoc.panelSettings = link.PanelSettings; 169 | uiDoc.visualTreeAsset = link.UxmlUi; 170 | uiDoc.sortingOrder = link.SortingOrder; 171 | AbilityBookUIElement book = uiDoc.rootVisualElement.Q(); 172 | if (book != null) book.Populate(entity, EntityManager); 173 | //Debug.Log($"Found Ability Book"); 174 | CastBar CastBar = uiDoc.rootVisualElement.Q(); 175 | if (CastBar != null) CastBar.SetOwnership(entity, EntityManager); 176 | //Debug.Log($"Found Cast Bar"); 177 | uiDoc.enabled = true; 178 | } 179 | } 180 | EntityManager.RemoveComponent(entity); 181 | }).WithoutBurst().Run(); 182 | } 183 | 184 | #endregion Protected Methods 185 | 186 | #region Private Methods 187 | 188 | private void BootstrapUi(Dictionary abilityCatalogue) 189 | { 190 | LinkUiToEntity(); 191 | } 192 | 193 | #endregion Private Methods 194 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Authoring/AbilityUIRequiereUIBootstrapSystem.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1661f9372f195dc4a928cfab1182b854 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Authoring/AbilityVFX.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using UnityEngine; 4 | 5 | [Serializable] 6 | public struct AbilityVFX 7 | { 8 | 9 | public GameObject VfxPrefab; 10 | public GameObject VfxParent; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /Runtime/Scripts/Authoring/AbilityVFX.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 37e932146a27b3744a6ef6081ab087dc 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Authoring/PresentaionPrefab.cs: -------------------------------------------------------------------------------- 1 | using Unity.Entities; 2 | using UnityEngine; 3 | 4 | public class PresentaionPrefab : IComponentData 5 | { 6 | #region Public Fields 7 | 8 | public GameObject prefab; 9 | 10 | #endregion Public Fields 11 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Authoring/PresentaionPrefab.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ad6ce7c37b0a41d4ab844b61751a66e4 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Authoring/PresentaionPrefabInitSystem.cs: -------------------------------------------------------------------------------- 1 | using Unity.Entities; 2 | using UnityEngine; 3 | using Unity.Transforms; 4 | using Unity.Mathematics; 5 | 6 | public partial class PresentaionPrefabInitSystem : SystemBase 7 | { 8 | #region Protected Methods 9 | private class GameObjEntity : ISystemStateComponentData 10 | { 11 | public GameObject go; 12 | } 13 | protected override void OnUpdate() 14 | { 15 | Entities.WithStructuralChanges().WithoutBurst().ForEach((Entity entity, PresentaionPrefab prefab) => 16 | { 17 | GameObject Prefab = GameObject.Instantiate(prefab.prefab); 18 | 19 | // link GO and Enitty to make them share position. 20 | EntityManager.AddComponentObject(entity, Prefab.transform); 21 | EntityManager.AddComponent(entity); 22 | 23 | // Give entity control over the GO's Animator 24 | Animator animator = Prefab.GetComponent(); 25 | EntityManager.AddComponentObject(entity, animator); 26 | 27 | // Give entity control over the GO's Animator 28 | VFXControler vfxControler = Prefab.GetComponent(); 29 | EntityManager.AddComponentObject(entity, vfxControler); 30 | 31 | // Mark entity as initised 32 | EntityManager.RemoveComponent(entity); 33 | 34 | // Keep track of the presenation game object for that entity 35 | EntityManager.AddComponentData(entity,new GameObjEntity() { go = Prefab }); 36 | }).Run(); 37 | 38 | // Get rid of presentation entites for entites taht were destroyed. 39 | Entities.WithStructuralChanges().WithoutBurst().WithNone().ForEach((Entity entity, GameObjEntity prefab) => 40 | { 41 | Object.Destroy(prefab.go); 42 | EntityManager.RemoveComponent(entity); 43 | }).Run(); 44 | 45 | } 46 | 47 | #endregion Protected Methods 48 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Authoring/PresentaionPrefabInitSystem.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 19df4061515f74941b660e16372b7ba5 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Authoring/RequiereUIBootstrap.cs: -------------------------------------------------------------------------------- 1 | using Unity.Entities; 2 | 3 | public struct RequiereUIBootstrap : IComponentData 4 | { 5 | #region Public Fields 6 | 7 | public uint uiAssetGuid; 8 | 9 | #endregion Public Fields 10 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Authoring/RequiereUIBootstrap.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c8bc74d6f4d77014db7067ae5f369e54 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Authoring/VFXControler.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | public class VFXControler : MonoBehaviour 5 | { 6 | 7 | public List controllers = new List(); 8 | [HideInInspector] 9 | public List lifeTimes = new List(); 10 | [HideInInspector] 11 | public List isLoopingVfx = new List(); 12 | 13 | 14 | // Start is called before the first frame update 15 | void Start() 16 | { 17 | foreach(var controller in controllers) 18 | { 19 | float duration = float.MinValue; 20 | bool isLooping = false; 21 | ParticleSystem[] psList = controller.VfxPrefab.GetComponentsInChildren(); 22 | foreach (var ps in psList) 23 | { 24 | duration = Mathf.Max(duration, ps.main.duration + ps.main.startLifetime.constantMax); 25 | isLooping |= ps.main.loop; 26 | } 27 | lifeTimes.Add(duration); 28 | isLoopingVfx.Add(isLooping); 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /Runtime/Scripts/Authoring/VFXControler.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c8da4faaeb664b542a17f8e686f90fbb 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9815c8b81497c864cadc6e1f19ce6ad8 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/Ability.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace WaynGroup.Mgm.Ability 4 | { 5 | /// 6 | /// The runtime representation of a ability. 7 | /// 8 | [Serializable] 9 | public struct Ability 10 | { 11 | #region Public Fields 12 | 13 | public uint id; 14 | public Timing CoolDown; 15 | public Timing CastTime; 16 | public Range Range; 17 | public bool IsInRange; 18 | public bool HasEnougthRessource; 19 | 20 | #endregion Public Fields 21 | 22 | #region Public Constructors 23 | 24 | public Ability(float coolDown, float castTime, Range range) : this() 25 | { 26 | State = AbilityState.CoolingDown; 27 | CoolDown = new Timing(coolDown); 28 | CastTime = new Timing(castTime); 29 | Range = range; 30 | IsInRange = false; 31 | HasEnougthRessource = true; 32 | } 33 | 34 | #endregion Public Constructors 35 | 36 | #region Public Properties 37 | 38 | public AbilityState State { get; set; } 39 | 40 | #endregion Public Properties 41 | 42 | #region Public Methods 43 | 44 | /// 45 | /// Mark the ability as inactive so that it's effects are no longer applied. 46 | /// 47 | public void StartCooloingDown() 48 | { 49 | CoolDown.Reset(); 50 | State = AbilityState.CoolingDown; 51 | } 52 | 53 | /// 54 | /// Tries to start casting the ability. 55 | /// 56 | /// Returns a CastResult. 57 | public AbilityCastResult TryCast() 58 | { 59 | if (State == AbilityState.CoolingDown) return AbilityCastResult.NotReady; 60 | if (!IsInRange) return AbilityCastResult.OutOfRange; 61 | if (!HasEnougthRessource) return AbilityCastResult.NotEnougthRessource; 62 | 63 | if (State != AbilityState.Casting) 64 | { 65 | CastTime.Reset(); 66 | State = AbilityState.Casting; 67 | return AbilityCastResult.Success; 68 | } 69 | 70 | return AbilityCastResult.AlreadyCasting; 71 | } 72 | 73 | /// 74 | /// Update the ability cast time and set the ability state to Active when the cast time is elapsed. 75 | /// 76 | /// The amount of time elapsed since the last update. 77 | public void UpdateCastTime(float deltaTime) 78 | { 79 | CastTime.Update(deltaTime); 80 | if (CastTime.IsElapsed()) 81 | { 82 | State = AbilityState.Active; 83 | } 84 | } 85 | 86 | /// 87 | /// Update the ability cooldowns and set the ability state to CooledDown when the cooldowns are elapsed. 88 | /// 89 | /// The amount of time elapsed since the last update. 90 | public void UpdateCoolDowns(float deltaTime) 91 | { 92 | CoolDown.Update(deltaTime); 93 | if (CoolDown.IsElapsed()) 94 | { 95 | State = AbilityState.CooledDown; 96 | } 97 | } 98 | 99 | #endregion Public Methods 100 | } 101 | } -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/Ability.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5dc698a7b54b3a4418c97aba782c540a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/AbilityBuffer.cs: -------------------------------------------------------------------------------- 1 | using Unity.Entities; 2 | 3 | namespace WaynGroup.Mgm.Ability 4 | { 5 | /// 6 | /// Buffer of ability references. 7 | /// 8 | [InternalBufferCapacity(0)] // Force the ability buffer to be stord out of chunk 9 | public struct AbilityCooldownBufferElement : IBufferElementData 10 | { 11 | #region Public Fields 12 | 13 | public float CooldownTime; 14 | 15 | #endregion Public Fields 16 | } 17 | } -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/AbilityBuffer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 048631187d919e0409b0c33f35c210c8 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/AbilityCastResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace WaynGroup.Mgm.Ability 4 | { 5 | [Serializable] 6 | public enum AbilityCastResult // May need to be replaced by a bit mask updated by one or several systems 7 | { 8 | Success, // The ability started casting 9 | AlreadyCasting, // The ability started casting 10 | NotReady, // The ability is not fully cooled downed yet 11 | NotEnougthRessource, // The player does not have enougth ressource to cast the ability ("not enougth mana") (not implemented and that is probably not the best place to do that... a dedicated system per ressource type would be better I think) 12 | OutOfRange // The ability's target is too far away (not implemented and that is probably not the best place to do that... a dedicated system per targeting mode would be better I think) 13 | } 14 | } -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/AbilityCastResult.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 149accde30af25243b357136a126c874 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/AbilityInput.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using Unity.Entities; 4 | using UnityEngine; 5 | 6 | [Serializable] 7 | public struct AbilityInput : IComponentData 8 | { 9 | #region Public Fields 10 | 11 | public uint AbilityId; 12 | 13 | /// 14 | /// Store the enabeling state in the for inputed ability. 15 | /// If the ability can't be cast due to several restriction each is represented as a bitmask value. 16 | /// 0 and 1 represent respectively enable and disabled states. 17 | /// 18 | public uint _enableMask; 19 | 20 | #endregion Public Fields 21 | 22 | #region Public Constructors 23 | 24 | public AbilityInput(uint abilityId) : this() 25 | { 26 | AbilityId = abilityId; 27 | _enableMask = 1; 28 | } 29 | 30 | #endregion Public Constructors 31 | 32 | #region Public Methods 33 | 34 | public void AddRestriction(uint restrictionId) => _enableMask = +restrictionId; 35 | 36 | /// 37 | /// Indicate if the ability should be casted. 38 | /// If the mask value is not equal to 0, either there were not cast request 39 | /// or the requested ability can't be cast due to restrictions. 40 | /// 41 | /// 42 | public bool IsApplicable() => _enableMask == 0; 43 | 44 | public bool IsEnabled() => (_enableMask & 1) == 0; 45 | 46 | public void Enable() => _enableMask = 0; 47 | 48 | public void Disable() => _enableMask = 1; 49 | 50 | #endregion Public Methods 51 | } -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/AbilityInput.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6a9f870166e6a92419053f67234331f2 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/AbilityState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace WaynGroup.Mgm.Ability 4 | { 5 | [Serializable] 6 | public enum AbilityState 7 | { 8 | CooledDown, // Ability is ready to use 9 | Casting, // Ability is charging up and can be interupted 10 | CoolingDown, // Ability is cooling down 11 | Active // Ability will apply it's effect during this tick 12 | } 13 | } -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/AbilityState.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1f633c88a1d5a9c439ce392d4378df94 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/AbilityUiLink.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using UnityEngine; 4 | using UnityEngine.UIElements; 5 | 6 | [CreateAssetMenu(fileName = "AbilityUiLink", menuName = "MGM/AbilityUiLink", order = 1)] 7 | [Serializable] 8 | public class AbilityUiLink : ScriptableObject 9 | { 10 | #region Public Fields 11 | 12 | [HideInInspector] 13 | public uint Id; 14 | 15 | public PanelSettings PanelSettings; 16 | public VisualTreeAsset UxmlUi; 17 | public float SortingOrder; 18 | 19 | #endregion Public Fields 20 | } -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/AbilityUiLink.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 68bab39dcf961d640bd8e6dfc6b3f754 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/EffectData.cs: -------------------------------------------------------------------------------- 1 | using WaynGroup.Mgm.Ability; 2 | 3 | public struct EffectData 4 | { 5 | #region Public Fields 6 | 7 | public uint Guid; 8 | public IEffect effect; 9 | 10 | #endregion Public Fields 11 | } 12 | 13 | public struct CostData 14 | { 15 | #region Public Fields 16 | 17 | public uint Guid; 18 | public IAbilityCost cost; 19 | 20 | #endregion Public Fields 21 | } -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/EffectData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 58b21615f23c1684aaeef9158ef3033e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/IEffect.cs: -------------------------------------------------------------------------------- 1 | using Unity.Entities; 2 | 3 | namespace WaynGroup.Mgm.Ability 4 | { 5 | public enum TargetingMode 6 | { 7 | Target, 8 | Self 9 | } 10 | 11 | public enum ActivationPhase 12 | { 13 | CastingStart, 14 | CastingEnd 15 | } 16 | 17 | /// 18 | /// Interface for declaring new effect struct. 19 | /// 20 | public interface IEffect : IComponentData 21 | { 22 | #region Public Properties 23 | 24 | TargetingMode Affects { get; set; } 25 | ActivationPhase Phase { get; set; } 26 | 27 | #endregion Public Properties 28 | } 29 | 30 | /// 31 | /// Interface for declaring new ability cost struct. 32 | /// 33 | public interface IAbilityCost : IComponentData 34 | { 35 | } 36 | 37 | public interface ICostHandler where RESOURCE : struct, IComponentData 38 | { 39 | #region Public Methods 40 | 41 | void ConsumeCost(COST cost, ref RESOURCE resource); 42 | 43 | bool HasEnougthResourceLeft(COST cost, in RESOURCE resource); 44 | 45 | #endregion Public Methods 46 | } 47 | } -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/IEffect.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f2603e8f77a0b934b9d8ef2c6cf0135c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/IEffectBufferElement.cs: -------------------------------------------------------------------------------- 1 | using Unity.Entities; 2 | 3 | namespace WaynGroup.Mgm.Ability 4 | { 5 | /// 6 | /// Interface to declare a new effect buffer to add to a runtime entity. 7 | /// 8 | /// 9 | public interface IEffectBufferElement : IBufferElementData where EFFECT : struct, IEffect 10 | { 11 | #region Public Properties 12 | 13 | /// 14 | /// The index of the ability this effect is attached to. 15 | /// 16 | int AbilityIndex { get; set; } 17 | 18 | /// 19 | /// The effect. 20 | /// 21 | EFFECT Effect { get; set; } 22 | 23 | #endregion Public Properties 24 | } 25 | 26 | /// 27 | /// Interface to declare a new effect buffer to add to a runtime entity. 28 | /// 29 | /// 30 | public interface IAbilityCostBufferElement : IBufferElementData where COST : struct, IAbilityCost 31 | { 32 | #region Public Properties 33 | 34 | /// 35 | /// The index of the ability this effect is attached to. 36 | /// 37 | int AbilityIndex { get; set; } 38 | 39 | /// 40 | /// The effect. 41 | /// 42 | COST Cost { get; set; } 43 | 44 | #endregion Public Properties 45 | } 46 | } -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/IEffectBufferElement.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 01551bd212dbe444d95e1aea9575ec7a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/MultiMap.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | public class MultiHashMap 4 | { 5 | #region Private Fields 6 | 7 | private readonly Dictionary> storage; 8 | 9 | #endregion Private Fields 10 | 11 | #region Public Constructors 12 | 13 | public MultiHashMap() 14 | { 15 | storage = new Dictionary>(); 16 | } 17 | 18 | #endregion Public Constructors 19 | 20 | #region Public Properties 21 | 22 | public IEnumerable Keys 23 | { 24 | get { return storage.Keys; } 25 | } 26 | 27 | #endregion Public Properties 28 | 29 | #region Public Indexers 30 | 31 | public IList this[TKey key] 32 | { 33 | get 34 | { 35 | if (!storage.ContainsKey(key)) 36 | throw new KeyNotFoundException( 37 | string.Format( 38 | "The given key {0} was not found in the collection.", key)); 39 | return storage[key]; 40 | } 41 | } 42 | 43 | #endregion Public Indexers 44 | 45 | #region Public Methods 46 | 47 | public void Add(TKey key, TValue value) 48 | { 49 | if (!storage.ContainsKey(key)) storage.Add(key, new List()); 50 | storage[key].Add(value); 51 | } 52 | 53 | public bool ContainsKey(TKey key) 54 | { 55 | return storage.ContainsKey(key); 56 | } 57 | 58 | public int Count(TKey key) 59 | { 60 | if (!storage.ContainsKey(key)) return 0; 61 | return this[key].Count; 62 | } 63 | 64 | #endregion Public Methods 65 | } -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/MultiMap.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 871717549a6521349b9d42f0934abcb9 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/NewTestCoponent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Unity.Collections; 3 | using Unity.Entities; 4 | using Unity.Mathematics; 5 | 6 | [Serializable] 7 | public struct NewTestCoponent : IComponentData 8 | { 9 | // Add fields to your component here. Remember that: 10 | // 11 | // * A component itself is for storing data and doesn't 'do' anything. 12 | // 13 | // * To act on the data, you will need a System. 14 | // 15 | // * Data in a component must be blittable, which means a component can 16 | // only contain fields which are primitive types or other blittable 17 | // structs; they cannot contain references to classes. 18 | // 19 | // * You should focus on the data structure that makes the most sense 20 | // for runtime use here. Authoring Components will be used for 21 | // authoring the data in the Editor. 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/NewTestCoponent.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 436c3f9291c544547808f415696cc4e7 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/ScriptableAbility.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UnityEditor; 4 | using UnityEngine; 5 | using UnityEngine.AddressableAssets; 6 | using UnityEngine.Localization; 7 | 8 | using WaynGroup.Mgm.Ability; 9 | 10 | [Serializable] 11 | public class PrefabAssetRef : AssetReferenceGameObject 12 | { 13 | public PrefabAssetRef(string guid) : base(guid) 14 | { 15 | } 16 | 17 | public GameObject GetAssetInEditor() 18 | { 19 | if(this.editorAsset != null) 20 | { 21 | Debug.Log("Returned from editorAsset"); 22 | return this.editorAsset; 23 | } 24 | Debug.Log("Returned from cached asset"); 25 | return (GameObject)this.CachedAsset; 26 | } 27 | } 28 | 29 | [Serializable] 30 | public class SpawnableData : IEffect 31 | { 32 | #region Public Fields 33 | 34 | public AssetReferenceGameObject PrefabRef; 35 | 36 | public int count; 37 | 38 | [field: SerializeField] 39 | public TargetingMode Affects { get; set; } 40 | [field: SerializeField] 41 | public ActivationPhase Phase { get; set; } 42 | 43 | #endregion Public Fields 44 | } 45 | 46 | [Serializable] 47 | public struct AbilityTimings 48 | { 49 | #region Public Fields 50 | 51 | public float Cast; 52 | public float CoolDown; 53 | 54 | #endregion Public Fields 55 | } 56 | 57 | [Serializable] 58 | public struct Range 59 | { 60 | #region Public Fields 61 | 62 | public float Min; 63 | public float Max; 64 | 65 | #endregion Public Fields 66 | } 67 | 68 | [CreateAssetMenu(fileName = "NewAbility", menuName = "MGM/Ability", order = 1)] 69 | [Serializable] 70 | public class ScriptableAbility : ScriptableObject 71 | { 72 | #region Public Fields 73 | 74 | /// 75 | /// A unique Id generated when creating the ability in the editor. 76 | /// 77 | public uint Id; 78 | 79 | /// 80 | /// The name of the ability. 81 | /// 82 | public LocalizedString Name; 83 | 84 | /// 85 | /// The skill Icon. 86 | /// 87 | public Texture2D Icon; 88 | 89 | /// 90 | /// The distance constraints that need to be met in order to cast the ability. 91 | /// 92 | public Range Range; 93 | 94 | /// 95 | /// The time necessary for the ability to recharge before it can be reused and time needed before it's activation. 96 | /// 97 | public AbilityTimings Timings; 98 | 99 | /// 100 | /// The list of costs that are check to cast the ability. 101 | /// A corresponding effect is automatically added to the list of effect at runtime to consume the associated ressource. 102 | /// 103 | [SerializeReference] 104 | public List Costs; 105 | 106 | /// 107 | /// The list of effect that are applied after the CastTime has elapsed. 108 | /// 109 | [SerializeReference] 110 | public List Effects; 111 | 112 | #endregion Public Fields 113 | 114 | } -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/ScriptableAbility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b49966bb9ea414943a50ddba966b498e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/Target.cs: -------------------------------------------------------------------------------- 1 | using Unity.Entities; 2 | 3 | namespace WaynGroup.Mgm.Ability 4 | { 5 | [GenerateAuthoringComponent] 6 | public struct Target : IComponentData 7 | { 8 | #region Public Fields 9 | 10 | public Entity Value; 11 | 12 | #endregion Public Fields 13 | } 14 | } -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/Target.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 492c9be7daddb434aa8a0ceaed92075c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/Timing.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace WaynGroup.Mgm.Ability 4 | { 5 | /// 6 | /// Represents a timeframe. 7 | /// 8 | [Serializable] 9 | public struct Timing 10 | { 11 | #region Public Fields 12 | 13 | /// 14 | /// The current remaining time on the timing. 15 | /// 16 | public float CurrentValue; 17 | 18 | #endregion Public Fields 19 | 20 | #region Private Fields 21 | 22 | /// 23 | /// The original amount of time on the timing. 24 | /// 25 | private readonly float OrginalValue; 26 | 27 | #endregion Private Fields 28 | 29 | #region Public Constructors 30 | 31 | /// 32 | /// Initialize the timing to the number of seconds passed as value. 33 | /// 34 | /// The number of seconds for that timing. 35 | public Timing(float value) 36 | { 37 | CurrentValue = value; 38 | OrginalValue = value; 39 | } 40 | 41 | #endregion Public Constructors 42 | 43 | #region Public Methods 44 | 45 | /// 46 | /// Compute the time remaining on that timing. First float is in seconds, second float is in % of total timing. 47 | /// 48 | /// 49 | public (float, float) ComputeRemainingTime() 50 | { 51 | return (CurrentValue, CurrentValue / OrginalValue); 52 | } 53 | 54 | /// 55 | /// Determines if the timing has elapsed. 56 | /// 57 | /// True if there is no remaining time on the timing, false otherwise. 58 | public bool IsElapsed() 59 | { 60 | return CurrentValue <= 0; 61 | } 62 | 63 | /// 64 | /// Update the remaining time on the timing. 65 | /// 66 | /// The amount of time to subtract from the remaining time. 67 | public void Update(float deltaTime) 68 | { 69 | CurrentValue -= deltaTime; 70 | } 71 | 72 | /// 73 | /// Resert the timing to it's original value. 74 | /// 75 | public void Reset() 76 | { 77 | CurrentValue = OrginalValue; 78 | } 79 | 80 | #endregion Public Methods 81 | } 82 | } -------------------------------------------------------------------------------- /Runtime/Scripts/DataStructures/Timing.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3dbfad0fb991fa545b441b7cf71d5a3c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Systems.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5a01a2eca96982e43ba7325260922e5e 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/AbilityCostCheckInitializationSystem.cs: -------------------------------------------------------------------------------- 1 | using Unity.Entities; 2 | using UnityEngine; 3 | 4 | namespace WaynGroup.Mgm.Ability 5 | { 6 | public partial class AbilityCostCheckInitializationSystem : SystemBase 7 | { 8 | #region Protected Methods 9 | 10 | protected override void OnUpdate() 11 | { 12 | Entities.ForEach((ref AbilityInput abilityInput) => 13 | { 14 | abilityInput.Disable(); 15 | }).WithBurst() 16 | .ScheduleParallel(); 17 | } 18 | 19 | #endregion Protected Methods 20 | } 21 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/AbilityCostCheckInitializationSystem.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ad6b2e39c317d3043b92221064f1abfd 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/AbilityCostCheckerSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using Unity.Burst; 4 | using Unity.Collections; 5 | using Unity.Collections.LowLevel.Unsafe; 6 | using Unity.Entities; 7 | using Unity.Jobs; 8 | using UnityEngine; 9 | 10 | namespace WaynGroup.Mgm.Ability 11 | { 12 | [UpdateInGroup(typeof(AbilityCostsCheckerSystemGroup))] 13 | public abstract partial class AbilityCostCheckerSystem : SystemBase 14 | where COST : struct, IAbilityCost 15 | where RESOURCE : struct, IComponentData 16 | where COST_HANDLER : struct, ICostHandler 17 | { 18 | #region Private Fields 19 | 20 | /// 21 | /// The base query to select entity that are eligible to this system. 22 | /// 23 | private EntityQuery _query; 24 | 25 | /// 26 | /// A map of all effects' unmutable data for the EFFECT type. 27 | /// 28 | private NativeParallelMultiHashMap _costMap; 29 | 30 | #endregion Private Fields 31 | 32 | #region Protected Methods 33 | 34 | protected override void OnCreate() 35 | { 36 | base.OnCreate(); 37 | _query = GetEntityQuery(new EntityQueryDesc() 38 | { 39 | All = new ComponentType[] 40 | { 41 | ComponentType.ReadOnly(), 42 | ComponentType.ReadWrite() 43 | } 44 | }); 45 | _costMap = new NativeParallelMultiHashMap(0, Allocator.Persistent); 46 | World.GetOrCreateSystem().OnCostUpdate += UpdateCostCache; 47 | Enabled = false; 48 | } 49 | 50 | protected override sealed void OnUpdate() 51 | { 52 | Dependency = new CostHandlerJob() 53 | { 54 | ResourceComponent = GetComponentTypeHandle(true), 55 | AbilityInputComponent = GetComponentTypeHandle(), 56 | CostMap = _costMap, 57 | CostHandler = GetCostHandler() 58 | }.ScheduleParallel(_query, Dependency); 59 | } 60 | 61 | protected override void OnDestroy() 62 | { 63 | base.OnDestroy(); 64 | if (_costMap.IsCreated) _costMap.Dispose(); 65 | } 66 | 67 | protected virtual COST_HANDLER GetCostHandler() 68 | { 69 | return default; 70 | } 71 | 72 | #endregion Protected Methods 73 | 74 | #region Private Methods 75 | 76 | private void UpdateCostCache(MultiHashMap costMap) 77 | { 78 | Enabled = false; 79 | _costMap.Clear(); 80 | _costMap.Capacity = costMap.Count(typeof(COST)); 81 | foreach (CostData costData in costMap[typeof(COST)]) 82 | { 83 | _costMap.Add(costData.Guid, (COST)costData.cost); 84 | } 85 | Enabled = true; 86 | } 87 | 88 | #endregion Private Methods 89 | 90 | #region Public Structs 91 | 92 | /// 93 | /// Job in charge of the shared logic (targetting, ability activity,..). 94 | /// This job will call the WriteContextualizedEffect method of the CTX_WRITER when the efect has to be triggered. 95 | /// 96 | [BurstCompile] 97 | public struct CostHandlerJob : IJobChunk 98 | { 99 | #region Public Fields 100 | 101 | public COST_HANDLER CostHandler; 102 | public ComponentTypeHandle AbilityInputComponent; 103 | [ReadOnly] public NativeParallelMultiHashMap CostMap; 104 | [ReadOnly] public ComponentTypeHandle ResourceComponent; 105 | 106 | #endregion Public Fields 107 | 108 | #region Public Methods 109 | 110 | public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) 111 | { 112 | NativeArray resourceComponent = chunk.GetNativeArray(ResourceComponent); 113 | NativeArray abilityInputComponent = chunk.GetNativeArray(AbilityInputComponent); 114 | for (int entityIndex = 0; entityIndex < chunk.Count; ++entityIndex) 115 | { 116 | AbilityInput input = abilityInputComponent[entityIndex]; 117 | if (input.IsEnabled()) 118 | { 119 | RESOURCE resource = resourceComponent[entityIndex]; 120 | bool temp = true; 121 | NativeParallelMultiHashMap.Enumerator enumerator = CostMap.GetValuesForKey(input.AbilityId); 122 | while (enumerator.MoveNext()) 123 | { 124 | COST cost = enumerator.Current; 125 | temp &= CostHandler.HasEnougthResourceLeft(cost, in resource); 126 | } 127 | if (!temp) 128 | { 129 | input.AddRestriction(4); 130 | } 131 | abilityInputComponent[entityIndex] = input; 132 | } 133 | } 134 | } 135 | 136 | #endregion Public Methods 137 | } 138 | 139 | #endregion Public Structs 140 | } 141 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/AbilityCostCheckerSystem.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a975914e86e8be840b5b0371465ef8ba 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/AbilityCostConsumerSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using Unity.Burst; 4 | using Unity.Collections; 5 | using Unity.Entities; 6 | 7 | namespace WaynGroup.Mgm.Ability 8 | { 9 | [UpdateInGroup(typeof(AbilityCostsConsumerSystemGroup))] 10 | public abstract partial class AbilityCostConsumerSystem : SystemBase 11 | where COST : struct, IAbilityCost 12 | where RESOURCE : struct, IComponentData 13 | where COST_HANDLER : struct, ICostHandler 14 | { 15 | #region Private Fields 16 | 17 | /// 18 | /// The base query to select entity that are eligible to this system. 19 | /// 20 | private EntityQuery _query; 21 | 22 | /// 23 | /// A map of all effects' unmutable data for the EFFECT type. 24 | /// 25 | private NativeParallelMultiHashMap _costMap; 26 | 27 | #endregion Private Fields 28 | 29 | #region Protected Methods 30 | 31 | protected override void OnCreate() 32 | { 33 | base.OnCreate(); 34 | _query = GetEntityQuery(new EntityQueryDesc() 35 | { 36 | All = new ComponentType[] 37 | { 38 | ComponentType.ReadWrite(), 39 | ComponentType.ReadOnly() 40 | } 41 | }); 42 | World.GetOrCreateSystem().OnCostUpdate += UpdateCostCache; 43 | Enabled = false; 44 | } 45 | 46 | protected override sealed void OnUpdate() 47 | { 48 | Dependency = new CostHandlerJob() 49 | { 50 | AbilityInputComponent = GetComponentTypeHandle(true), 51 | ResourceComponent = GetComponentTypeHandle(false), 52 | CostMap = _costMap, 53 | CostHandler = GetCostHandler() 54 | }.ScheduleParallel(_query, Dependency); 55 | } 56 | 57 | protected override void OnDestroy() 58 | { 59 | base.OnDestroy(); 60 | if (_costMap.IsCreated) _costMap.Dispose(); 61 | } 62 | 63 | protected virtual COST_HANDLER GetCostHandler() 64 | { 65 | return default; 66 | } 67 | 68 | #endregion Protected Methods 69 | 70 | #region Private Methods 71 | 72 | private static NativeParallelMultiHashMap BuildEffectMapCache(MultiHashMap effectMap) 73 | { 74 | NativeParallelMultiHashMap map = new NativeParallelMultiHashMap(effectMap.Count(typeof(COST)), Allocator.Persistent); 75 | foreach (CostData costData in effectMap[typeof(COST)]) 76 | { 77 | map.Add(costData.Guid, (COST)costData.cost); 78 | } 79 | return map; 80 | } 81 | 82 | private void UpdateCostCache(MultiHashMap costMap) 83 | { 84 | NativeParallelMultiHashMap map = BuildEffectMapCache(costMap); 85 | RefreshEffectMapChache(map); 86 | Enabled = true; 87 | } 88 | 89 | private void RefreshEffectMapChache(NativeParallelMultiHashMap map) 90 | { 91 | if (_costMap.IsCreated) _costMap.Dispose(); 92 | _costMap = map; 93 | } 94 | 95 | #endregion Private Methods 96 | 97 | #region Public Structs 98 | 99 | /// 100 | /// Job in charge of the shared logic (targetting, ability activity,..). 101 | /// This job will call the WriteContextualizedEffect method of the CTX_WRITER when the efect has to be triggered. 102 | /// 103 | [BurstCompile] 104 | public struct CostHandlerJob : IJobChunk 105 | { 106 | #region Public Fields 107 | 108 | [ReadOnly] public ComponentTypeHandle AbilityInputComponent; 109 | [ReadOnly] public NativeParallelMultiHashMap CostMap; 110 | public COST_HANDLER CostHandler; 111 | public ComponentTypeHandle ResourceComponent; 112 | 113 | #endregion Public Fields 114 | 115 | #region Public Methods 116 | 117 | public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) 118 | { 119 | NativeArray resourceComponent = chunk.GetNativeArray(ResourceComponent); 120 | NativeArray abilityInputComponent = chunk.GetNativeArray(AbilityInputComponent); 121 | 122 | for (int entityIndex = 0; entityIndex < chunk.Count; ++entityIndex) 123 | { 124 | AbilityInput abilityInput = abilityInputComponent[entityIndex]; 125 | if (!abilityInput.IsApplicable()) continue; 126 | 127 | RESOURCE resource = resourceComponent[entityIndex]; 128 | NativeParallelMultiHashMap.Enumerator enumerator = CostMap.GetValuesForKey(abilityInput.AbilityId); 129 | while (enumerator.MoveNext()) 130 | { 131 | COST cost = enumerator.Current; 132 | CostHandler.ConsumeCost(cost, ref resource); 133 | resourceComponent[entityIndex] = resource; 134 | } 135 | } 136 | } 137 | 138 | #endregion Public Methods 139 | } 140 | 141 | #endregion Public Structs 142 | } 143 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/AbilityCostConsumerSystem.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 19f3a546b5bd6ad439b1c73db3b6d776 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/AbilityEffectConsumerSystems.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Unity.Burst; 3 | using Unity.Collections; 4 | using Unity.Entities; 5 | using Unity.Jobs; 6 | using UnityEngine; 7 | 8 | namespace WaynGroup.Mgm.Ability 9 | { 10 | [UpdateInGroup(typeof(AbilityConsumerSystemGroup))] 11 | public abstract partial class AbilityEffectConsumerSystem : SystemBase where EFFECT : struct, IEffect 12 | where EFFECT_CTX : struct, IEffectContext 13 | { 14 | #region Protected Fields 15 | 16 | /// 17 | /// A map o effect per targeted entity to improve consumer job performance. 18 | /// 19 | protected NativeParallelMultiHashMap _effects; 20 | 21 | #endregion Protected Fields 22 | 23 | #region Private Fields 24 | 25 | /// 26 | /// The stream to Read/Write the contextualized effect. 27 | /// 28 | private List _effectStreams; 29 | 30 | private List _forEachCounts; 31 | 32 | /// 33 | /// The trigger job handle to make sure we finished trigerring all necessary effect before consuming the effects. 34 | /// 35 | private JobHandle TriggerJobHandle; 36 | 37 | #endregion Private Fields 38 | 39 | #region Public Methods 40 | 41 | /// 42 | /// Setup the dependecy between the trigger job and the consumer job to make sure we finished trigerring all necessary effect before consuming the effects. 43 | /// 44 | /// The trigger job JobHandle. 45 | public void RegisterTriggerDependency(JobHandle triggerJobHandle) 46 | { 47 | TriggerJobHandle = triggerJobHandle; 48 | } 49 | 50 | /// 51 | /// Get a NativeStream.Writer to write the effects to consume. 52 | /// 53 | /// The number of chunk of thread that writes to the NativeStream 54 | /// 55 | public NativeStream.Writer CreateConsumerWriter(int foreachCount) 56 | { 57 | var _effectStream = new NativeStream(foreachCount, Allocator.TempJob); 58 | _effectStreams.Add(_effectStream); 59 | _forEachCounts.Add(foreachCount); 60 | //Debug.Log($"New Writer ({_effectStreams.Count})"); 61 | return _effectStream.AsWriter(); 62 | } 63 | 64 | #endregion Public Methods 65 | 66 | #region Protected Methods 67 | 68 | protected override void OnCreate() 69 | { 70 | base.OnCreate(); 71 | _effectStreams = new List(); 72 | _forEachCounts = new List(); 73 | // Allocate the map only on create to avoid allocating every frame. 74 | _effects = new NativeParallelMultiHashMap(0, Allocator.Persistent); 75 | } 76 | 77 | protected override void OnDestroy() 78 | { 79 | base.OnDestroy(); 80 | foreach (var stream in _effectStreams) 81 | { 82 | if (stream.IsCreated) 83 | { 84 | stream.Dispose(Dependency); 85 | } 86 | } 87 | if (_effects.IsCreated) 88 | { 89 | _effects.Dispose(Dependency); 90 | } 91 | } 92 | 93 | /// 94 | /// Delegate the effect consumption logic to the derived class. 95 | /// 96 | protected abstract void Consume(); 97 | 98 | protected override sealed void OnUpdate() 99 | { 100 | Dependency = JobHandle.CombineDependencies(Dependency, TriggerJobHandle); 101 | 102 | #region Make sure there is something to do 103 | 104 | // If the producer did not actually write anything to the stream, the native stream will 105 | // not be flaged as created. In that case we don't need to do anything and we can remove 106 | // the stream from the list of stream to process Not doing the IsCreated check actually 107 | // result in a non authrorized access to the memory and crashes Unity. 108 | for (int i = _effectStreams.Count - 1; i >= 0; i--) 109 | { 110 | if (!_effectStreams[i].IsCreated) 111 | { 112 | _effectStreams.RemoveAt(i); 113 | _forEachCounts.RemoveAt(i); 114 | } 115 | } 116 | 117 | // if there are no stream left to process, do nothing 118 | if (_effectStreams.Count == 0) return; 119 | 120 | 121 | #endregion Make sure there is something to do 122 | 123 | #region Setup effect map and ensure it's capacity 124 | 125 | NativeArray effectCounts = new NativeArray(_effectStreams.Count, Allocator.TempJob); 126 | var inputDeps = Dependency; 127 | var outDeps = new NativeArray(_effectStreams.Count + 1, Allocator.TempJob); 128 | outDeps[0] = Dependency; 129 | for (int i = 0; i < _effectStreams.Count; i++) 130 | { 131 | outDeps[i + 1] = new CountEffectJob() 132 | { 133 | streamReader = _effectStreams[i].AsReader(), 134 | index = i, 135 | count = effectCounts 136 | }.Schedule(inputDeps); 137 | } 138 | Dependency = JobHandle.CombineDependencies(outDeps); 139 | outDeps.Dispose(Dependency); 140 | EnsureCapcityJob AllocateJob = new EnsureCapcityJob() 141 | { 142 | EffectCounts = effectCounts, 143 | Effects = _effects 144 | }; 145 | Dependency = AllocateJob.Schedule(Dependency); 146 | effectCounts.Dispose(Dependency); 147 | 148 | #endregion Setup effect map and ensure it's capacity 149 | 150 | #region Remap Effect to their targeted entity 151 | 152 | NativeParallelMultiHashMap.ParallelWriter effectsWriter = _effects.AsParallelWriter(); 153 | 154 | for (int i = 0; i < _effectStreams.Count; i++) 155 | { 156 | Dependency = new RemapEffects() 157 | { 158 | EffectReader = _effectStreams[i].AsReader(), 159 | EffectsWriter = _effects.AsParallelWriter() 160 | }.Schedule(_forEachCounts[i], 1, Dependency); 161 | } 162 | 163 | #endregion Remap Effect to their targeted entity 164 | 165 | // Call the effect consumption logic defined in the derived class. 166 | Consume(); 167 | for (int i = 0; i < _effectStreams.Count; i++) 168 | { 169 | _effectStreams[i].Dispose(Dependency); 170 | } 171 | _effectStreams.Clear(); 172 | } 173 | 174 | #endregion Protected Methods 175 | 176 | #region Protected Structs 177 | 178 | protected struct ContextualizedEffect 179 | { 180 | #region Public Fields 181 | 182 | public EFFECT Effect; 183 | public EFFECT_CTX Context; 184 | 185 | #endregion Public Fields 186 | } 187 | 188 | #endregion Protected Structs 189 | 190 | #region Private Structs 191 | 192 | [BurstCompatible] 193 | private struct CountEffectJob : IJob 194 | { 195 | #region Public Fields 196 | 197 | [NativeDisableParallelForRestriction] 198 | public NativeArray count; 199 | 200 | [ReadOnly] public int index; 201 | [ReadOnly] public NativeStream.Reader streamReader; 202 | 203 | #endregion Public Fields 204 | 205 | #region Public Methods 206 | 207 | public void Execute() 208 | { 209 | count[index] = streamReader.Count(); 210 | } 211 | 212 | #endregion Public Methods 213 | } 214 | 215 | /// 216 | /// This job reads all the effects to apply and dsipatche them into a map by targeted entity. 217 | /// This ensures better performance overall in consuming the effect. 218 | /// 219 | [BurstCompile] 220 | private struct RemapEffects : IJobParallelFor 221 | { 222 | #region Public Fields 223 | 224 | [ReadOnly] public NativeStream.Reader EffectReader; 225 | public NativeParallelMultiHashMap.ParallelWriter EffectsWriter; 226 | 227 | #endregion Public Fields 228 | 229 | #region Public Methods 230 | 231 | public void Execute(int index) 232 | { 233 | EffectReader.BeginForEachIndex(index); 234 | while (EffectReader.RemainingItemCount > 0) 235 | { 236 | EFFECT effect = EffectReader.Read(); 237 | EFFECT_CTX context = EffectReader.Read(); 238 | int targetCount = EffectReader.Read(); 239 | for (int i = 0; i < targetCount; ++i) 240 | { 241 | EffectsWriter.Add(EffectReader.Read(), new ContextualizedEffect() { Effect = effect, Context = context }); 242 | } 243 | } 244 | EffectReader.EndForEachIndex(); 245 | } 246 | 247 | #endregion Public Methods 248 | } 249 | 250 | /// 251 | /// Clear the effect map and allocate additional capacity if needed. 252 | /// 253 | [BurstCompile] 254 | private struct EnsureCapcityJob : IJob 255 | { 256 | #region Public Fields 257 | 258 | [ReadOnly] public NativeArray EffectCounts; 259 | public NativeParallelMultiHashMap Effects; 260 | 261 | #endregion Public Fields 262 | 263 | #region Public Methods 264 | 265 | public void Execute() 266 | { 267 | var count = 0; 268 | for (int i = 0; i < EffectCounts.Length; i++) 269 | { 270 | count += EffectCounts[i]; 271 | } 272 | 273 | Debug.Log($"{count} Effect in total."); 274 | Effects.Clear(); 275 | if (Effects.Capacity < count) 276 | { 277 | Effects.Capacity = count; 278 | } 279 | } 280 | 281 | #endregion Public Methods 282 | } 283 | 284 | #endregion Private Structs 285 | } 286 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/AbilityEffectConsumerSystems.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 539ba9a373b579a459b75dfdb31fb3d8 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/AbilityEffectTriggerSystems.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Unity.Burst; 4 | using Unity.Collections; 5 | using Unity.Entities; 6 | using UnityEngine; 7 | 8 | namespace WaynGroup.Mgm.Ability 9 | { 10 | /// 11 | /// Base system to trigger effects. It provides the shared functionality of checking which ability is active and which target(s) are affected. 12 | /// 13 | /// The effect type trigered by this system. 14 | /// The system in charge of consuming the effects once triggered. 15 | /// The writer struct in charge of populating the context surroinding the triggered effect like informations about the caster (position, strength,...). 16 | /// The struct containing the effect and it's context like informations about the caster (position, strength,...) 17 | [UpdateInGroup(typeof(AbilityTriggerSystemGroup))] 18 | public abstract partial class AbilityEffectTriggerSystem : SystemBase 19 | where EFFECT : struct, IEffect 20 | where CONSUMER : AbilityEffectConsumerSystem 21 | where CTX_BUILDER : struct, IEffectContextWriter 22 | where EFFECT_CTX : struct, IEffectContext 23 | { 24 | #region Private Fields 25 | 26 | /// 27 | /// The system in charge of consuming the effects once triggered. 28 | /// 29 | private AbilityEffectConsumerSystem _conusmerSystem; 30 | 31 | /// 32 | /// The base query to select entity that are eligible to this system. 33 | /// 34 | private EntityQuery _query; 35 | 36 | /// 37 | /// A map of all effects' unmutable data for the EFFECT type. 38 | /// 39 | private NativeParallelMultiHashMap _effectMap; 40 | 41 | #endregion Private Fields 42 | 43 | #region Protected Methods 44 | 45 | protected override void OnCreate() 46 | { 47 | base.OnCreate(); 48 | ListenfForEffectCatalogUpdate(); 49 | CacheEffectConsumerSystem(); 50 | BuildEntityQuery(); 51 | Enabled = false; 52 | } 53 | 54 | protected override void OnUpdate() 55 | { 56 | // If the consumer won't run, there is no point in tirgerring the effects... 57 | // This also avoid the creation of a stream that would never be disposed of. 58 | if (!_conusmerSystem.ShouldRunSystem()) return; 59 | 60 | Dependency = new TriggerJob() 61 | { 62 | CurrentlyCastingChunk = GetComponentTypeHandle(true), 63 | TargetChunk = GetComponentTypeHandle(true), 64 | EntityChunk = GetEntityTypeHandle(), 65 | ConsumerWriter = _conusmerSystem.CreateConsumerWriter(_query.CalculateChunkCount()), 66 | EffectContextBuilder = GetContextWriter(), 67 | EffectMap = _effectMap 68 | }.ScheduleParallel(_query, Dependency); 69 | 70 | // Tell the consumer to wait for ths trigger job to finish before starting to consume the effects. 71 | _conusmerSystem.RegisterTriggerDependency(Dependency); 72 | } 73 | 74 | /// 75 | /// This method delegates the cosntruction of the CTX_WRITER to the derived class. 76 | /// 77 | /// A struct implementing IEffectContextWriter. 78 | protected virtual CTX_BUILDER GetContextWriter() 79 | { 80 | return default; 81 | } 82 | 83 | /// 84 | /// A method to describe the necessary components on the caster to populate the effect's context. 85 | /// 86 | /// EntityQueryDesc 87 | protected virtual EntityQueryDesc GetEffectContextEntityQueryDesc() 88 | { 89 | return new EntityQueryDesc(); 90 | } 91 | 92 | protected override void OnDestroy() 93 | { 94 | base.OnDestroy(); 95 | if (_effectMap.IsCreated) _effectMap.Dispose(); 96 | } 97 | 98 | #endregion Protected Methods 99 | 100 | #region Private Methods 101 | 102 | private static NativeParallelMultiHashMap BuildEffectMapCache(MultiHashMap effectMap) 103 | { 104 | 105 | Debug.Log($"Caching for {typeof(EFFECT)}"); 106 | NativeParallelMultiHashMap map = new NativeParallelMultiHashMap(effectMap.Count(typeof(EFFECT)), Allocator.Persistent); 107 | foreach (EffectData effectData in effectMap[typeof(EFFECT)]) 108 | { 109 | 110 | Debug.Log($"Caching for {effectData.Guid},{effectData.effect}"); 111 | map.Add(effectData.Guid, (EFFECT)effectData.effect); 112 | } 113 | return map; 114 | } 115 | 116 | private void UpdateEffectCache(MultiHashMap effectMap) 117 | { 118 | if (!effectMap.ContainsKey(typeof(EFFECT))) 119 | { 120 | _conusmerSystem.Enabled = false; 121 | return; 122 | } 123 | NativeParallelMultiHashMap map = BuildEffectMapCache(effectMap); 124 | RefreshEffectMapChache(map); 125 | Enabled = true; 126 | _conusmerSystem.Enabled = true; 127 | } 128 | 129 | private void RefreshEffectMapChache(NativeParallelMultiHashMap map) 130 | { 131 | if (_effectMap.IsCreated) _effectMap.Dispose(); 132 | _effectMap = map; 133 | } 134 | 135 | private void ListenfForEffectCatalogUpdate() 136 | { 137 | World.GetOrCreateSystem().OnEffectUpdate += UpdateEffectCache; 138 | } 139 | 140 | private void CacheEffectConsumerSystem() 141 | { 142 | _conusmerSystem = World.GetOrCreateSystem(); 143 | } 144 | 145 | private void BuildEntityQuery() 146 | { 147 | EntityQueryDesc baseEntityQueryDesc = new EntityQueryDesc() 148 | { 149 | All = new ComponentType[] 150 | { 151 | ComponentType.ReadOnly(), 152 | ComponentType.ReadOnly() 153 | } 154 | }; 155 | 156 | EntityQueryDesc contextQueryDesc = GetEffectContextEntityQueryDesc(); 157 | 158 | EntityQueryDesc entityQueryDesc = new EntityQueryDesc() 159 | { 160 | All = baseEntityQueryDesc.All.Concat(contextQueryDesc.All).ToArray(), 161 | Any = baseEntityQueryDesc.Any.Concat(contextQueryDesc.Any).ToArray(), 162 | None = baseEntityQueryDesc.None.Concat(contextQueryDesc.None).ToArray(), 163 | Options = contextQueryDesc.Options 164 | }; 165 | 166 | _query = GetEntityQuery(entityQueryDesc); 167 | } 168 | 169 | #endregion Private Methods 170 | 171 | #region Public Structs 172 | 173 | /// 174 | /// Job in charge of the shared logic (targetting, ability activity,..). 175 | /// This job will call the WriteContextualizedEffect method of the CTX_WRITER when the efect has to be triggered. 176 | /// 177 | [BurstCompile] 178 | public struct TriggerJob : IJobEntityBatch 179 | { 180 | #region Public Fields 181 | 182 | [ReadOnly] public ComponentTypeHandle CurrentlyCastingChunk; 183 | [ReadOnly] public ComponentTypeHandle TargetChunk; 184 | [ReadOnly] public EntityTypeHandle EntityChunk; 185 | [ReadOnly] public NativeParallelMultiHashMap EffectMap; 186 | public NativeStream.Writer ConsumerWriter; 187 | public CTX_BUILDER EffectContextBuilder; 188 | 189 | #endregion Public Fields 190 | 191 | #region Public Methods 192 | 193 | public void Execute(ArchetypeChunk batchInChunk, int batchIndex) 194 | { 195 | NativeArray CurrentlyCastingComponent = batchInChunk.GetNativeArray(CurrentlyCastingChunk); 196 | NativeArray targets = batchInChunk.GetNativeArray(TargetChunk); 197 | NativeArray entities = batchInChunk.GetNativeArray(EntityChunk); 198 | EffectContextBuilder.PrepareChunk(batchInChunk); 199 | 200 | // removing this result in exception for more than 2 chunks whatever the index passed to BeginForEachIndex 201 | ConsumerWriter.PatchMinMaxRange(batchIndex); 202 | ConsumerWriter.BeginForEachIndex(batchIndex); 203 | for (int entityIndex = 0; entityIndex < batchInChunk.Count; ++entityIndex) 204 | { 205 | CurrentlyCasting cc = CurrentlyCastingComponent[entityIndex]; 206 | NativeParallelMultiHashMap.Enumerator effectEnumerator = EffectMap.GetValuesForKey(cc.abilityGuid); 207 | while (effectEnumerator.MoveNext()) 208 | { 209 | EFFECT effect = effectEnumerator.Current; 210 | if (cc.castTime < 0) 211 | { 212 | ConsumerWriter.Write(effect); 213 | Entity targetEntity = FindTargets(ref targets, ref entities, entityIndex, effect.Affects); 214 | ConsumerWriter.Write(EffectContextBuilder.BuildEffectContext(entityIndex)); 215 | ConsumerWriter.Write(1); 216 | ConsumerWriter.Write(targetEntity); 217 | } 218 | } 219 | effectEnumerator.Dispose(); 220 | } 221 | ConsumerWriter.EndForEachIndex(); 222 | } 223 | 224 | #endregion Public Methods 225 | 226 | #region Private Methods 227 | 228 | private static Entity FindTargets(ref NativeArray targets, ref NativeArray entities, int entityIndex, TargetingMode efffectTargetingMode) 229 | { 230 | return efffectTargetingMode == TargetingMode.Target ? targets[entityIndex].Value : entities[entityIndex]; 231 | } 232 | 233 | #endregion Private Methods 234 | } 235 | 236 | #endregion Public Structs 237 | } 238 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/AbilityEffectTriggerSystems.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3b689af224936864f822731588b0ae66 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/AbilitySystemGroup.cs: -------------------------------------------------------------------------------- 1 | using Unity.Entities; 2 | 3 | namespace WaynGroup.Mgm.Ability 4 | { 5 | //[UpdateInGroup(typeof(FixedStepSimulationSystemGroup))] 6 | public class AbilitySystemGroup : ComponentSystemGroup 7 | { 8 | } 9 | 10 | [UpdateInGroup(typeof(AbilitySystemGroup))] 11 | public class AbilityUpdateSystemGroup : ComponentSystemGroup 12 | { 13 | } 14 | 15 | [UpdateAfter(typeof(AbilityUpdateSystemGroup))] 16 | [UpdateInGroup(typeof(AbilitySystemGroup))] 17 | public class AbilityTriggerSystemGroup : ComponentSystemGroup 18 | { 19 | } 20 | 21 | [UpdateAfter(typeof(AbilityUpdateSystemGroup))] 22 | [UpdateInGroup(typeof(AbilitySystemGroup))] 23 | public class AbilityCostsSystemGroup : ComponentSystemGroup 24 | { 25 | } 26 | 27 | [UpdateInGroup(typeof(AbilityCostsSystemGroup))] 28 | public class AbilityCostsCheckerSystemGroup : ComponentSystemGroup 29 | { 30 | } 31 | 32 | [UpdateInGroup(typeof(AbilityCostsSystemGroup))] 33 | [UpdateAfter(typeof(AbilityCostsCheckerSystemGroup))] 34 | public class AbilityCostsConsumerSystemGroup : ComponentSystemGroup 35 | { 36 | } 37 | 38 | [UpdateAfter(typeof(AbilityTriggerSystemGroup))] 39 | [UpdateInGroup(typeof(AbilitySystemGroup))] 40 | public class AbilityConsumerSystemGroup : ComponentSystemGroup 41 | { 42 | } 43 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/AbilitySystemGroup.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2f6987ead20d6914e9083b305af84432 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/AbilityTimingsCache.cs: -------------------------------------------------------------------------------- 1 | using Unity.Entities; 2 | 3 | namespace WaynGroup.Mgm.Ability 4 | { 5 | public struct AbilityTimingsCache : ICacheComponent 6 | { 7 | #region Public Properties 8 | 9 | public BlobAssetReference> Cache { get; set; } 10 | 11 | #endregion Public Properties 12 | 13 | #region Public Methods 14 | 15 | public void Dispose() 16 | { 17 | if (Cache.IsCreated) Cache.Dispose(); 18 | } 19 | 20 | #endregion Public Methods 21 | } 22 | 23 | public struct AbilitySpawnableCache : ICacheComponent 24 | { 25 | #region Public Properties 26 | 27 | public BlobAssetReference> Cache { get; set; } 28 | 29 | #endregion Public Properties 30 | 31 | #region Public Methods 32 | 33 | public void Dispose() 34 | { 35 | if (Cache.IsCreated) Cache.Dispose(); 36 | } 37 | 38 | #endregion Public Methods 39 | } 40 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/AbilityTimingsCache.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f48b8993f83bb6a459d95771c24050e3 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/AbilityUpdateRangeSystem.cs: -------------------------------------------------------------------------------- 1 | using Unity.Burst; 2 | using Unity.Collections; 3 | using Unity.Entities; 4 | using Unity.Mathematics; 5 | using Unity.Transforms; 6 | 7 | namespace WaynGroup.Mgm.Ability 8 | { 9 | /// 10 | /// This system will determine if the current target is in range of a ability. 11 | /// 12 | [UpdateInGroup(typeof(AbilityUpdateSystemGroup))] 13 | [BurstCompile] 14 | public struct AbilityUpdateRangeSystem : ISystem 15 | { 16 | #region Private Fields 17 | 18 | private EntityQuery _cache; 19 | private EntityQuery _query; 20 | 21 | private ComponentTypeHandle _targetTypeHande; 22 | private ComponentTypeHandle _translationTypeHande; 23 | private ComponentTypeHandle _abilityInputTypeHandle; 24 | 25 | #endregion Private Fields 26 | 27 | #region Public Methods 28 | [BurstCompile] 29 | public void OnCreate(ref SystemState state) 30 | { 31 | NativeArray types = new NativeArray(1, Allocator.Temp); 32 | types[0] = ComponentType.ReadWrite(); 33 | _query = state.GetEntityQuery(types); 34 | types[0] = ComponentType.ReadOnly(); 35 | _cache = state.GetEntityQuery(types); 36 | types.Dispose(); 37 | 38 | state.RequireSingletonForUpdate(); 39 | 40 | 41 | _targetTypeHande = state.GetComponentTypeHandle(true); 42 | _translationTypeHande = state.GetComponentTypeHandle(true); 43 | _abilityInputTypeHandle = state.GetComponentTypeHandle(false); 44 | } 45 | 46 | [BurstCompile] 47 | public void OnDestroy(ref SystemState state) 48 | { 49 | } 50 | [BurstCompile] 51 | public void OnUpdate(ref SystemState state) 52 | { 53 | _abilityInputTypeHandle.Update(ref state); 54 | _translationTypeHande.Update(ref state); 55 | _targetTypeHande.Update(ref state); 56 | 57 | 58 | state.Dependency = new UpdateRangeJob() 59 | { 60 | AbilityInputChunk = _abilityInputTypeHandle, 61 | Cache = _cache.GetSingleton(), 62 | Position = state.GetComponentDataFromEntity(true), 63 | TargetChunk = _targetTypeHande, 64 | TranslationChunk = _translationTypeHande 65 | }.ScheduleParallel(_query, state.Dependency); 66 | } 67 | 68 | #endregion Public Methods 69 | 70 | #region Public Structs 71 | 72 | [BurstCompile] 73 | public struct UpdateRangeJob : IJobEntityBatch 74 | { 75 | #region Public Fields 76 | 77 | public ComponentTypeHandle AbilityInputChunk; 78 | [ReadOnly] public SquaredRangeCache Cache; 79 | [ReadOnly] public ComponentDataFromEntity Position; 80 | [ReadOnly] public ComponentTypeHandle TargetChunk; 81 | [ReadOnly] public ComponentTypeHandle TranslationChunk; 82 | 83 | #endregion Public Fields 84 | 85 | #region Public Methods 86 | 87 | public void Execute(ArchetypeChunk batchInChunk, int batchIndex) 88 | { 89 | NativeArray targets = batchInChunk.GetNativeArray(TargetChunk); 90 | NativeArray translations = batchInChunk.GetNativeArray(TranslationChunk); 91 | NativeArray inputs = batchInChunk.GetNativeArray(AbilityInputChunk); 92 | 93 | ref BlobMultiHashMap cacheMap = ref Cache.Cache.Value; 94 | for (int entityIndex = 0; entityIndex < batchInChunk.Count; ++entityIndex) 95 | { 96 | AbilityInput ai = inputs[entityIndex]; 97 | // only check range when trying to activate an ability 98 | if (ai.IsEnabled()) 99 | { 100 | Entity target = targets[entityIndex].Value; 101 | 102 | if (!Position.HasComponent(target)) continue; 103 | float3 targetPosition = Position[target].Position; 104 | float3 casterPosition = translations[entityIndex].Value; 105 | 106 | float distance = math.distancesq(casterPosition, targetPosition); 107 | Range range = cacheMap.GetValuesForKey(ai.AbilityId)[0]; 108 | ai.AddRestriction((uint)math.select(2, 0, range.Min <= distance && distance <= range.Max)); 109 | inputs[entityIndex] = ai; 110 | } 111 | } 112 | } 113 | 114 | #endregion Public Methods 115 | } 116 | 117 | #endregion Public Structs 118 | } 119 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/AbilityUpdateRangeSystem.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5041bc69977569943957951b562c9fe8 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/AbilityUpdateStateAndTimingsSystem.cs: -------------------------------------------------------------------------------- 1 | using Unity.Burst; 2 | using Unity.Burst.CompilerServices; 3 | using Unity.Collections; 4 | using Unity.Entities; 5 | using UnityEngine; 6 | 7 | namespace WaynGroup.Mgm.Ability 8 | { 9 | 10 | [BurstCompile] 11 | public struct AbilityUpdateStateAndTimingsSystem : ISystem 12 | { 13 | #region Private Fields 14 | 15 | private EntityQuery _queryCooldown; 16 | private EntityQuery _queryCasting; 17 | private EntityQuery _cache; 18 | 19 | #endregion Private Fields 20 | 21 | #region Public Methods 22 | 23 | public void OnCreate(ref SystemState state) 24 | { 25 | _queryCooldown = state.GetEntityQuery(typeof(AbilityCooldownBufferElement)); 26 | _queryCasting = state.GetEntityQuery(typeof(AbilitiesMapIndex), typeof(AbilityCooldownBufferElement), typeof(CurrentlyCasting), typeof(AbilityInput)); 27 | _cache = state.GetEntityQuery(ComponentType.ReadOnly(typeof(AbilityTimingsCache))); 28 | state.RequireSingletonForUpdate(); 29 | } 30 | 31 | [BurstCompile] 32 | public void OnUpdate(ref SystemState state) 33 | { 34 | // Cooldown all abilities 35 | state.Dependency = new AbilityUpdpdateCooldownJob() 36 | { 37 | DeltaTime = state.WorldUnmanaged.CurrentTime.DeltaTime, 38 | AbilityCooldownBufferChunk = state.GetBufferTypeHandle() 39 | }.ScheduleParallel(_queryCooldown, state.Dependency); 40 | 41 | state.Dependency = new AbilityUpdateCastingJob() 42 | { 43 | DeltaTime = state.WorldUnmanaged.CurrentTime.DeltaTime, 44 | Cache = _cache.GetSingleton(), 45 | AbilityMapIndexChunk = state.GetComponentTypeHandle(true), 46 | CurrentlyCastingChunk = state.GetComponentTypeHandle(), 47 | AbilityInputChunk = state.GetComponentTypeHandle(), 48 | AbilityCooldownBufferChunk = state.GetBufferTypeHandle() 49 | }.ScheduleParallel(_queryCasting, state.Dependency); 50 | } 51 | 52 | public void OnDestroy(ref SystemState state) 53 | { 54 | } 55 | 56 | #endregion Public Methods 57 | 58 | #region Public Structs 59 | 60 | [BurstCompile] 61 | public struct AbilityUpdateCastingJob : IJobChunk 62 | { 63 | #region Public Fields 64 | 65 | [ReadOnly] public float DeltaTime; 66 | [ReadOnly] public AbilityTimingsCache Cache; 67 | [ReadOnly] public ComponentTypeHandle AbilityMapIndexChunk; 68 | 69 | public ComponentTypeHandle CurrentlyCastingChunk; 70 | public ComponentTypeHandle AbilityInputChunk; 71 | public BufferTypeHandle AbilityCooldownBufferChunk; 72 | 73 | #endregion Public Fields 74 | 75 | #region Public Methods 76 | 77 | public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) 78 | { 79 | NativeArray abilityMapIndexer = chunk.GetNativeArray(AbilityMapIndexChunk); 80 | BufferAccessor abilityCooldownBufferElementAccessor = chunk.GetBufferAccessor(AbilityCooldownBufferChunk); 81 | NativeArray currentlyCastingArray = chunk.GetNativeArray(CurrentlyCastingChunk); 82 | NativeArray abilityInputArray = chunk.GetNativeArray(AbilityInputChunk); 83 | 84 | ref BlobMultiHashMap timmingCacheMap = ref Cache.Cache.Value; 85 | 86 | for (int entityIndex = 0; entityIndex < chunk.Count; ++entityIndex) 87 | { 88 | CurrentlyCasting cc = currentlyCastingArray[entityIndex]; 89 | AbilityInput ai = abilityInputArray[entityIndex]; 90 | // if casting 91 | // want to start casting while casting ? add restriction 92 | if (ai.IsEnabled() && cc.IsCasting) 93 | { 94 | ai.AddRestriction(8); 95 | } 96 | if (cc.castTime < 0) 97 | { 98 | // If casting finished, star coolingdown 99 | var entityIndexToGuid = abilityMapIndexer[entityIndex]; 100 | ref BlobMultiHashMap guidToIndex = ref entityIndexToGuid.guidToIndex.Value; 101 | int index = guidToIndex.GetValuesForKey(cc.abilityGuid)[0]; 102 | var timmings = timmingCacheMap.GetValuesForKey(cc.abilityGuid)[0]; 103 | 104 | NativeArray acbe = abilityCooldownBufferElementAccessor[entityIndex].AsNativeArray(); 105 | AbilityCooldownBufferElement abilityCooldown = acbe[index]; 106 | abilityCooldown.CooldownTime = timmings.CoolDown; 107 | acbe[index] = abilityCooldown; 108 | // and stop casting 109 | cc.castTime = float.NaN; 110 | } 111 | if (cc.IsCasting) 112 | { 113 | // Reduce casting time left 114 | cc.castTime -= DeltaTime; 115 | } 116 | 117 | // if applicable (enabled and no retriction) 118 | if (ai.IsApplicable() && !cc.IsCasting) 119 | { 120 | // Start casting 121 | cc.abilityGuid = ai.AbilityId; 122 | cc.castTime = timmingCacheMap.GetValuesForKey(cc.abilityGuid)[0].Cast; 123 | } 124 | 125 | abilityInputArray[entityIndex] = ai; 126 | currentlyCastingArray[entityIndex] = cc; 127 | } 128 | } 129 | 130 | #endregion Public Methods 131 | } 132 | 133 | [BurstCompile] 134 | public struct AbilityUpdpdateCooldownJob : IJobChunk 135 | { 136 | #region Public Fields 137 | 138 | [ReadOnly] public float DeltaTime; 139 | 140 | public BufferTypeHandle AbilityCooldownBufferChunk; 141 | 142 | #endregion Public Fields 143 | 144 | #region Public Methods 145 | 146 | public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) 147 | { 148 | BufferAccessor abilityBufferAccessor = chunk.GetBufferAccessor(AbilityCooldownBufferChunk); 149 | 150 | for (int entityIndex = 0; entityIndex < chunk.Count; ++entityIndex) 151 | { 152 | NativeArray sbArray = abilityBufferAccessor[entityIndex].AsNativeArray(); 153 | Cooldown(sbArray, DeltaTime); 154 | } 155 | 156 | void Cooldown(NativeArray sbArray, float DeltaTime) 157 | { 158 | for (int i = 0; i < sbArray.Length; i++) 159 | { 160 | var ability = sbArray[i]; 161 | ability.CooldownTime -= DeltaTime; 162 | sbArray[i] = ability; 163 | } 164 | } 165 | } 166 | 167 | #endregion Public Methods 168 | } 169 | 170 | #endregion Public Structs 171 | } 172 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/AbilityUpdateStateAndTimingsSystem.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 94155c0c9564ce6488aa217ce52f92e4 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/AddressableAbilityCatalogSystem.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7721883c30636684687415f72d63dc4a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/CooldownRestrictionSystem.cs: -------------------------------------------------------------------------------- 1 | using Unity.Entities; 2 | 3 | namespace WaynGroup.Mgm.Ability 4 | { 5 | [UpdateInGroup(typeof(AbilityUpdateSystemGroup))] 6 | public partial class CooldownRestrictionSystem : SystemBase 7 | { 8 | #region Protected Methods 9 | 10 | protected override void OnUpdate() 11 | { 12 | Entities.ForEach((ref AbilityInput abilityInput, in DynamicBuffer cooldownBuffer, 13 | in AbilitiesMapIndex indexMap) => 14 | { 15 | ref BlobMultiHashMap map = ref indexMap.guidToIndex.Value; 16 | var bufferIndex = map.GetValuesForKey(abilityInput.AbilityId)[0]; 17 | if (cooldownBuffer[bufferIndex].CooldownTime > 0) 18 | abilityInput.AddRestriction(16); 19 | }).WithBurst().ScheduleParallel(); 20 | } 21 | 22 | #endregion Protected Methods 23 | } 24 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/CooldownRestrictionSystem.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5f3ba0de2bacd8a42bbd98955b9b0755 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/CurrentlyCasting.cs: -------------------------------------------------------------------------------- 1 | using Unity.Entities; 2 | 3 | namespace WaynGroup.Mgm.Ability 4 | { 5 | public struct CurrentlyCasting : ISystemStateComponentData 6 | { 7 | #region Public Fields 8 | 9 | public float castTime; 10 | public uint abilityGuid; 11 | 12 | #endregion Public Fields 13 | 14 | #region Public Properties 15 | 16 | public bool IsCasting => !float.NaN.Equals(castTime); 17 | 18 | #endregion Public Properties 19 | } 20 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/CurrentlyCasting.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 725a115d9557b9d43b4b920cc0759a7a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/ICacheComponent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Unity.Entities; 3 | 4 | namespace WaynGroup.Mgm.Ability 5 | { 6 | public interface ICacheComponent : IComponentData, IDisposable 7 | { 8 | } 9 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/ICacheComponent.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ec997893efe8c5e459ad0b188aaa0abb 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/IEffectContext.cs: -------------------------------------------------------------------------------- 1 | namespace WaynGroup.Mgm.Ability 2 | { 3 | public interface IEffectContext 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/IEffectContext.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 647288f6410351949a979790be444463 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/IEffectContextWriter.cs: -------------------------------------------------------------------------------- 1 | using Unity.Entities; 2 | 3 | namespace WaynGroup.Mgm.Ability 4 | { 5 | public interface IEffectContextWriter 6 | where EFFECT_CTX : struct, IEffectContext 7 | { 8 | #region Public Methods 9 | 10 | /// 11 | /// Method to cash the necessary component data array ([ReadOnly]) used to populate the effect context in the BuildEffectContext method. 12 | /// 13 | /// 14 | void PrepareChunk(ArchetypeChunk chunk); 15 | 16 | EFFECT_CTX BuildEffectContext(int casterEntityIndex); 17 | 18 | #endregion Public Methods 19 | } 20 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/IEffectContextWriter.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c000b725daedd184ab83bb84655b62ca 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/SquaredRangeCache.cs: -------------------------------------------------------------------------------- 1 | using Unity.Entities; 2 | 3 | namespace WaynGroup.Mgm.Ability 4 | { 5 | public struct SquaredRangeCache : ICacheComponent 6 | { 7 | #region Public Properties 8 | 9 | public BlobAssetReference> Cache { get; set; } 10 | 11 | #endregion Public Properties 12 | 13 | #region Public Methods 14 | 15 | public void Dispose() 16 | { 17 | if (Cache.IsCreated) Cache.Dispose(); 18 | } 19 | 20 | #endregion Public Methods 21 | } 22 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Systems/SquaredRangeCache.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 33731e2fffb90f34fa6e1601251e43d5 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/UI.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1cf828c6adb2b5748aa5cd165fdaad6b 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Scripts/UI/AbilityBookUIElement.cs: -------------------------------------------------------------------------------- 1 | using Unity.Entities; 2 | 3 | using UnityEngine; 4 | using UnityEngine.UIElements; 5 | 6 | namespace WaynGroup.Mgm.Ability.UI 7 | { 8 | internal class AbilityBookUIElement : VisualElement 9 | { 10 | #region Private Fields 11 | 12 | private VisualElement _bookRoot; 13 | 14 | #endregion Private Fields 15 | 16 | #region Public Constructors 17 | 18 | public AbilityBookUIElement() 19 | { 20 | VisualTreeAsset visualTree = Resources.Load("AbilityBookUIElement"); 21 | visualTree.CloneTree(this); 22 | _bookRoot = this; 23 | } 24 | 25 | #endregion Public Constructors 26 | 27 | #region Public Methods 28 | 29 | public void Populate(Entity owner, EntityManager entityManager) 30 | { 31 | _bookRoot.Clear(); 32 | var abilitiesMapIndex = entityManager.GetComponentData(owner); 33 | 34 | ref BlobMultiHashMap indexToGuid = ref abilitiesMapIndex.indexToGuid.Value; 35 | 36 | int abilityCount = indexToGuid.ValueCount.Value; 37 | for (int i = 0; i < abilityCount; i++) 38 | { 39 | AbilityUIElement uiAbility = new AbilityUIElement(); 40 | var array = indexToGuid.GetValuesForKey(i); 41 | if (!array.IsCreated) 42 | { 43 | Debug.Log("Fail"); 44 | continue; 45 | } 46 | uint abilityId = array[0]; 47 | uiAbility.AssignAbility(owner, abilityId, entityManager); 48 | _bookRoot.Add(uiAbility); 49 | } 50 | } 51 | 52 | #endregion Public Methods 53 | 54 | #region Public Classes 55 | 56 | public new class UxmlFactory : UxmlFactory 57 | { 58 | } 59 | 60 | public new class UxmlTraits : VisualElement.UxmlTraits 61 | { } 62 | 63 | #endregion Public Classes 64 | } 65 | } -------------------------------------------------------------------------------- /Runtime/Scripts/UI/AbilityBookUIElement.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b47c05216bb926f42936f0df6e4e524e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/UI/AbilityUIElement.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | using Unity.Entities; 4 | using Unity.Mathematics; 5 | 6 | using UnityEngine; 7 | using UnityEngine.UIElements; 8 | 9 | namespace WaynGroup.Mgm.Ability.UI 10 | { 11 | public interface ICommand 12 | { 13 | #region Public Methods 14 | 15 | void Execute(); 16 | 17 | #endregion Public Methods 18 | } 19 | 20 | public struct AbilityUICommand : ICommand 21 | { 22 | #region Public Fields 23 | 24 | public Entity CommandedEntity; 25 | public uint AbilityID; 26 | public EntityManager EntityManager; 27 | 28 | #endregion Public Fields 29 | 30 | #region Public Methods 31 | 32 | public void Execute() 33 | { 34 | if (!EntityManager.Exists(CommandedEntity) || !EntityManager.HasComponent(CommandedEntity)) return; 35 | var ai = new AbilityInput(AbilityID); 36 | ai.Enable(); 37 | EntityManager.SetComponentData(CommandedEntity, ai); 38 | } 39 | 40 | #endregion Public Methods 41 | } 42 | 43 | internal class AbilityUIElement : EntityOwnedUpdatableVisualElement 44 | { 45 | #region Private Fields 46 | 47 | private ICommand _command; 48 | 49 | private Texture2D Icon; 50 | 51 | private ScriptableAbility _ability; 52 | 53 | private ProgressBar _CoolDown; 54 | 55 | private int _cachedAbilityIndex; 56 | 57 | #endregion Private Fields 58 | 59 | #region Public Constructors 60 | 61 | public AbilityUIElement() 62 | { 63 | VisualTreeAsset visualTree = Resources.Load("AbilityUIElement"); 64 | visualTree.CloneTree(this); 65 | VisualElement root = this.Q(name: "Shape"); 66 | _CoolDown = this.Q(name: "coolDown"); 67 | _CoolDown.Value = 0; 68 | _CoolDown.SetOrientation(FlexDirection.ColumnReverse); 69 | _command = default; 70 | this.AddManipulator(new DragableAbility()); 71 | } 72 | 73 | #endregion Public Constructors 74 | 75 | #region Public Properties 76 | 77 | public bool IsAssigned => !_command.Equals(default); 78 | 79 | #endregion Public Properties 80 | 81 | #region Public Methods 82 | 83 | public AbilityUIElement Clone() 84 | { 85 | AbilityUIElement copy = new AbilityUIElement(); 86 | copy.AssignAbility(_owner, _ability.Id, _entityManager); 87 | return copy; 88 | } 89 | 90 | public void AssignAbility(Entity owner, uint abilityID, EntityManager entityManager) 91 | { 92 | _entityManager = entityManager; 93 | entityManager.World.GetOrCreateSystem().OnAbilityUpdate += UpdateCalatoguedInfo; 94 | 95 | _owner = owner; 96 | 97 | _command = new AbilityUICommand() 98 | { 99 | CommandedEntity = owner, 100 | AbilityID = abilityID, 101 | EntityManager = entityManager 102 | }; 103 | var abilitiesMapIndex = entityManager.GetComponentData(owner); 104 | 105 | ref BlobMultiHashMap guidToIndex = ref abilitiesMapIndex.guidToIndex.Value; 106 | _cachedAbilityIndex = guidToIndex.GetValuesForKey(abilityID)[0]; 107 | 108 | // Need to force the first update on assignement because the ability assignement happens after the first catalogue update 109 | UpdatedCachedInfo(entityManager.World.GetOrCreateSystem().AbilityCatalog, abilityID); 110 | 111 | RegisterCallback(MouseOver); 112 | RegisterCallback(MouseUnOver); 113 | } 114 | 115 | public void ExecuteAction() 116 | { 117 | _command.Execute(); 118 | } 119 | 120 | public void UnassignAbility() 121 | { 122 | _command = default; 123 | SetIcon(null); 124 | 125 | this.Q