From 6ef010c6ef7016c6e2e6e59cc3ef8eb59fc7091d Mon Sep 17 00:00:00 2001 From: Oleg Morozov Date: Thu, 29 Dec 2022 17:39:36 +0300 Subject: [PATCH 1/5] =?UTF-8?q?=F0=9F=9A=80=20NuGet=20Support?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README_NUGET.md | 283 +++++++++++++++++++++++++++++++++++++++ Scellecs.Morpeh.csproj | 112 +++++++++++++++- Scellecs.Morpeh.sln | 16 +++ Scellecs.Morpeh.sln.meta | 7 + 4 files changed, 415 insertions(+), 3 deletions(-) create mode 100644 README_NUGET.md create mode 100644 Scellecs.Morpeh.sln create mode 100644 Scellecs.Morpeh.sln.meta diff --git a/README_NUGET.md b/README_NUGET.md new file mode 100644 index 00000000..edf473e7 --- /dev/null +++ b/README_NUGET.md @@ -0,0 +1,283 @@ +# Morpeh [![License](https://img.shields.io/github/license/scellecs/morpeh?color=3750c1&style=flat-square)](LICENSE.md) [![Unity](https://img.shields.io/badge/Unity-2020.3+-2296F3.svg?color=3750c1&style=flat-square)](https://unity.com/) [![Version](https://img.shields.io/github/package-json/v/scellecs/morpeh?color=3750c1&style=flat-square)](package.json) +๐ŸŽฒ **ECS Framework for Unity Game Engine and .Net Platform** + +* Simple Syntax. +* Plug & Play Installation. +* No code generation. +* Structure-Based and Cache-Friendly. + +## ๐Ÿ“– Table of Contents + +* [Migration](#-migration-to-new-version) +* [Introduction](#-introduction) + * [Base concept of ECS pattern](#-base-concept-of-ecs-pattern) + * [Advanced](#-advanced) + * [Component Disposing](#-component-disposing) +* [Examples](#-examples) +* [Games](#-games) +* [License](#-license) +* [Contacts](#-contacts) + +## โœˆ๏ธ Migration To New Version + +English version: [Migration Guide](MIGRATION.md) +Russian version: [ะ“ะฐะนะด ะฟะพ ะผะธะณั€ะฐั†ะธะธ](MIGRATION_RU.md) + +## ๐Ÿ“– Introduction +### ๐Ÿ“˜ Base concept of ECS pattern + +#### ๐Ÿ”– Entity +Container of components. +Has a set of methods for add, get, set, remove components. +It is reference type. Each entity is unique and not pooled. Only entity IDs are reused. + +```c# +var entity = this.World.CreateEntity(); + +ref var addedHealthComponent = ref entity.AddComponent(); +ref var gottenHealthComponent = ref entity.GetComponent(); + +//if you remove last component on entity it will be destroyd on next world.Commit() +bool removed = entity.RemoveComponent(); +entity.SetComponent(new HealthComponent {healthPoints = 100}); + +bool hasHealthComponent = entity.Has(); + +var newEntity = this.World.CreateEntity(); +//after migration entity has no components, so it will be destroyd on next world.Commit() +entity.MigrateTo(newEntity); +``` + + +#### ๐Ÿ”– Component +Components are types which include only data. +In Morpeh components are value types for performance purposes. +```c# +public struct HealthComponent : IComponent { + public int healthPoints; +} +``` + +#### ๐Ÿ”– System + +Types that process entities with a specific set of components. +Entities are selected using a filter. + +All systems are represented by interfaces, but for convenience, there are ScriptableObject classes that make it easier to work with the inspector and `Installer`. +Such classes are the default tool, but you can write pure classes that implement the interface, but then you need to use the `SystemsGroup` API instead of the `Installer`. + +```c# +public class HealthSystem : ISystem { + public World World { get; set; } + + private Filter filter; + + public void OnAwake() { + this.filter = this.World.Filter.With(); + } + + public void OnUpdate(float deltaTime) { + foreach (var entity in this.filter) { + ref var healthComponent = ref entity.GetComponent(); + healthComponent.healthPoints += 1; + } + } + + public void Dispose() { + } +} +``` + +All systems types: +* `IInitializer` & `Initializer` - have only OnAwake and Dispose methods, convenient for executing startup logic +* `ISystem` & `UpdateSystem` +* `IFixedSystem` & `FixedUpdateSystem` +* `ILateSystem` & `LateUpdateSystem` +* `ICleanupSystem` & `CleanupSystem` + +#### ๐Ÿ”– SystemsGroup + +The type that contains the systems. +There is an `Installer` wrapper to work in the inspector, but if you want to control everything from code, you can use the systems group directly. + +```c# +var newWorld = World.Create(); + +var newSystem = new HealthSystem(); +var newInitializer = new HealthInitializer(); + +var systemsGroup = newWorld.CreateSystemsGroup(); +systemsGroup.AddSystem(newSystem); +systemsGroup.AddInitializer(newInitializer); + +//it is bad practice to turn systems off and on, but sometimes it is very necessary for debugging +systemsGroup.DisableSystem(newSystem); +systemsGroup.EnableSystem(newSystem); + +systemsGroup.RemoveSystem(newSystem); +systemsGroup.RemoveInitializer(newInitializer); + +newWorld.AddSystemsGroup(order: 0, systemsGroup); +newWorld.RemoveSystemsGroup(systemsGroup); +``` + +#### ๐Ÿ”– World +A type that contains entities, components stashes, systems and root filter. +```c# +var newWorld = World.Create(); +//a variable that specifies whether the world should be updated automatically by the game engine. +//if set to false, then you can update the world manually. +//and can also be used for game pauses by changing the value of this variable. +newWorld.UpdateByUnity = true; + +var newEntity = newWorld.CreateEntity(); +newWorld.RemoveEntity(newEntity); + +var systemsGroup = newWorld.CreateSystemsGroup(); +systemsGroup.AddSystem(new HealthSystem()); + +newWorld.AddSystemsGroup(order: 0, systemsGroup); +newWorld.RemoveSystemsGroup(systemsGroup); + +var filter = newWorld.Filter.With(); + +var healthCache = newWorld.GetStash(); +var reflectionHealthCache = newWorld.GetReflectionStash(typeof(HealthComponent)); + +//manually world updates +newWorld.Update(Time.deltaTime); +newWorld.FixedUpdate(Time.fixedDeltaTime); +newWorld.LateUpdate(Time.deltaTime); +newWorld.CleanupUpdate(Time.deltaTime); + +//apply all entity changes, filters will be updated. +//automatically invoked between systems +newWorld.Commit(); +``` + +#### ๐Ÿ”– Filter +A type that contains entities constrained by conditions With and/or Without. +You can chain them in any order and quantity. +```c# +var filter = this.World.Filter.With() + .With() + .Without(); + +var firstEntityOrException = filter.First(); +var firstEntityOrNull = filter.FirstOrDefault(); + +bool filterIsEmpty = filter.IsEmpty(); +int filterLengthCalculatedOnCall = filter.GetLengthSlow(); + +``` + +#### ๐Ÿ”– Stash +A type that contains components. +You can get components and do other operations directly from the stash, because entity methods look up the stash each time on call. +However, such code is harder to read. +```c# +var healthStash = this.World.GetStash(); +var entity = this.World.CreateEntity(); + +ref var addedHealthComponent = ref healthStash.Add(entity); +ref var gottenHealthComponent = ref healthStash.Get(entity); + +bool removed = healthStash.Remove(entity); + +healthStash.Set(entity, new HealthComponent {healthPoints = 100}); + +bool hasHealthComponent = healthStash.Has(entity); + +var newEntity = this.World.CreateEntity(); +//transfers a component from one entity to another +healthStash.Migrate(from: entity, to: newEntity); + +//not a generic variation of stash, so we can only do a limited set of operations +var reflectionHealthCache = newWorld.GetReflectionStash(typeof(HealthComponent)); + +//set default(HealthComponent) to entity +reflectionHealthCache.Set(entity); + +bool removed = reflectionHealthCache.Remove(entity); + +bool hasHealthComponent = reflectionHealthCache.Has(entity); +``` + +--- + + + +### ๐Ÿ“– Advanced + +#### ๐Ÿงน Component Disposing + +Sometimes it becomes necessary to clear component values. +For this, it is enough that the component implements `IDisposable`. For example: + +```c# +public struct PlayerView : IComponent, IDisposable { + public GameObject value; + + public void Dispose() { + Object.Destroy(value); + } +} +``` + +The initializer or system needs to mark the stash as disposable. For example: + +```c# +public class PlayerViewDisposeInitializer : Initializer { + public override void OnAwake() { + this.World.GetStash().AsDisposable(); + } +} +``` + +or + +```c# +public class PlayerViewSystem : UpdateSystem { + public override void OnAwake() { + this.World.GetStash().AsDisposable(); + } + + public override void OnUpdate(float deltaTime) { + ... + } +} +``` + +Now, when the component is removed from the entity, the `Dispose()` method will be called on the `PlayerView` component. + +## ๐Ÿ“š Examples + +* [**Tanks**](https://github.com/scellecs/morpeh.examples.tanks) by *SH42913* +* [**Ping Pong**](https://github.com/scellecs/morpeh.examples.pong) by *SH42913* + +## ๐Ÿ”ฅ Games + +* **Zombie City** by *GreenButtonGames* + [Android](https://play.google.com/store/apps/details?id=com.greenbuttongames.zombiecity) [iOS](https://apps.apple.com/us/app/zombie-city-master/id1543420906) + + +* **Fish Idle** by *GreenButtonGames* + [Android](https://play.google.com/store/apps/details?id=com.greenbuttongames.FishIdle) [iOS](https://apps.apple.com/us/app/fish-idle-hooked-tycoon/id1534396279) + + +* **Stickman of Wars: RPG Shooters** by *Multicast Games* + [Android](https://play.google.com/store/apps/details?id=com.multicastgames.sow3) [iOS](https://apps.apple.com/us/app/stickman-of-wars-rpg-shooters/id1620422798) + + +* **One State RP - Life Simulator** by *Chillbase* + [Android](https://play.google.com/store/apps/details?id=com.Chillgaming.oneState) [iOS](https://apps.apple.com/us/app/one-state-rp-online/id1597760047) + +## ๐Ÿ“˜ License + +๐Ÿ“„ [MIT License](LICENSE.md) + +## ๐Ÿ’ฌ Contacts + +โœ‰๏ธ Telegram: [olegmrzv](https://t.me/olegmrzv) +๐Ÿ“ง E-Mail: [benjminmoore@gmail.com](mailto:benjminmoore@gmail.com) +๐Ÿ‘ฅ Telegram Community RU: [Morpeh ECS Development](https://t.me/morpeh_development_chat) diff --git a/Scellecs.Morpeh.csproj b/Scellecs.Morpeh.csproj index b8aa5d0d..b1aaa1cf 100644 --- a/Scellecs.Morpeh.csproj +++ b/Scellecs.Morpeh.csproj @@ -3,22 +3,67 @@ netstandard2.1 true + true + 2022.2.0 + Scellecs.Morpeh + Oleg Morozov, Igor Boyko + ECS Framework for Unity Game Engine and .Net Platform + Copyright (c) 2022 Oleg Morozov, Igor Boyko + https://github.com/scellecs/morpeh/blob/master/LICENSE.md + logo.png + README_NUGET.md + https://github.com/scellecs/morpeh + ecs, unity, gamedev + Scellecs + Morpeh - + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + - + + + + + + @@ -72,6 +117,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Scellecs.Morpeh.sln b/Scellecs.Morpeh.sln new file mode 100644 index 00000000..8455b501 --- /dev/null +++ b/Scellecs.Morpeh.sln @@ -0,0 +1,16 @@ +๏ปฟ +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scellecs.Morpeh", "Scellecs.Morpeh.csproj", "{99D1D230-B89C-40B9-AA59-B1F016008E7D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {99D1D230-B89C-40B9-AA59-B1F016008E7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {99D1D230-B89C-40B9-AA59-B1F016008E7D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {99D1D230-B89C-40B9-AA59-B1F016008E7D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {99D1D230-B89C-40B9-AA59-B1F016008E7D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/Scellecs.Morpeh.sln.meta b/Scellecs.Morpeh.sln.meta new file mode 100644 index 00000000..7d94bc98 --- /dev/null +++ b/Scellecs.Morpeh.sln.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 754504418a79e47d28e43908e204fb26 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From 02447ecff552bb5c32032ced5bb2e2596a7a6b8b Mon Sep 17 00:00:00 2001 From: Oleg Morozov Date: Thu, 29 Dec 2022 17:41:51 +0300 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=9A=80=20NuGet=20Support?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README_NUGET.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/README_NUGET.md b/README_NUGET.md index edf473e7..c7f009c3 100644 --- a/README_NUGET.md +++ b/README_NUGET.md @@ -7,8 +7,6 @@ * Structure-Based and Cache-Friendly. ## ๐Ÿ“– Table of Contents - -* [Migration](#-migration-to-new-version) * [Introduction](#-introduction) * [Base concept of ECS pattern](#-base-concept-of-ecs-pattern) * [Advanced](#-advanced) @@ -18,11 +16,6 @@ * [License](#-license) * [Contacts](#-contacts) -## โœˆ๏ธ Migration To New Version - -English version: [Migration Guide](MIGRATION.md) -Russian version: [ะ“ะฐะนะด ะฟะพ ะผะธะณั€ะฐั†ะธะธ](MIGRATION_RU.md) - ## ๐Ÿ“– Introduction ### ๐Ÿ“˜ Base concept of ECS pattern From b8a2fd3cb0ad420d11f50f3397ab2c07f4972c91 Mon Sep 17 00:00:00 2001 From: Oleg Morozov Date: Mon, 9 Jan 2023 12:43:12 +0300 Subject: [PATCH 3/5] =?UTF-8?q?=F0=9F=9A=A7=20Disable=20Warnings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Unity/Utils/Editor/CompilationTime.cs | 2 ++ Unity/Utils/Editor/DependencyResolver.cs | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/Unity/Utils/Editor/CompilationTime.cs b/Unity/Utils/Editor/CompilationTime.cs index 3f1d203d..8f0ffc6d 100644 --- a/Unity/Utils/Editor/CompilationTime.cs +++ b/Unity/Utils/Editor/CompilationTime.cs @@ -27,7 +27,9 @@ public class CompilationTime { static CompilationTime() { + #pragma warning disable CS0618 CompilationPipeline.assemblyCompilationStarted += CompilationPipelineOnAssemblyCompilationStarted; + #pragma warning restore CS0618 CompilationPipeline.assemblyCompilationFinished += CompilationPipelineOnAssemblyCompilationFinished; AssemblyReloadEvents.beforeAssemblyReload += AssemblyReloadEventsOnBeforeAssemblyReload; AssemblyReloadEvents.afterAssemblyReload += AssemblyReloadEventsOnAfterAssemblyReload; diff --git a/Unity/Utils/Editor/DependencyResolver.cs b/Unity/Utils/Editor/DependencyResolver.cs index d8fbfe7d..7e7abfcc 100644 --- a/Unity/Utils/Editor/DependencyResolver.cs +++ b/Unity/Utils/Editor/DependencyResolver.cs @@ -31,7 +31,9 @@ static DependencyResolver() { //todo //UnityEditor.PackageManager.Events.registeredPackages replace for unity 2020+ //we still support 2019.4 so we use assemblyReload event + #pragma warning disable CS0618 CompilationPipeline.assemblyCompilationStarted += CompilationPipelineOnAssemblyCompilationStarted; + #pragma warning restore CS0618 AssemblyReloadEvents.afterAssemblyReload += AssemblyReloadEventsOnAfterAssemblyReload; } @@ -41,7 +43,9 @@ private static void AssemblyReloadEventsOnAfterAssemblyReload() { } private static void CompilationPipelineOnAssemblyCompilationStarted(string obj) { + #pragma warning disable CS0618 CompilationPipeline.assemblyCompilationStarted -= CompilationPipelineOnAssemblyCompilationStarted; + #pragma warning restore CS0618 ResolveDependencies(); } From 2e387f26a187c26fe0acaf10e14e065e08ffd504 Mon Sep 17 00:00:00 2001 From: Oleg Morozov Date: Mon, 16 Jan 2023 21:14:48 +0300 Subject: [PATCH 4/5] =?UTF-8?q?=F0=9F=9A=80EntityProvider.map=20private=20?= =?UTF-8?q?to=20public?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README_NUGET.md.meta | 7 +++++++ Unity/Providers/EntityProvider.cs | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 README_NUGET.md.meta diff --git a/README_NUGET.md.meta b/README_NUGET.md.meta new file mode 100644 index 00000000..9a0a8bab --- /dev/null +++ b/README_NUGET.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9b7efe3b4a66f4b8da3bfc50a234b9e4 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Unity/Providers/EntityProvider.cs b/Unity/Providers/EntityProvider.cs index 95d2fcf3..bc39bfd7 100644 --- a/Unity/Providers/EntityProvider.cs +++ b/Unity/Providers/EntityProvider.cs @@ -10,8 +10,8 @@ namespace Scellecs.Morpeh.Providers { [Il2CppSetOption(Option.DivideByZeroChecks, false)] [AddComponentMenu("ECS/" + nameof(EntityProvider))] public class EntityProvider : MonoBehaviour { - private static IntHashMap map = new IntHashMap(); - private struct MapItem { + public static IntHashMap map = new IntHashMap(); + public struct MapItem { public Entity entity; public int refCounter; } From 7df02c0582f4030ca21ef7e3a5a7a6f991fdea02 Mon Sep 17 00:00:00 2001 From: Oleg Morozov Date: Mon, 16 Jan 2023 21:19:35 +0300 Subject: [PATCH 5/5] =?UTF-8?q?=F0=9F=9A=80=20Update=20Nuget=20and=20packa?= =?UTF-8?q?ge.json=20to=202022.2.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.MD | 7 +++++++ Scellecs.Morpeh.csproj | 6 +++++- package.json | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 7f4a384b..2e5aa3a8 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2022.2.1] - 16.01.2023 +### Changed +- Change visibility of `EntityProvider.map` from private to public. + +### Fixed +- Disable warnings for Unity 2021+ + ## [2022.2.0] - 28.12.2022 ### Added - Added `ICleanupSystem` suitable for cleanup logic. Called by the most recent in LateUpdate by default. diff --git a/Scellecs.Morpeh.csproj b/Scellecs.Morpeh.csproj index b1aaa1cf..037124fa 100644 --- a/Scellecs.Morpeh.csproj +++ b/Scellecs.Morpeh.csproj @@ -4,7 +4,7 @@ netstandard2.1 true true - 2022.2.0 + 2022.2.1 Scellecs.Morpeh Oleg Morozov, Igor Boyko ECS Framework for Unity Game Engine and .Net Platform @@ -18,6 +18,10 @@ Morpeh + + TRACE;MORPEH_DEBUG + + diff --git a/package.json b/package.json index ae01e7bf..f063176c 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "displayName": "Morpeh", "description": "Fast and Simple ECS Framework for Unity Game Engine.", "unity": "2020.3", - "version": "2022.2.0", + "version": "2022.2.1", "keywords": [ "morpeh", "ecs"