Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
net.namekdev.entity_tracker.EntityTracker Maven / Gradle / Ivy
package net.namekdev.entity_tracker;
import java.util.BitSet;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import net.namekdev.entity_tracker.connectors.WorldController;
import net.namekdev.entity_tracker.connectors.WorldUpdateListener;
import net.namekdev.entity_tracker.model.AspectInfo;
import net.namekdev.entity_tracker.model.ComponentTypeInfo;
import net.namekdev.entity_tracker.model.FieldInfo;
import net.namekdev.entity_tracker.model.SystemInfo;
import net.namekdev.entity_tracker.model.ManagerInfo;
import net.namekdev.entity_tracker.utils.ArrayPool;
import net.namekdev.entity_tracker.utils.ReflectionUtils;
import net.namekdev.entity_tracker.utils.serialization.NetworkSerialization;
import com.artemis.Aspect;
import com.artemis.BaseEntitySystem;
import com.artemis.BaseSystem;
import com.artemis.Component;
import com.artemis.ComponentManager;
import com.artemis.ComponentMapper;
import com.artemis.ComponentType;
import com.artemis.ComponentTypeFactory;
import com.artemis.Entity;
import com.artemis.EntitySubscription;
import com.artemis.EntitySubscription.SubscriptionListener;
import com.artemis.Manager;
import com.artemis.utils.Bag;
import com.artemis.utils.ImmutableBag;
import com.artemis.utils.IntBag;
import com.artemis.utils.reflect.ClassReflection;
import com.artemis.utils.reflect.Field;
import com.artemis.utils.reflect.Method;
import com.artemis.utils.reflect.ReflectionException;
/**
* @author Namek
*
*/
public class EntityTracker extends Manager implements WorldController {
private WorldUpdateListener updateListener;
public final Bag systemsInfo = new Bag();
public final Map systemsInfoByName = new HashMap();
public final Bag managersInfo = new Bag();
public final Map managersInfoByName = new HashMap();
public final Map, ComponentTypeInfo> allComponentTypesInfoByClass = new HashMap, ComponentTypeInfo>();
public final Bag allComponentTypesInfo = new Bag();
public final Bag> allComponentMappers = new Bag>();
protected Method entity_getComponentBits;
protected ComponentTypeFactory typeFactory;
protected Bag allComponentTypes;
private int _notifiedComponentTypesCount = 0;
private final ArrayPool _objectArrPool = new ArrayPool<>(Object.class);
public EntityTracker() {
}
public EntityTracker(WorldUpdateListener listener) {
setUpdateListener(listener);
}
public void setUpdateListener(WorldUpdateListener listener) {
this.updateListener = listener;
listener.injectWorldController(this);
}
@Override
protected void initialize() {
entity_getComponentBits = ReflectionUtils.getHiddenMethod(Entity.class, "getComponentBits");
typeFactory = (ComponentTypeFactory) ReflectionUtils.getHiddenFieldValue(ComponentManager.class, "typeFactory", world.getComponentManager());
allComponentTypes = (Bag) ReflectionUtils.getHiddenFieldValue(ComponentTypeFactory.class, "types", typeFactory);
find42UnicornManagers();
}
private void find42UnicornManagers() {
ImmutableBag systems = world.getSystems();
int index = 0;
for (int i = 0, n = systems.size(); i < n; ++i) {
BaseSystem system = systems.get(i);
if (system instanceof Manager) {
continue;
}
Class extends BaseSystem> systemType = system.getClass();
String systemName = systemType.getSimpleName();
Aspect aspect = null;
BitSet actives = null;
EntitySubscription subscription = null;
if (system instanceof BaseEntitySystem) {
BaseEntitySystem entitySystem = (BaseEntitySystem) system;
subscription = entitySystem.getSubscription();
aspect = subscription.getAspect();
actives = subscription.getActiveEntityIds();
}
AspectInfo aspectInfo = new AspectInfo();
if (aspect != null) {
aspectInfo.allTypes = aspect.getAllSet();
aspectInfo.oneTypes = aspect.getOneSet();
aspectInfo.exclusionTypes = aspect.getExclusionSet();
}
SystemInfo info = new SystemInfo(index, systemName, system, aspect, aspectInfo, actives, subscription);
systemsInfo.add(info);
systemsInfoByName.put(systemName, info);
if (subscription != null) {
listenForEntitySetChanges(info);
}
updateListener.addedSystem(index++, systemName, aspectInfo.allTypes, aspectInfo.oneTypes, aspectInfo.exclusionTypes);
}
for (int i = 0, n = systems.size(); i < n; ++i) {
BaseSystem system = systems.get(i);
if (!(system instanceof Manager)) {
continue;
}
Manager manager = (Manager) system;
Class extends Manager> managerType = manager.getClass();
String managerName = managerType.getSimpleName();
ManagerInfo info = new ManagerInfo(managerName, manager);
managersInfo.add(info);
managersInfoByName.put(managerName, info);
updateListener.addedManager(managerName);
}
}
private void listenForEntitySetChanges(final SystemInfo info) {
info.subscription.addSubscriptionListener(new SubscriptionListener() {
@Override
public void removed(IntBag entities) {
info.entitiesCount -= entities.size();
if (updateListener != null && (updateListener.getListeningBitset() & WorldUpdateListener.ENTITY_SYSTEM_STATS) != 0) {
updateListener.updatedEntitySystem(info.systemIndex, info.entitiesCount, info.maxEntitiesCount);
}
}
@Override
public void inserted(IntBag entities) {
info.entitiesCount += entities.size();
if (info.entitiesCount > info.maxEntitiesCount) {
info.maxEntitiesCount = info.entitiesCount;
}
if (updateListener != null && (updateListener.getListeningBitset() & WorldUpdateListener.ENTITY_SYSTEM_STATS) != 0) {
updateListener.updatedEntitySystem(info.systemIndex, info.entitiesCount, info.maxEntitiesCount);
}
}
});
}
private BitSet componentsToAspectBitset(Collection> componentTypes) {
BitSet bitset = new BitSet(allComponentTypes.size());
for (Class extends Component> componentType : componentTypes) {
int index = typeFactory.getIndexFor(componentType);
bitset.set(index);
}
return bitset;
}
@Override
public void added(Entity e) {
if (updateListener == null || (updateListener.getListeningBitset() & WorldUpdateListener.ENTITY_ADDED) == 0) {
return;
}
BitSet componentBitset = null;
try {
componentBitset = (BitSet) entity_getComponentBits.invoke(e);
}
catch (ReflectionException exc) {
throw new RuntimeException(exc);
}
if (componentBitset.size() > _notifiedComponentTypesCount) {
inspectNewComponentTypesAndNotify();
}
updateListener.addedEntity(e.getId(), (BitSet) componentBitset.clone());
}
@Override
public void deleted(Entity e) {
if (updateListener == null || (updateListener.getListeningBitset() & WorldUpdateListener.ENTITY_DELETED) == 0) {
return;
}
updateListener.deletedEntity(e.getId());
}
private void inspectNewComponentTypesAndNotify() {
int index = _notifiedComponentTypesCount;
int n = allComponentTypes.size();
for (int i = index; i < n; ++i) {
Class type = (Class) ReflectionUtils.getHiddenFieldValue(ComponentType.class, "type", allComponentTypes.get(i));
ComponentTypeInfo info = inspectComponentType(type);
info.index = i;
allComponentTypesInfoByClass.put(type, info);
allComponentTypesInfo.set(i, info);
allComponentMappers.set(i, ComponentMapper.getFor(type, world));
updateListener.addedComponentType(i, info);
++_notifiedComponentTypesCount;
}
}
private ComponentTypeInfo inspectComponentType(Class type) {
Field[] fields = ClassReflection.getDeclaredFields(type);
ComponentTypeInfo info = new ComponentTypeInfo(type);
for (Field field : fields) {
info.fields.add(FieldInfo.reflectField(field));
}
return info;
}
//////////////////////////////////////
// World Controller interface
@Override
public void setSystemState(String name, boolean isOn) {
SystemInfo info = systemsInfoByName.get(name);
info.system.setEnabled(isOn);
}
@Override
public void setManagerState(String name, boolean isOn) {
ManagerInfo info = managersInfoByName.get(name);
info.manager.setEnabled(isOn);
}
@Override
public void requestComponentState(int entityId, int componentIndex) {
final ComponentTypeInfo info = allComponentTypesInfo.get(componentIndex);
final ComponentMapper extends Component> mapper = allComponentMappers.get(componentIndex);
Object component = mapper.get(entityId);
int size = info.fields.size();
Object[] values = _objectArrPool.obtain(size, true);
for (int i = 0; i < size; ++i) {
FieldInfo fieldInfo = info.fields.get(i);
// TODO no support for arrays, yet
if (fieldInfo.isArray) {
values[i] = null;
}
else {
values[i] = ReflectionUtils.getFieldValue(fieldInfo.field, component);
}
}
updateListener.updatedComponentState(entityId, componentIndex, values);
_objectArrPool.free(values, true);
}
@Override
public void setComponentFieldValue(int entityId, int componentIndex, int fieldIndex, Object value) {
final ComponentTypeInfo info = allComponentTypesInfo.get(componentIndex);
final ComponentMapper extends Component> mapper = allComponentMappers.get(componentIndex);
Object component = mapper.get(entityId);
FieldInfo fieldInfo = info.fields.get(fieldIndex);
// TODO we should receive appropriate type here. Convert Strings on GUI side.
if (value instanceof String) {
value = NetworkSerialization.convertStringToTypedValue((String) value, fieldInfo.valueType);
}
try {
fieldInfo.field.set(component, value);
}
catch (ReflectionException e) {
e.printStackTrace();
}
}
}