package com.indignado.logicbricks.core; import com.badlogic.ashley.core.*; import com.badlogic.gdx.InputMultiplexer; import com.badlogic.gdx.InputProcessor; import com.badlogic.gdx.physics.box2d.Body; import com.badlogic.gdx.physics.box2d.ContactListener; import com.badlogic.gdx.physics.box2d.Filter; import com.badlogic.gdx.physics.box2d.Fixture; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.ObjectMap; import com.badlogic.gdx.utils.Pool; import com.badlogic.gdx.utils.ReflectionPool; import com.indignado.logicbricks.components.IdentityComponent; import com.indignado.logicbricks.components.RigidBodiesComponents; import com.indignado.logicbricks.config.GameContext; import com.indignado.logicbricks.config.Settings; import com.indignado.logicbricks.core.data.Data; import com.indignado.logicbricks.core.data.LogicBrick; import com.indignado.logicbricks.systems.LogicBrickSystem; import com.indignado.logicbricks.utils.Log; /** * @author Rubentxu. */ public class LogicBricksEngine extends PooledEngine { private static Long IDS = 0L; private String tag = LogicBricksEngine.class.getSimpleName(); private GameContext context; private ObjectMap<Long, Entity> idEntities; private ObjectMap<String, Array<Entity>> tagEntities; private DataPools dataPools; private InputMultiplexer inputs; private Array<ContactListener> contactSystems; private ObjectMap<Class<? extends LogicBrick>, BricksClasses> bricksClasses; private ObjectMap<Class<? extends Component>, Class<? extends LogicBrickSystem>[]> systemClasses; public LogicBricksEngine(GameContext context) { this(10, 100, 10, 100, 50, 200, context); } public LogicBricksEngine(int entityPoolInitialSize, int entityPoolMaxSize, int componentPoolInitialSize, int componentPoolMaxSize, int bricksPoolInitialSize, int brickPoolMaxSize, GameContext context) { super(entityPoolInitialSize, entityPoolMaxSize, componentPoolInitialSize, componentPoolMaxSize); idEntities = new ObjectMap<Long, Entity>(); tagEntities = new ObjectMap<String, Array<Entity>>(); dataPools = new DataPools(bricksPoolInitialSize, brickPoolMaxSize); inputs = new InputMultiplexer(); contactSystems = new Array<>(); this.context = context; systemClasses = new ObjectMap<>(); bricksClasses = new ObjectMap<>(); } @Override protected void removeEntityInternal(Entity entity) { IdentityComponent identity = getComponent(entity, IdentityComponent.class, false); if (Settings.DEBUG_ENTITY != null) tag = String.format("%s::%s:", this.getClass().getSimpleName(), identity.tag); Log.debug(tag, "LogicBricksEngine"); idEntities.remove(identity.uuid); tagEntities.get(identity.tag).removeValue(entity, false); super.removeEntityInternal(entity); } @Override public void addSystem(EntitySystem system) { super.addSystem(system); if (EntityListener.class.isInstance(system)) { this.addEntityListener((EntityListener) system); } if (InputProcessor.class.isInstance(system)) { inputs.addProcessor((InputProcessor) system); } if (ContactListener.class.isInstance(system)) { contactSystems.add((ContactListener) system); } } @Override public void addEntity(Entity entity) { super.addEntity(entity); IdentityComponent identity = getComponent(entity, IdentityComponent.class, true); idEntities.put(identity.uuid, entity); configEntity(entity); Log.debug(tag, "AddEntity %d", identity.uuid); } public void update(float deltaTime) { super.update(deltaTime); } @Override public void clearPools() { super.clearPools(); dataPools.clear(); } private void configEntity(Entity entity) { IdentityComponent identity = getComponent(entity, IdentityComponent.class, true); identity.uuid = IDS++; if (Settings.DEBUG_ENTITY != null) tag = String.format("%s::%s:", this.getClass().getSimpleName(), identity.tag); if (!tagEntities.containsKey(identity.tag)) { tagEntities.put(identity.tag, new Array<Entity>()); } tagEntities.get(identity.tag).add(entity); RigidBodiesComponents rigidBodies = getComponent(entity, RigidBodiesComponents.class, false); if (rigidBodies != null) { for (Body rigidBody : rigidBodies.rigidBodies) { rigidBody.setUserData(entity); for (Fixture fixture : rigidBody.getFixtureList()) { Filter filter = new Filter(); filter.categoryBits = identity.category; filter.maskBits = identity.collisionMask; filter.groupIndex = identity.group; fixture.setFilterData(filter); } } } } public <C extends Component> C getComponent(Entity entity, Class<C> clazzComponent, boolean create) { C comp = null; comp = entity.getComponent(clazzComponent); if (comp == null && create) { comp = createComponent(clazzComponent); entity.add(comp); } return comp; } public Entity getEntity(long uuid) { return idEntities.get(uuid); } public Array<Entity> getEntities(String tag) { if (tagEntities.containsKey(tag)) return tagEntities.get(tag); return null; } public <D extends Data> D createData(Class<D> dataType) { return (D) dataPools.obtain(dataType); } public InputMultiplexer getInputs() { return inputs; } public Array<ContactListener> getContactSystems() { return contactSystems; } public GameContext getGameContext() { return context; } public void registerBricksClasses(Class <? extends LogicBrick> brick, Class<? extends Component> component, Class<? extends LogicBrickSystem> system) { bricksClasses.put(brick, new BricksClasses(component, system)); } public void registerEngineClasses(Class<? extends Component> component, Class<? extends LogicBrickSystem> ... system) { systemClasses.put(component, system); } public <L extends LogicBrick> BricksClasses getBricksClasses(Class<L> clazz) { return bricksClasses.get(clazz); } public Class<? extends LogicBrickSystem>[] getSystemClass(Class<? extends Component> clazz) { return systemClasses.get(clazz); } private class DataPools<D extends Data> { private ObjectMap<Class<D>, ReflectionPool> pools; private int initialSize; private int maxSize; public DataPools(int initialSize, int maxSize) { this.pools = new ObjectMap<Class<D>, ReflectionPool>(); this.initialSize = 0; this.maxSize = 0; } public D obtain(Class<D> type) { ReflectionPool pool = pools.get(type); if (pool == null) { pool = new ReflectionPool(type, initialSize, maxSize); pools.put(type, pool); } return (D) pool.obtain(); } public void free(D object) { if (object == null) { throw new IllegalArgumentException("object cannot be null."); } ReflectionPool pool = pools.get((Class<D>) object.getClass()); if (pool == null) { return; // Ignore freeing an object that was never retained. } pool.free(object); } public void freeAll(Array<D> objects) { if (objects == null) throw new IllegalArgumentException("objects cannot be null."); for (int i = 0, n = objects.size; i < n; i++) { D object = objects.get(i); if (object == null) continue; free(object); } } public void clear() { for (Pool pool : pools.values()) { pool.clear(); } } } }