diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml new file mode 100644 index 00000000..bd957c59 --- /dev/null +++ b/.github/workflows/compile.yml @@ -0,0 +1,26 @@ +# This workflow will build a Java project with Gradle +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle + +name: Compile and publish local + +on: + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Build and test + run: ./gradlew clean ashley:test + - name: Local install + run: ./gradlew uploadArchives diff --git a/.github/workflows/publish_release.yml b/.github/workflows/publish_release.yml new file mode 100644 index 00000000..cec1c0f6 --- /dev/null +++ b/.github/workflows/publish_release.yml @@ -0,0 +1,33 @@ +name: Compile and publish release + +on: + release: + types: [published] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Build and test + run: ./gradlew clean ashley:test + - name: Import GPG key + id: import_gpg + uses: crazy-max/ghaction-import-gpg@v3 + with: + gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} + passphrase: ${{ secrets.GPG_PASSPHRASE }} + - name: Release build deploy + env: + NEXUS_USERNAME: ${{ secrets.NEXUS_USERNAME }} + NEXUS_PASSWORD: ${{ secrets.NEXUS_PASSWORD }} + run: + ./gradlew clean uploadArchives -PRELEASE=true -Psigning.gnupg.keyId=${{ secrets.GPG_KEYID }} -Psigning.gnupg.passphrase=${{ secrets.GPG_PASSPHRASE }} -Psigning.gnupg.keyName=${{ secrets.GPG_KEYID }} diff --git a/.github/workflows/publish_snapshot.yml b/.github/workflows/publish_snapshot.yml new file mode 100644 index 00000000..f4569a60 --- /dev/null +++ b/.github/workflows/publish_snapshot.yml @@ -0,0 +1,27 @@ +name: Compile and publish snapshot + +on: + push: + branches: + - master + - release/** +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Build and test + run: ./gradlew clean ashley:test + - name: Publish snapshot + env: + NEXUS_USERNAME: ${{ secrets.NEXUS_USERNAME }} + NEXUS_PASSWORD: ${{ secrets.NEXUS_PASSWORD }} + run: ./gradlew uploadArchives -PSNAPSHOT=true diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 4239e58a..00000000 --- a/.travis.yml +++ /dev/null @@ -1,2 +0,0 @@ -language: java -script: ./gradlew clean ashley:test diff --git a/README.md b/README.md index 7323f294..02499c1d 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,8 @@ Ashley is awesome, if you don't believe it, check out some [games](https://githu Ashley lives under the [Libgdx](https://github.com/libgdx) family but it does not force you to use that specific framework if you do not wish to do so. -[![Build Status](https://travis-ci.org/libgdx/ashley.svg?branch=master)](https://travis-ci.org/libgdx/ashley) +[![Sonatype Nexus (Releases)](https://img.shields.io/nexus/r/com.badlogicgames.ashley/ashley?nexusVersion=2&server=https%3A%2F%2Foss.sonatype.org&label=release)](https://search.maven.org/artifact/com.badlogicgames.ashley/ashley) +[![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/s/com.badlogicgames.ashley/ashley?server=https%3A%2F%2Foss.sonatype.org&label=snapshot)](https://oss.sonatype.org/#nexus-search;gav~com.badlogicgames.ashley~ashley) ### Get started diff --git a/ashley/src/com/badlogic/ashley/core/ComponentOperationHandler.java b/ashley/src/com/badlogic/ashley/core/ComponentOperationHandler.java index 3f430dfb..a87c91f1 100644 --- a/ashley/src/com/badlogic/ashley/core/ComponentOperationHandler.java +++ b/ashley/src/com/badlogic/ashley/core/ComponentOperationHandler.java @@ -35,6 +35,10 @@ public void remove(Entity entity) { } } + public boolean hasOperationsToProcess() { + return operations.size > 0; + } + public void processOperations() { for (int i = 0; i < operations.size; ++i) { ComponentOperation operation = operations.get(i); diff --git a/ashley/src/com/badlogic/ashley/core/Engine.java b/ashley/src/com/badlogic/ashley/core/Engine.java index 755a6760..fdd019d0 100644 --- a/ashley/src/com/badlogic/ashley/core/Engine.java +++ b/ashley/src/com/badlogic/ashley/core/Engine.java @@ -89,6 +89,14 @@ public void removeEntity(Entity entity){ boolean delayed = updating || familyManager.notifying(); entityManager.removeEntity(entity, delayed); } + + /** + * Removes all entities of the given {@link Family}. + */ + public void removeAllEntities(Family family) { + boolean delayed = updating || familyManager.notifying(); + entityManager.removeAllEntities(getEntitiesFor(family), delayed); + } /** * Removes all entities registered with this Engine. @@ -98,6 +106,29 @@ public void removeAllEntities() { entityManager.removeAllEntities(delayed); } + /** + * Returns an {@link ImmutableArray} of {@link Entity} that is managed by the the Engine + * but cannot be used to modify the state of the Engine. This Array is not Immutable in + * the sense that its contents will not be modified, but in the sense that it only reflects + * the state of the engine. + * + * The Array is Immutable in the sense that you cannot modify its contents through the API of + * the {@link ImmutableArray} class, but is instead "Managed" by the Engine itself. The engine + * may add or remove items from the array and this will be reflected in the returned array. + * + * This is an important note if you are looping through the returned entities and calling operations + * that may add/remove entities from the engine, as the underlying iterator of the returned array + * will reflect these modifications. + * + * The returned array will have entities removed from it if they are removed from the engine, + * but there is no way to introduce new Entities through the array's interface, or remove + * entities from the engine through the array interface. + * + * Discussion of this can be found at https://github.com/libgdx/ashley/issues/224 + * + * @return An unmodifiable array of entities that will match the state of the entities in the + * engine. + */ public ImmutableArray getEntities() { return entityManager.getEntities(); } @@ -118,6 +149,13 @@ public void removeSystem(EntitySystem system){ systemManager.removeSystem(system); } + /** + * Removes all systems from this Engine. + */ + public void removeAllSystems(){ + systemManager.removeAllSystems(); + } + /** * Quick {@link EntitySystem} retrieval. */ @@ -133,8 +171,8 @@ public ImmutableArray getSystems() { return systemManager.getSystems(); } - /** - * Returns immutable collection of entities for the specified {@link Family}. Will return the same instance every time. + /** Returns immutable collection of entities for the specified {@link Family}. + * Returns the same instance every time for the same Family. */ public ImmutableArray getEntitiesFor(Family family){ return familyManager.getEntitiesFor(family); @@ -202,8 +240,10 @@ public void update(float deltaTime){ system.update(deltaTime); } - componentOperationHandler.processOperations(); - entityManager.processPendingOperations(); + while(componentOperationHandler.hasOperationsToProcess() || entityManager.hasPendingOperations()) { + componentOperationHandler.processOperations(); + entityManager.processPendingOperations(); + } } } finally { diff --git a/ashley/src/com/badlogic/ashley/core/Entity.java b/ashley/src/com/badlogic/ashley/core/Entity.java index df133e96..fe71bba9 100644 --- a/ashley/src/com/badlogic/ashley/core/Entity.java +++ b/ashley/src/com/badlogic/ashley/core/Entity.java @@ -78,7 +78,7 @@ public Entity add (Component component) { * Adds a {@link Component} to this Entity. If a {@link Component} of the same type already exists, it'll be replaced. * @return The Component for direct component manipulation (e.g. PooledComponent) */ - public Component addAndReturn(Component component) { + public T addAndReturn(T component) { add(component); return component; } @@ -86,23 +86,28 @@ public Component addAndReturn(Component component) { /** * Removes the {@link Component} of the specified type. Since there is only ever one component of one type, we don't need an * instance reference. - * @return The removed {@link Component}, or null if the Entity did no contain such a component. + * @return The removed {@link Component}, or null if the Entity did not contain such a component. */ - public Component remove (Class componentClass) { + public T remove (Class componentClass) { ComponentType componentType = ComponentType.getFor(componentClass); int componentTypeIndex = componentType.getIndex(); - Component removeComponent = components.get(componentTypeIndex); - - if (removeComponent != null && removeInternal(componentClass)) { - if (componentOperationHandler != null) { - componentOperationHandler.remove(this); - } - else { - notifyComponentRemoved(); + + if(components.isIndexWithinBounds(componentTypeIndex)){ + Component removeComponent = components.get(componentTypeIndex); + + if (removeComponent != null && removeInternal(componentClass) != null) { + if (componentOperationHandler != null) { + componentOperationHandler.remove(this); + } + else { + notifyComponentRemoved(); + } } + + return (T) removeComponent; } - - return removeComponent; + + return null; } /** Removes all the {@link Component}'s from the Entity. */ @@ -189,9 +194,9 @@ boolean addInternal (Component component) { /** * @param componentClass - * @return whether or not a component with the specified class was found and removed. + * @return the component if the specified class was found and removed. Otherwise, null */ - boolean removeInternal (Class componentClass) { + Component removeInternal (Class componentClass) { ComponentType componentType = ComponentType.getFor(componentClass); int componentTypeIndex = componentType.getIndex(); Component removeComponent = components.get(componentTypeIndex); @@ -201,10 +206,10 @@ boolean removeInternal (Class componentClass) { componentsArray.removeValue(removeComponent, true); componentBits.clear(componentTypeIndex); - return true; + return removeComponent; } - - return false; + + return null; } void notifyComponentAdded() { @@ -219,4 +224,9 @@ void notifyComponentRemoved() { public boolean isScheduledForRemoval () { return scheduledForRemoval; } + + /** @return true if the entity is being removed */ + public boolean isRemoving() { + return removing; + } } diff --git a/ashley/src/com/badlogic/ashley/core/EntityManager.java b/ashley/src/com/badlogic/ashley/core/EntityManager.java index 1d5d9252..1b52cadb 100644 --- a/ashley/src/com/badlogic/ashley/core/EntityManager.java +++ b/ashley/src/com/badlogic/ashley/core/EntityManager.java @@ -55,20 +55,29 @@ public void removeEntity(Entity entity, boolean delayed){ } public void removeAllEntities() { - removeAllEntities(false); + removeAllEntities(immutableEntities); } public void removeAllEntities(boolean delayed) { + removeAllEntities(immutableEntities, delayed); + } + + public void removeAllEntities(ImmutableArray entities) { + removeAllEntities(entities, false); + } + + public void removeAllEntities(ImmutableArray entities, boolean delayed) { if (delayed) { for(Entity entity: entities) { entity.scheduledForRemoval = true; } EntityOperation operation = entityOperationPool.obtain(); operation.type = EntityOperation.Type.RemoveAll; + operation.entities = entities; pendingOperations.add(operation); } else { - while(entities.size > 0) { + while(entities.size() > 0) { removeEntity(entities.first(), false); } } @@ -78,6 +87,10 @@ public ImmutableArray getEntities() { return immutableEntities; } + public boolean hasPendingOperations() { + return pendingOperations.size > 0; + } + public void processPendingOperations() { for (int i = 0; i < pendingOperations.size; ++i) { EntityOperation operation = pendingOperations.get(i); @@ -86,8 +99,8 @@ public void processPendingOperations() { case Add: addEntityInternal(operation.entity); break; case Remove: removeEntityInternal(operation.entity); break; case RemoveAll: - while(entities.size > 0) { - removeEntityInternal(entities.first()); + while(operation.entities.size() > 0) { + removeEntityInternal(operation.entities.first()); } break; default: @@ -132,6 +145,7 @@ public enum Type { public Type type; public Entity entity; + public ImmutableArray entities; @Override public void reset() { diff --git a/ashley/src/com/badlogic/ashley/core/PooledEngine.java b/ashley/src/com/badlogic/ashley/core/PooledEngine.java index 3deb66df..67d92ec6 100644 --- a/ashley/src/com/badlogic/ashley/core/PooledEngine.java +++ b/ashley/src/com/badlogic/ashley/core/PooledEngine.java @@ -96,14 +96,13 @@ protected void removeEntityInternal (Entity entity) { private class PooledEntity extends Entity implements Poolable { @Override - public Component remove (Class componentClass) { - Component component = super.remove(componentClass); - - if (component != null) { - componentPools.free(component); + Component removeInternal(Class componentClass) { + Component removed = super.removeInternal(componentClass); + if (removed != null) { + componentPools.free(removed); } - return component; + return removed; } @Override @@ -181,4 +180,4 @@ public void clear () { } } } -} \ No newline at end of file +} diff --git a/ashley/src/com/badlogic/ashley/core/SystemManager.java b/ashley/src/com/badlogic/ashley/core/SystemManager.java index ca55685b..22b152b6 100644 --- a/ashley/src/com/badlogic/ashley/core/SystemManager.java +++ b/ashley/src/com/badlogic/ashley/core/SystemManager.java @@ -39,6 +39,12 @@ public void removeSystem(EntitySystem system){ listener.systemRemoved(system); } } + + public void removeAllSystems() { + while(systems.size > 0) { + removeSystem(systems.first()); + } + } @SuppressWarnings("unchecked") public T getSystem(Class systemType) { diff --git a/ashley/src/com/badlogic/ashley/systems/IntervalSystem.java b/ashley/src/com/badlogic/ashley/systems/IntervalSystem.java index 09659df2..cb62a416 100644 --- a/ashley/src/com/badlogic/ashley/systems/IntervalSystem.java +++ b/ashley/src/com/badlogic/ashley/systems/IntervalSystem.java @@ -49,7 +49,7 @@ public float getInterval() { } @Override - public final void update (float deltaTime) { + public void update (float deltaTime) { accumulator += deltaTime; while (accumulator >= interval) { diff --git a/ashley/src/com/badlogic/ashley/utils/Bag.java b/ashley/src/com/badlogic/ashley/utils/Bag.java index 7e6a95e6..45df846a 100644 --- a/ashley/src/com/badlogic/ashley/utils/Bag.java +++ b/ashley/src/com/badlogic/ashley/utils/Bag.java @@ -153,7 +153,7 @@ public void set (int index, E e) { if (index >= data.length) { grow(index * 2); } - size = index + 1; + size = Math.max(size, index + 1); data[index] = e; } diff --git a/ashley/src/com/badlogic/ashley/utils/ImmutableArray.java b/ashley/src/com/badlogic/ashley/utils/ImmutableArray.java index 2a73e6d6..683e78d0 100644 --- a/ashley/src/com/badlogic/ashley/utils/ImmutableArray.java +++ b/ashley/src/com/badlogic/ashley/utils/ImmutableArray.java @@ -70,7 +70,7 @@ public T[] toArray () { return array.toArray(); } - public V[] toArray (Class type) { + public V[] toArray (Class type) { return array.toArray(type); } diff --git a/ashley/tests/com/badlogic/ashley/core/ComponentClassFactory.java b/ashley/tests/com/badlogic/ashley/core/ComponentClassFactory.java new file mode 100644 index 00000000..aec6f598 --- /dev/null +++ b/ashley/tests/com/badlogic/ashley/core/ComponentClassFactory.java @@ -0,0 +1,68 @@ +package com.badlogic.ashley.core; + +import org.mockito.asm.ClassWriter; +import org.mockito.asm.MethodVisitor; +import org.mockito.asm.Opcodes; + +/** + * Class loader allowing dynamic {@link Component} class definitions. + * + * Useful for tests that need several different component types. + * + * Adapted from https://dzone.com/articles/fully-dynamic-classes-with-asm + * + * @author mgsx + * + */ +public class ComponentClassFactory extends ClassLoader +{ + /** + * create new {@link Component} type + * @param name name of the class to create + * @return created class + */ + @SuppressWarnings("unchecked") + public Class createComponentType(String name){ + + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + + String interfacePath = Component.class.getName().replaceAll("\\.", "/"); + + // create public class (default package) implementing Component + + cw.visit(Opcodes.V1_6, // Java 1.6 + Opcodes.ACC_PUBLIC, // public class + name, // package and name + null, // signature (null means not generic) + "java/lang/Object", // superclass + new String[]{ interfacePath }); // interfaces + + // create public no-arg constructor + + MethodVisitor con = cw.visitMethod( + Opcodes.ACC_PUBLIC, // public method + "", // method name + "()V", // descriptor + null, // signature (null means not generic) + null); // exceptions (array of strings) + + // define constructor body : call super constructor (java.lang.Object) + + con.visitCode(); // Start the code for this method + con.visitVarInsn(Opcodes.ALOAD, 0); // Load "this" onto the stack + con.visitMethodInsn(Opcodes.INVOKESPECIAL, // Invoke an instance method (non-virtual) + "java/lang/Object", // Class on which the method is defined + "", // Name of the method + "()V"); // Descriptor + con.visitInsn(Opcodes.RETURN); // End the constructor method + con.visitMaxs(1, 1); // Specify max stack and local vars + + // close class definition. + + cw.visitEnd(); + + // load and return class. + byte[] b = cw.toByteArray(); + return (Class)defineClass(name, b, 0, b.length); + } +} \ No newline at end of file diff --git a/ashley/tests/com/badlogic/ashley/core/EngineTests.java b/ashley/tests/com/badlogic/ashley/core/EngineTests.java index ced21d2d..39bdab9c 100644 --- a/ashley/tests/com/badlogic/ashley/core/EngineTests.java +++ b/ashley/tests/com/badlogic/ashley/core/EngineTests.java @@ -233,6 +233,15 @@ public void addAndRemoveSystem () { assertNull(engine.getSystem(EntitySystemMockB.class)); assertEquals(1, systemA.removedCalls); assertEquals(1, systemB.removedCalls); + + engine.addSystem(systemA); + engine.addSystem(systemB); + engine.removeAllSystems(); + + assertNull(engine.getSystem(EntitySystemMockA.class)); + assertNull(engine.getSystem(EntitySystemMockB.class)); + assertEquals(2, systemA.removedCalls); + assertEquals(2, systemB.removedCalls); } @Test @@ -675,6 +684,92 @@ public void entityAddRemoveComponentWhileIterating() { engine.removeSystem(removeSystem); } + @Test + public void cascadeOperationsInListenersWhileUpdating() { + + // This test case mix both add/remove component and add/remove entities + // in listeners. + // Listeners trigger each other recursively to test cascade operations : + + // CREATION PHASE : + // first listener will add a component which trigger the second, + // second listener will create an entity which trigger the first one, + // and so on. + + // DESTRUCTION PHASE : + // first listener will remove component which trigger the second, + // second listener will remove the entity which trigger the first one, + // and so on. + + final int numEntities = 20; + final Engine engine = new Engine(); + ComponentAddedListener addedListener = new ComponentAddedListener(numEntities); + ComponentRemovedListener removedListener = new ComponentRemovedListener(numEntities); + + final Array entities = new Array(); + + engine.addEntityListener(Family.all(ComponentA.class).get(), new EntityListener() { + @Override + public void entityRemoved(Entity entity) { + engine.removeEntity(entity); + } + @Override + public void entityAdded(Entity entity) { + if(entities.size < numEntities){ + Entity e = new Entity(); + engine.addEntity(e); + } + } + }); + engine.addEntityListener(new EntityListener() { + @Override + public void entityRemoved(Entity entity) { + entities.removeValue(entity, true); + if(entities.size > 0){ + entities.peek().remove(ComponentA.class); + } + } + @Override + public void entityAdded(Entity entity) { + entities.add(entity); + entity.add(new ComponentA()); + } + }); + + engine.addEntityListener(Family.all(ComponentA.class).get(), addedListener); + engine.addEntityListener(Family.all(ComponentA.class).get(), removedListener); + + // this system will just create an entity which will trigger + // listeners cascade creations (up to 20) + EntitySystem addSystem = new EntitySystem() { + @Override + public void update(float deltaTime) { + getEngine().addEntity(new Entity()); + } + }; + + engine.addSystem(addSystem); + engine.update(deltaTime); + engine.removeSystem(addSystem); + addedListener.checkEntityListenerNonUpdate(); + removedListener.checkEntityListenerUpdate(); + + // this system will just remove an entity which will trigger + // listeners cascade deletion (up to 0) + EntitySystem removeSystem = new EntitySystem() { + @Override + public void update(float deltaTime) { + getEngine().removeEntity(entities.peek()); + } + }; + + engine.addSystem(removeSystem); + engine.update(deltaTime); + engine.removeSystem(removeSystem); + addedListener.checkEntityListenerUpdate(); + removedListener.checkEntityListenerNonUpdate(); + } + @Test public void familyListener () { Engine engine = new Engine(); @@ -739,6 +834,22 @@ public void familyListener () { assertEquals(1, listenerB.removedCount); engine.addEntityListener(listenerB); + + engine.addEntity(entity1); + engine.addEntity(entity2); + + assertEquals(3, listenerA.addedCount); + assertEquals(3, listenerB.addedCount); + + engine.removeAllEntities(familyA); + + assertEquals(3, listenerA.removedCount); + assertEquals(2, listenerB.removedCount); + + engine.removeAllEntities(familyB); + + assertEquals(3, listenerA.removedCount); + assertEquals(3, listenerB.removedCount); } @Test diff --git a/ashley/tests/com/badlogic/ashley/core/EntityTests.java b/ashley/tests/com/badlogic/ashley/core/EntityTests.java index f9350c7e..c7b8abb9 100644 --- a/ashley/tests/com/badlogic/ashley/core/EntityTests.java +++ b/ashley/tests/com/badlogic/ashley/core/EntityTests.java @@ -64,6 +64,12 @@ public void addAndReturnComponent(){ assertEquals(2, entity.getComponents().size()); } + @Test + public void addAndReturnComponentGeneric () { + Entity entity = new Entity(); + ComponentA componentA = entity.addAndReturn(new ComponentA()); + } + @Test public void noComponents () { Entity entity = new Entity(); @@ -109,6 +115,21 @@ public void addAndRemoveComponent () { assertFalse(am.has(entity)); assertFalse(bm.has(entity)); } + + @Test + public void removeUnexistingComponent () throws Exception { + // ensure remove unexisting component work with + // new component type at default bag limits (64) + Entity entity = new Entity(); + + ComponentClassFactory cl = new ComponentClassFactory(); + + for(int i=0 ; i<65 ; i++){ + Class type = cl.createComponentType("Component" + i); + entity.remove(type); + entity.add(type.newInstance()); + } + } @Test public void addAndRemoveAllComponents () { diff --git a/ashley/tests/com/badlogic/ashley/core/PooledEngineTests.java b/ashley/tests/com/badlogic/ashley/core/PooledEngineTests.java index d84c829d..267d55d6 100644 --- a/ashley/tests/com/badlogic/ashley/core/PooledEngineTests.java +++ b/ashley/tests/com/badlogic/ashley/core/PooledEngineTests.java @@ -14,10 +14,20 @@ public class PooledEngineTests { private float deltaTime = 0.16f; + private final ComponentMapper poolableMapper = ComponentMapper.getFor(PoolableComponent.class); + public static class ComponentA implements Component { public ComponentA(){} } + public static class PoolableComponent implements Component, Poolable { + boolean reset = true; + @Override + public void reset() { + reset = true; + } + } + public static class PositionComponent implements Component { public float x = 0.0f; public float y = 0.0f; @@ -244,4 +254,42 @@ public void createNewComponent () { assertNotNull(componentA); } + + @Test + public void addSameComponentShouldResetAndReturnOldComponentToPool () { + PooledEngine engine = new PooledEngine(); + + PoolableComponent component1 = engine.createComponent(PoolableComponent.class); + component1.reset = false; + PoolableComponent component2 = engine.createComponent(PoolableComponent.class); + component2.reset = false; + + Entity entity = engine.createEntity(); + entity.add(component1); + entity.add(component2); + + assertEquals(1, entity.getComponents().size()); + assertTrue(poolableMapper.has(entity)); + assertNotEquals(component1, poolableMapper.get(entity)); + assertEquals(component2, poolableMapper.get(entity)); + + assertTrue(component1.reset); + } + + @Test + public void removeComponentReturnsItToThePoolExactlyOnce() { + PooledEngine engine = new PooledEngine(); + + PoolableComponent removedComponent = engine.createComponent(PoolableComponent.class); + + Entity entity = engine.createEntity(); + entity.add(removedComponent); + + entity.remove(PoolableComponent.class); + + PoolableComponent newComponent1 = engine.createComponent(PoolableComponent.class); + PoolableComponent newComponent2 = engine.createComponent(PoolableComponent.class); + + assertNotEquals(newComponent1, newComponent2); + } } diff --git a/ashley/tests/com/badlogic/ashley/core/SystemManagerTests.java b/ashley/tests/com/badlogic/ashley/core/SystemManagerTests.java index 9c5c3dc2..dd77cfa1 100644 --- a/ashley/tests/com/badlogic/ashley/core/SystemManagerTests.java +++ b/ashley/tests/com/badlogic/ashley/core/SystemManagerTests.java @@ -109,6 +109,15 @@ public void addAndRemoveSystem () { assertNull(manager.getSystem(EntitySystemMockB.class)); assertEquals(1, systemA.removedCalls); assertEquals(1, systemB.removedCalls); + + manager.addSystem(systemA); + manager.addSystem(systemB); + manager.removeAllSystems(); + + assertNull(manager.getSystem(EntitySystemMockA.class)); + assertNull(manager.getSystem(EntitySystemMockB.class)); + assertEquals(2, systemA.removedCalls); + assertEquals(2, systemB.removedCalls); } @Test diff --git a/ashley/tests/com/badlogic/ashley/utils/BagTest.java b/ashley/tests/com/badlogic/ashley/utils/BagTest.java new file mode 100644 index 00000000..0bfbf415 --- /dev/null +++ b/ashley/tests/com/badlogic/ashley/utils/BagTest.java @@ -0,0 +1,20 @@ +package com.badlogic.ashley.utils; + +import org.junit.Assert; +import org.junit.Test; + +public class BagTest { + + @Test + public void testSet(){ + final Bag bag = new Bag(); + bag.add("a"); + bag.add("b"); + bag.add("c"); + Assert.assertEquals(3, bag.size()); + + bag.set(1, "d"); + Assert.assertEquals(3, bag.size()); + Assert.assertEquals("d", bag.get(1)); + } +} diff --git a/build.gradle b/build.gradle index ab1d0513..ffcd3eca 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ subprojects { apply plugin: "eclipse" apply plugin: "idea" - apply plugin: "java" + apply plugin: "java-library" repositories { mavenLocal() @@ -14,7 +14,7 @@ subprojects { ext { projectGroup = "ashley" - gdxVersion = "1.9.4" + gdxVersion = "1.9.9" jUnitVersion = "4.12" mockitoVersion = "1.10.19" } @@ -32,25 +32,25 @@ project(":ashley") { apply from : '../publish.gradle' dependencies { - compile "com.badlogicgames.gdx:gdx:$gdxVersion" - testCompile "junit:junit:$jUnitVersion" - testCompile "org.mockito:mockito-core:$mockitoVersion" + api "com.badlogicgames.gdx:gdx:$gdxVersion" + testImplementation "junit:junit:$jUnitVersion" + testImplementation "org.mockito:mockito-core:$mockitoVersion" } } project(":tests") { dependencies { - compile project(":ashley") - compile "com.badlogicgames.gdx:gdx-backend-lwjgl:$gdxVersion" - compile "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop" + implementation project(":ashley") + implementation "com.badlogicgames.gdx:gdx-backend-lwjgl:$gdxVersion" + implementation "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop" } } project(":benchmarks") { dependencies { - compile project(":ashley") - compile "junit:junit:$jUnitVersion" - compile fileTree(dir: new File(projectDir, "libs"), include: "*.jar") + implementation project(":ashley") + implementation "junit:junit:$jUnitVersion" + implementation fileTree(dir: new File(projectDir, "libs"), include: "*.jar") } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 07867f65..d1bae53f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip diff --git a/publish.gradle b/publish.gradle index db69af11..f7794d3f 100644 --- a/publish.gradle +++ b/publish.gradle @@ -1,11 +1,8 @@ -import org.gradle.api.XmlProvider -import org.gradle.api.artifacts.maven.MavenDeployment - apply plugin: 'maven' apply plugin: 'signing' group = 'com.badlogicgames.ashley' -version = '1.7.3' +version = '1.7.4' ext.packaging = 'jar' def isDevBuild @@ -15,11 +12,11 @@ def isReleaseBuild def sonatypeRepositoryUrl //set build variables based on build type (release, continuous integration, development) -if(hasProperty("release")) { +if(hasProperty("RELEASE")) { isReleaseBuild = true - sonatypeRepositoryUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" + sonatypeRepositoryUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" println "Performing release build" -} else if (hasProperty("snapshot")) { +} else if (hasProperty("SNAPSHOT")) { isCiBuild = true version += "-SNAPSHOT" sonatypeRepositoryUrl = "https://oss.sonatype.org/content/repositories/snapshots/" @@ -29,6 +26,14 @@ if(hasProperty("release")) { println "Performing local build" } +def getRepositoryUsername = { + return project.hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : "$System.env.NEXUS_USERNAME" +} + +def getRepositoryPassword = { + return project.hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : "$System.env.NEXUS_PASSWORD" +} + repositories { mavenCentral() } @@ -51,6 +56,7 @@ artifacts { if(isReleaseBuild) { signing { + useGpgCmd() sign configurations.archives } } else { @@ -71,7 +77,7 @@ uploadArchives { } repository(url: sonatypeRepositoryUrl) { - authentication(userName: sonatypeUsername, password: sonatypePassword) + authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) } pom.version = version