Skip to content

Commit

Permalink
Merge pull request #12 from player-03/activate-deactivate
Browse files Browse the repository at this point in the history
Replace `addSystem()` and `removeSystem()`.
  • Loading branch information
player-03 authored Dec 18, 2023
2 parents ff37027 + cd96668 commit 8e57842
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 46 deletions.
26 changes: 15 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class EchoesExample {
Echoes.init();
//Create and activate an instance of our system.
Echoes.addSystem(new RenderSystem()); //Details below.
new RenderSystem().activate(); //Details below.
//Create an entity with the components our system will use. Entities are
//activated automatically unless `false` is passed.
Expand Down Expand Up @@ -114,8 +114,8 @@ class EchoesExample {
//Adding `physicsSystems` first means that entire group will run before
//`RenderSystem`, even if more systems are added later.
Echoes.addSystem(physicsSystems);
Echoes.addSystem(new RenderSystem()); //Details in previous example.
physicsSystems.activate();
new RenderSystem().activate(); //Details in previous example.
//Create entities: one tree and two rabbits. The rabbits will race
//towards the tree.
Expand Down Expand Up @@ -303,9 +303,9 @@ class Main {
//Run all `enterFrame` systems first, then all `midFrame` systems, then
//all `exitFrame` systems.
Echoes.addSystem(enterFrame);
Echoes.addSystem(midFrame);
Echoes.addSystem(exitFrame);
enterFrame.activate();
midFrame.activate();
exitFrame.activate();
//Even if `exitFrame` systems are defined first, they'll run last.
exitFrame.add(new ExitFrameSystem());
Expand Down Expand Up @@ -333,11 +333,11 @@ class Main {
var enterFrame:SystemList = new SystemList();
enterFrame.add(new EnterFrameSystem());
enterFrame.add(new EnterFrameSystem2());
Echoes.addSystem(enterFrame);
enterFrame.activate();
var midFrame:SystemList = new SystemList();
midFrame.add(new MidFrameSystem());
Echoes.addSystem(midFrame);
midFrame.activate();
//Set up `physics` as part of `midFrame`.
var physics:SystemList = new SystemList();
Expand All @@ -355,7 +355,7 @@ class Main {
var exitFrame:SystemList = new SystemList();
exitFrame.add(new ExitFrameSystem());
exitFrame.add(new ExitFrameSystem2());
Echoes.addSystem(exitFrame);
exitFrame.activate();
}
}
```
Expand Down Expand Up @@ -430,8 +430,8 @@ class Main {
//Because `AverageSystem` and `list` both have priority 0, they run in
//the order they're added.
Echoes.addSystem(new AverageSystem());
Echoes.addSystem(list);
new AverageSystem().activate();
list.activate();
//No matter how high a system's priority, if it's added to `list` it
//will run during `list`, and will come after `AverageSystem`.
Expand Down Expand Up @@ -576,11 +576,13 @@ Echoes offers a few ways to customize compilation.

### Since v1.0.0-rc.5

- `Echoes.addSystem()`, `Echoes.hasSystem()`, and `Echoes.removeSystem()` have been replaced by `system.activate()`, `system.active`, and `system.deactivate()`, respectively.
- `Entity.getComponents()` now returns a list of `ComponentStorage` instances, instead of a map. If you prefer the old format, you can perform an implicit cast: `var map:Map<String, Dynamic> = Entity.getComponents()`.
- Systems no longer receive `@:remove` events when deactivated. For instance, a system removed by `Echoes.removeSystem()` won't receive a bunch of events.
- `View.entities` is now an `Array` rather than a `List`. You can still iterate over it as before, but you'll have to call `contains()` rather than `has()` if you want to check existence.
- `Echoes.activeEntities` and `View.entities` may be re-ordered when entities or their components are removed. You can set `-D echoes_stable_order` to preserve the order, potentially at the cost of speed.
- `@:remove` listeners are no longer allowed to add back the component that's currently being removed. They may still add other components as normal.
- `SystemList.exists()` now searches recursively, returning true for grandchildren as well as direct children.

### Since v1.0.0-rc.3

Expand Down Expand Up @@ -630,6 +632,8 @@ Find | Replace with | Notes
`Echoes.entities` | `Echoes.activeEntities`
`Echoes.views` | `Echoes.activeViews`
`Echoes.systems` | `Echoes.activeSystems`
`Echoes.addSystem(system)` | `system.activate()` | You might have used a different variable name than `system`.
`Echoes.removeSystem(system)` | `system.deactivate()` | Ditto.
`AbstractView` | `ViewBase` | Import `echoes.View`.
`ISystem` | `System` | Change "`implements`" to "`extends`," if applicable.
`ICleanableComponentContainer` | `ComponentStorage`
Expand Down
38 changes: 23 additions & 15 deletions src/echoes/Echoes.hx
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,38 @@ class Echoes {

@:allow(echoes.ViewBase)
private static final _activeViews:Array<ViewBase> = [];
/**
* All currently-active views.
*/
public static var activeViews(get, never):ReadOnlyArray<ViewBase>;
private static inline function get_activeViews():ReadOnlyArray<ViewBase> return _activeViews;

/**
* All currently-active systems. Unlike `activeEntities` and `activeViews`,
* this is not a flat array, but rather the root node of a tree: it may
* contain `SystemList`s containing `SystemList`s. All active systems will
* be somewhere in this tree.
*
* Adding a system to this list (whether directly, via `addSystem()`, or by
* adding a list containing that system) activates that system.
*
* Removing a system from this list (whether directly, via `removeSystem()`,
* or by removing a list containing that system) deactivates that system.
*
* To search the full tree, use `activeSystems.find()`.
*/
public static var activeSystems(default, null):SystemList = {
var activeSystems:SystemList = new SystemList();
activeSystems.__activate__();
activeSystems.clock.maxTime = 1;
activeSystems;
};

/**
* The clock used to update `activeSystems`. This starts with all the usual
* defaults, except `maxTime` is set to 1 second. Any changes you make to
* this clock will be preserved, even after `Echoes.reset()`.
*/
public static var clock(get, never):Clock;
private static inline function get_clock():Clock {
return activeSystems.clock;
Expand Down Expand Up @@ -141,21 +164,6 @@ class Echoes {
init(0);
}

//System management
//=================

public static inline function addSystem(system:System):Void {
activeSystems.add(system);
}

public static inline function removeSystem(system:System):Void {
activeSystems.remove(system);
}

public static inline function hasSystem(system:System):Bool {
return activeSystems.exists(system);
}

//Singleton getters
//=================

Expand Down
16 changes: 16 additions & 0 deletions src/echoes/System.hx
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,22 @@ class System {
//Everything else is handled by macro.
}

/**
* Adds this to `activeSystems`, activating it.
*
* Note: you can also activate this by adding it to an active `SystemList`.
*/
public inline function activate():Void {
Echoes.activeSystems.add(this);
}

/**
* Removes this from `activeSystems`, deactivating it.
*/
public inline function deactivate():Void {
parent.remove(this);
}

/**
* @see `SystemList.find()`
*/
Expand Down
10 changes: 7 additions & 3 deletions src/echoes/SystemList.hx
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,15 @@ class SystemList extends System {
}

/**
* Returns whether this list directly contains the given system.
* @see `find()` if you need to recursively search child lists.
* Returns whether this list directly or indirectly contains `system`. Use
* `system.parent` instead if you only want its direct parent.
*/
public inline function exists(system:System):Bool {
return system.parent == this;
var parent:SystemList = system.parent;
while(parent != null && parent != this) {
parent = parent.parent;
}
return parent == this;
}

/**
Expand Down
12 changes: 6 additions & 6 deletions test/AdvancedFunctionalityTest.hx
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ class AdvancedFunctionalityTest extends Test {
}

private function testEntityTemplates():Void {
Echoes.addSystem(new NameSystem());
Echoes.addSystem(new AppearanceSystem());
new NameSystem().activate();
new AppearanceSystem().activate();

var entity:Entity = new Entity();
entity.add(("John":Name));
Expand Down Expand Up @@ -112,7 +112,7 @@ class AdvancedFunctionalityTest extends Test {

private function testGenerics():Void {
var system:GenericSystem<String, Int> = new GenericSystem<String, Int>();
Echoes.addSystem(system);
system.activate();

var entity:Entity = new Entity();
entity.add("STRING");
Expand All @@ -133,7 +133,7 @@ class AdvancedFunctionalityTest extends Test {
}

var system = new GenericSystem<Alias<Name>, String>();
Echoes.addSystem(system);
system.activate();

entity.add(("NAME":Alias<Name>));
switch(system.record) {
Expand Down Expand Up @@ -311,13 +311,13 @@ class AdvancedFunctionalityTest extends Test {
Assert.equals(0, viewOfColor.entities.length);

//Adding/removing the system should activate/deactivate the linked view.
Echoes.addSystem(nameSystem);
nameSystem.activate();
Assert.isTrue(viewOfColor.active);
Assert.equals(2, viewOfColor.entities.length);
Assert.isTrue(viewOfColor.entities.contains(colorName));
Assert.isTrue(viewOfColor.entities.contains(colorShape));

Echoes.removeSystem(nameSystem);
nameSystem.deactivate();
Assert.isFalse(viewOfColor.active);
Assert.equals(0, viewOfColor.entities.length);
}
Expand Down
10 changes: 5 additions & 5 deletions test/BasicFunctionalityTest.hx
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ class BasicFunctionalityTest extends Test {
Assert.isFalse(inactive.active);
Assert.equals(0, Echoes.activeEntities.length);

Echoes.addSystem(new AppearanceSystem());
new AppearanceSystem().activate();
assertTimesCalled(0, "AppearanceSystem.colorAdded");

//Add some components the system looks for.
Expand All @@ -159,7 +159,7 @@ class BasicFunctionalityTest extends Test {
var appearanceSystem:AppearanceSystem = new AppearanceSystem();
Assert.equals(0, Echoes.activeSystems.length);

Echoes.addSystem(appearanceSystem);
appearanceSystem.activate();
Assert.equals(1, Echoes.activeSystems.length);
assertTimesCalled(0, "AppearanceSystem.colorAdded");

Expand Down Expand Up @@ -193,7 +193,7 @@ class BasicFunctionalityTest extends Test {
redLine.add(("redLine":Name));
assertTimesCalled(0, "NameSystem.nameAdded", "NameSystem isn't active but its method was still called.");

Echoes.addSystem(nameSystem);
nameSystem.activate();
assertTimesCalled(2, "NameSystem.nameAdded");
assertTimesCalled(0, "NameSystem.nameRemoved");

Expand Down Expand Up @@ -223,7 +223,7 @@ class BasicFunctionalityTest extends Test {
assertTimesCalled(2, "NameSystem.nameRemoved");

//Deactivate a system.
Echoes.removeSystem(nameSystem);
nameSystem.deactivate();
assertTimesCalled(2, "NameSystem.nameRemoved");

//Destroy the remaining entity.
Expand All @@ -238,7 +238,7 @@ class BasicFunctionalityTest extends Test {
private function testUpdateEvents():Void {
//Create a `TimeCountSystem` and use a custom `Clock`.
var systems:SystemList = new SystemList(new OneSecondClock());
Echoes.addSystem(systems);
systems.activate();

var timeCountSystem:TimeCountSystem = new TimeCountSystem();
Assert.equals(0.0, timeCountSystem.totalTime);
Expand Down
12 changes: 6 additions & 6 deletions test/EdgeCaseTest.hx
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ class EdgeCaseTest extends Test {
//Tests may be run in any order, but not in parallel.

private function testChildSystems():Void {
Echoes.addSystem(new NameSubsystem());
new NameSubsystem().activate();

var entity:Entity = new Entity();
entity.add(("Name":Name));
assertTimesCalled(0, "NameSystem.nameAdded");
assertTimesCalled(1, "NameSubsystem.nameAdded");

Echoes.addSystem(new NameSystem());
new NameSystem().activate();
assertTimesCalled(1, "NameSystem.nameAdded");
assertTimesCalled(0, "NameSystem.nameRemoved");
assertTimesCalled(0, "NameSubsystem.nameRemoved");
Expand All @@ -45,7 +45,7 @@ class EdgeCaseTest extends Test {
}

private function testComponentsExist():Void {
Echoes.addSystem(new ComponentsExistSystem());
new ComponentsExistSystem().activate();

var entity:Entity = new Entity();
entity.add(("name":Name));
Expand Down Expand Up @@ -136,7 +136,7 @@ class EdgeCaseTest extends Test {
}

private function testRedundantOperations():Void {
Echoes.addSystem(new AppearanceSystem());
new AppearanceSystem().activate();

var entity:Entity = new Entity(false);

Expand Down Expand Up @@ -171,7 +171,7 @@ class EdgeCaseTest extends Test {
assertTimesCalled(1, "AppearanceSystem.colorRemoved");

//Replace a `Name` with itself.
Echoes.addSystem(new NameSystem());
new NameSystem().activate();
entity.add(("name":Name));
assertTimesCalled(1, "NameSystem.nameAdded");
assertTimesCalled(0, "NameSystem.nameRemoved");
Expand All @@ -189,7 +189,7 @@ class EdgeCaseTest extends Test {
var entity:Entity = new Entity();

//Activate the system first so that it can process events first.
Echoes.addSystem(new RecursiveEventSystem());
new RecursiveEventSystem().activate();

//Certain events should stop propagating after `RecursiveEventSystem`
//gets to them.
Expand Down

0 comments on commit 8e57842

Please sign in to comment.