package com.hypixel.hytale.component;
import com.hypixel.hytale.codec.Codec;
import com.hypixel.hytale.codec.codecs.array.ArrayCodec;
import com.hypixel.hytale.common.util.ArrayUtil;
import com.hypixel.hytale.component.data.ForEachTaskData;
import com.hypixel.hytale.component.data.change.ChangeType;
import com.hypixel.hytale.component.data.change.ComponentChange;
import com.hypixel.hytale.component.data.change.DataChange;
import com.hypixel.hytale.component.data.change.SystemChange;
import com.hypixel.hytale.component.data.unknown.UnknownComponents;
import com.hypixel.hytale.component.event.EntityEventType;
import com.hypixel.hytale.component.event.WorldEventType;
import com.hypixel.hytale.component.metric.ArchetypeChunkData;
import com.hypixel.hytale.component.metric.SystemMetricData;
import com.hypixel.hytale.component.query.ExactArchetypeQuery;
import com.hypixel.hytale.component.query.Query;
import com.hypixel.hytale.component.system.ArchetypeChunkSystem;
import com.hypixel.hytale.component.system.EcsEvent;
import com.hypixel.hytale.component.system.EntityEventSystem;
import com.hypixel.hytale.component.system.HolderSystem;
import com.hypixel.hytale.component.system.ISystem;
import com.hypixel.hytale.component.system.MetricSystem;
import com.hypixel.hytale.component.system.QuerySystem;
import com.hypixel.hytale.component.system.RefChangeSystem;
import com.hypixel.hytale.component.system.RefSystem;
import com.hypixel.hytale.component.system.StoreSystem;
import com.hypixel.hytale.component.system.WorldEventSystem;
import com.hypixel.hytale.component.system.data.ArchetypeDataSystem;
import com.hypixel.hytale.component.system.data.EntityDataSystem;
import com.hypixel.hytale.component.system.tick.ArchetypeTickingSystem;
import com.hypixel.hytale.component.system.tick.EntityTickingSystem;
import com.hypixel.hytale.component.system.tick.TickableSystem;
import com.hypixel.hytale.component.system.tick.TickingSystem;
import com.hypixel.hytale.component.task.ParallelRangeTask;
import com.hypixel.hytale.component.task.ParallelTask;
import com.hypixel.hytale.function.consumer.IntBiObjectConsumer;
import com.hypixel.hytale.metrics.MetricResults;
import com.hypixel.hytale.metrics.MetricsRegistry;
import com.hypixel.hytale.metrics.metric.HistoricMetric;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collection;
import java.util.Deque;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.function.BiConsumer;
import java.util.function.BiPredicate;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class Store<ECS_TYPE> implements ComponentAccessor<ECS_TYPE> {
public static final Store[] EMPTY_ARRAY = new Store[0];
@Nonnull
public static final MetricsRegistry<Store<?>> METRICS_REGISTRY;
@Nonnull
private final ComponentRegistry<ECS_TYPE> registry;
@Nonnull
private final ECS_TYPE externalData;
@Nonnull
private final IResourceStorage resourceStorage;
private final Deque<CommandBuffer<ECS_TYPE>> commandBuffers = new ArrayDeque();
private final Thread thread = Thread.currentThread();
@Nonnull
private final ParallelTask<EntityTickingSystem.SystemTaskData<ECS_TYPE>> parallelTask = new ParallelTask<EntityTickingSystem.SystemTaskData<ECS_TYPE>>(EntityTickingSystem.SystemTaskData::new);
@Nonnull
private final ParallelTask<ForEachTaskData<ECS_TYPE>> forEachTask = new ParallelTask<ForEachTaskData<ECS_TYPE>>(ForEachTaskData::new);
@Nonnull
private final ParallelTask<EntityDataSystem.SystemTaskData<ECS_TYPE, ?, ?>> fetchTask = new ParallelTask<EntityDataSystem.SystemTaskData<ECS_TYPE, ?, ?>>(EntityDataSystem.SystemTaskData::new);
@Nonnull
private final ProcessingCounter processing = new ProcessingCounter();
private boolean shutdown;
int storeIndex;
private int entitiesSize;
@Nonnull
private Ref<ECS_TYPE>[] refs = new Ref[16];
@Nonnull
private int[] entityToArchetypeChunk = new int[16];
@Nonnull
private int[] entityChunkIndex = new int[16];
@Nonnull
private BitSet[] systemIndexToArchetypeChunkIndexes;
@Nonnull
private BitSet[] archetypeChunkIndexesToSystemIndex;
@Nonnull
private final Object2IntMap<Archetype<ECS_TYPE>> archetypeToIndexMap;
private int archetypeSize;
@Nonnull
private final BitSet archetypeChunkReuse;
@Nonnull
private ArchetypeChunk<ECS_TYPE>[] archetypeChunks;
@Nonnull
private Resource<ECS_TYPE>[] resources;
@Nonnull
private HistoricMetric[] systemMetrics;
@Deprecated(
forRemoval = true
)
private boolean disableProcessingAssert;
Store(@Nonnull ComponentRegistry<ECS_TYPE> registry, int storeIndex, @Nonnull ECS_TYPE externalData, @Nonnull IResourceStorage resourceStorage) {
this.systemIndexToArchetypeChunkIndexes = ArrayUtil.EMPTY_BITSET_ARRAY;
this.archetypeChunkIndexesToSystemIndex = ArrayUtil.EMPTY_BITSET_ARRAY;
this.archetypeToIndexMap = new Object2IntOpenHashMap<Archetype<ECS_TYPE>>();
this.archetypeChunkReuse = new BitSet();
this.archetypeChunks = ArchetypeChunk.<ECS_TYPE>emptyArray();
this.resources = Resource.EMPTY_ARRAY;
this.systemMetrics = HistoricMetric.EMPTY_ARRAY;
this.disableProcessingAssert = false;
this.registry = registry;
this.storeIndex = storeIndex;
this.externalData = externalData;
this.resourceStorage = resourceStorage;
this.archetypeToIndexMap.defaultReturnValue(-2147483648);
Arrays.fill(this.entityToArchetypeChunk, -2147483648);
Arrays.fill(this.entityChunkIndex, -2147483648);
}
@Nonnull
CommandBuffer<ECS_TYPE> takeCommandBuffer() {
this.assertThread();
if (this.commandBuffers.isEmpty()) {
return new CommandBuffer<ECS_TYPE>(this);
} else {
CommandBuffer<ECS_TYPE> buffer = (CommandBuffer)this.commandBuffers.pop();
assert buffer.setThread();
return buffer;
}
}
void storeCommandBuffer(@Nonnull CommandBuffer<ECS_TYPE> commandBuffer) {
this.assertThread();
commandBuffer.validateEmpty();
this.commandBuffers.add(commandBuffer);
}
public int getStoreIndex() {
return this.storeIndex;
}
@Nonnull
public ComponentRegistry<ECS_TYPE> getRegistry() {
return this.registry;
}
@Nonnull
public ECS_TYPE getExternalData() {
return this.externalData;
}
@Nonnull
public IResourceStorage getResourceStorage() {
return this.resourceStorage;
}
@Nonnull
public ParallelTask<EntityTickingSystem.SystemTaskData<ECS_TYPE>> getParallelTask() {
return this.parallelTask;
}
@Nonnull
public ParallelTask<EntityDataSystem.SystemTaskData<ECS_TYPE, ?, ?>> getFetchTask() {
return this.fetchTask;
}
@Nonnull
public HistoricMetric[] getSystemMetrics() {
this.assertThread();
return this.systemMetrics;
}
public boolean isShutdown() {
return this.shutdown;
}
void onAdd(@Nonnull ComponentRegistry.Data<ECS_TYPE> data) {
this.updateArchetypeIndexes(data);
int resourceSize = data.getResourceSize();
this.resources = (Resource[])Arrays.copyOf(this.resources, resourceSize);
for(int index = 0; index < resourceSize; ++index) {
ResourceType<ECS_TYPE, ? extends Resource<ECS_TYPE>> resourceType = data.getResourceType(index);
if (resourceType != null) {
this.resources[index] = (Resource)this.resourceStorage.load(this, data, resourceType).join();
}
}
for(int systemIndex = 0; systemIndex < data.getSystemSize(); ++systemIndex) {
this.updateData(data, data, new SystemChange(ChangeType.REGISTERED, data.getSystem(systemIndex)));
}
this.systemMetrics = (HistoricMetric[])Arrays.copyOf(this.systemMetrics, data.getSystemSize());
SystemType<ECS_TYPE, TickableSystem<ECS_TYPE>> tickingSystemType = this.registry.getTickableSystemType();
BitSet systemIndexes = data.getSystemIndexesForType(tickingSystemType);
for(int systemIndex = -1; (systemIndex = systemIndexes.nextSetBit(systemIndex + 1)) >= 0; this.systemMetrics[systemIndex] = HistoricMetric.builder(33333333L, TimeUnit.NANOSECONDS).addPeriod(1L, TimeUnit.SECONDS).addPeriod(1L, TimeUnit.MINUTES).addPeriod(5L, TimeUnit.MINUTES).build()) {
}
}
public void shutdown() {
if (this.shutdown) {
throw new IllegalStateException("Store is already shutdown!");
} else {
this.registry.removeStore(this);
}
}
void shutdown0(@Nonnull ComponentRegistry.Data<ECS_TYPE> data) {
if (this.thread.isAlive() && !this.thread.equals(Thread.currentThread())) {
throw new IllegalArgumentException("Unable to shutdown store while thread is still running!");
} else {
for(int systemIndex = data.getSystemSize() - 1; systemIndex >= 0; --systemIndex) {
this.updateData(data, data, new SystemChange(ChangeType.UNREGISTERED, data.getSystem(systemIndex)));
}
this.saveAllResources0(data).join();
this.processing.lock();
try {
for(int i = 0; i < this.entitiesSize; ++i) {
this.refs[i].invalidate();
this.refs[i] = null;
}
} finally {
this.processing.unlock();
}
this.shutdown = true;
}
}
@Nonnull
public CompletableFuture<Void> saveAllResources() {
return this.saveAllResources0(this.registry.getData());
}
@Nonnull
private CompletableFuture<Void> saveAllResources0(@Nonnull ComponentRegistry.Data<ECS_TYPE> data) {
int resourceSize = data.getResourceSize();
CompletableFuture<Void>[] futures = new CompletableFuture[resourceSize];
int idx = 0;
for(int index = 0; index < resourceSize; ++index) {
ResourceType<ECS_TYPE, ? extends Resource<ECS_TYPE>> resourceType = data.getResourceType(index);
if (resourceType != null) {
futures[idx++] = this.resourceStorage.save(this, data, resourceType, this.resources[index]);
}
}
return CompletableFuture.allOf((CompletableFuture[])Arrays.copyOf(futures, idx));
}
public int getEntityCount() {
return this.entitiesSize;
}
public int getEntityCountFor(@Nonnull Query<ECS_TYPE> query) {
this.assertThread();
if (query instanceof ExactArchetypeQuery<ECS_TYPE> exactQuery) {
int archetypeIndex = this.archetypeToIndexMap.getInt(exactQuery.getArchetype());
return archetypeIndex != -2147483648 ? this.archetypeChunks[archetypeIndex].size() : 0;
} else {
int count = 0;
for(int archetypeIndex = 0; archetypeIndex < this.archetypeSize; ++archetypeIndex) {
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[archetypeIndex];
if (archetypeChunk != null && query.test(archetypeChunk.getArchetype())) {
count += archetypeChunk.size();
}
}
return count;
}
}
public int getEntityCountFor(int systemIndex) {
this.assertThread();
int count = 0;
BitSet indexes = this.systemIndexToArchetypeChunkIndexes[systemIndex];
for(int index = -1; (index = indexes.nextSetBit(index + 1)) >= 0; count += this.archetypeChunks[index].size()) {
}
return count;
}
public int getArchetypeChunkCount() {
this.assertThread();
return this.archetypeSize;
}
@Nonnull
public ArchetypeChunkData[] collectArchetypeChunkData() {
this.assertThread();
ObjectArrayList<ArchetypeChunkData> result = new ObjectArrayList<ArchetypeChunkData>(this.archetypeSize);
for(int i = 0; i < this.archetypeSize; ++i) {
ArchetypeChunk<ECS_TYPE> chunk = this.archetypeChunks[i];
if (chunk != null) {
Archetype<ECS_TYPE> archetype = chunk.getArchetype();
String[] componentTypeNames = new String[archetype.count()];
int nameIndex = 0;
for(int j = archetype.getMinIndex(); j < archetype.length(); ++j) {
ComponentType<ECS_TYPE, ? extends Component<ECS_TYPE>> componentType = archetype.get(j);
if (componentType != null) {
componentTypeNames[nameIndex++] = componentType.getTypeClass().getName();
}
}
result.add(new ArchetypeChunkData(componentTypeNames, chunk.size()));
}
}
return (ArchetypeChunkData[])result.toArray((x$0) -> new ArchetypeChunkData[x$0]);
}
public int getArchetypeChunkCountFor(int systemIndex) {
this.assertThread();
return this.systemIndexToArchetypeChunkIndexes[systemIndex].cardinality();
}
protected void setEntityChunkIndex(@Nonnull Ref<ECS_TYPE> ref, int newEntityChunkIndex) {
if (ref.isValid()) {
this.entityChunkIndex[ref.getIndex()] = newEntityChunkIndex;
}
}
@Nullable
public Ref<ECS_TYPE> addEntity(@Nonnull Archetype<ECS_TYPE> archetype, @Nonnull AddReason reason) {
this.assertThread();
this.assertWriteProcessing();
Component<ECS_TYPE>[] entityComponents;
if (archetype.isEmpty()) {
entityComponents = Component.EMPTY_ARRAY;
} else {
ComponentRegistry.Data<ECS_TYPE> data = this.registry._internal_getData();
entityComponents = new Component[archetype.length()];
for(int i = archetype.getMinIndex(); i < archetype.length(); ++i) {
ComponentType<ECS_TYPE, ? extends Component<ECS_TYPE>> componentType = archetype.get(i);
if (componentType != null) {
entityComponents[componentType.getIndex()] = data.createComponent(componentType);
}
}
}
return this.addEntity(this.registry.newHolder(archetype, entityComponents), new Ref(this), reason);
}
@Nullable
public Ref<ECS_TYPE> addEntity(@Nonnull Holder<ECS_TYPE> holder, @Nonnull AddReason reason) {
return this.addEntity(holder, new Ref(this), reason);
}
@Nullable
public Ref<ECS_TYPE> addEntity(@Nonnull Holder<ECS_TYPE> holder, @Nonnull Ref<ECS_TYPE> ref, @Nonnull AddReason reason) {
if (ref.isValid()) {
throw new IllegalArgumentException("EntityReference is already in use!");
} else if (ref.getStore() != this) {
throw new IllegalArgumentException("EntityReference is not for this store!");
} else {
this.assertThread();
this.assertWriteProcessing();
CommandBuffer<ECS_TYPE> commandBuffer = this.takeCommandBuffer();
ComponentRegistry.Data<ECS_TYPE> data = this.registry._internal_getData();
this.processing.lock();
try {
SystemType<ECS_TYPE, HolderSystem<ECS_TYPE>> systemType = this.registry.getHolderSystemType();
BitSet systemIndexes = data.getSystemIndexesForType(systemType);
int systemIndex = -1;
while((systemIndex = systemIndexes.nextSetBit(systemIndex + 1)) >= 0) {
HolderSystem<ECS_TYPE> system = (HolderSystem)data.getSystem(systemIndex, systemType);
if (system.test(this.registry, holder.getArchetype())) {
system.onEntityAdd(holder, reason, this);
}
}
int entityIndex = this.entitiesSize++;
int oldLength = this.refs.length;
if (oldLength <= entityIndex) {
systemIndex = ArrayUtil.grow(entityIndex);
this.refs = (Ref[])Arrays.copyOf(this.refs, systemIndex);
this.entityToArchetypeChunk = Arrays.copyOf(this.entityToArchetypeChunk, systemIndex);
this.entityChunkIndex = Arrays.copyOf(this.entityChunkIndex, systemIndex);
Arrays.fill(this.entityToArchetypeChunk, oldLength, systemIndex, -2147483648);
Arrays.fill(this.entityChunkIndex, oldLength, systemIndex, -2147483648);
}
this.refs[entityIndex] = ref;
ref.setIndex(entityIndex);
systemIndex = this.findOrCreateArchetypeChunk(holder.getArchetype());
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[systemIndex];
int chunkEntityRef = archetypeChunk.addEntity(ref, holder);
this.entityToArchetypeChunk[entityIndex] = systemIndex;
this.entityChunkIndex[entityIndex] = chunkEntityRef;
SystemType<ECS_TYPE, RefSystem<ECS_TYPE>> systemType = this.registry.getRefSystemType();
BitSet systemIndexes = data.getSystemIndexesForType(systemType);
BitSet entityProcessedBySystemIndexes = this.archetypeChunkIndexesToSystemIndex[systemIndex];
commandBuffer.track(ref);
int systemIndex = -1;
while((systemIndex = systemIndexes.nextSetBit(systemIndex + 1)) >= 0) {
if (entityProcessedBySystemIndexes.get(systemIndex)) {
RefSystem<ECS_TYPE> system = (RefSystem)data.getSystem(systemIndex, systemType);
boolean oldDisableProcessingAssert = this.disableProcessingAssert;
this.disableProcessingAssert = system instanceof DisableProcessingAssert;
system.onEntityAdded(ref, reason, this, commandBuffer);
this.disableProcessingAssert = oldDisableProcessingAssert;
if (commandBuffer.consumeWasTrackedRefRemoved()) {
break;
}
}
}
} finally {
this.processing.unlock();
}
commandBuffer.consume();
return ref.isValid() ? ref : null;
}
}
@Nonnull
public Ref<ECS_TYPE>[] addEntities(@Nonnull Holder<ECS_TYPE>[] holders, @Nonnull AddReason reason) {
return this.addEntities(holders, 0, holders.length, reason);
}
@Nonnull
public Ref<ECS_TYPE>[] addEntities(@Nonnull Holder<ECS_TYPE>[] holders, int start, int length, @Nonnull AddReason reason) {
Ref<ECS_TYPE>[] refs = new Ref[length];
for(int i = 0; i < length; ++i) {
refs[i] = new Ref(this);
}
this.addEntities(holders, start, refs, 0, length, reason);
return refs;
}
public void addEntities(@Nonnull Holder<ECS_TYPE>[] holders, @Nonnull Ref<ECS_TYPE>[] refs, @Nonnull AddReason reason) {
if (holders.length != refs.length) {
throw new IllegalArgumentException("EntityHolder and EntityReference array length doesn't match!");
} else {
this.addEntities(holders, 0, refs, 0, holders.length, reason);
}
}
public void addEntities(@Nonnull Holder<ECS_TYPE>[] holders, int holderStart, @Nonnull Ref<ECS_TYPE>[] refs, int refStart, int length, @Nonnull AddReason reason) {
int holderEnd = holderStart + length;
int refEnd = refStart + length;
if (holders.length < holderEnd) {
throw new IllegalArgumentException("EntityHolder start and length exceed array length!");
} else if (refs.length < refEnd) {
throw new IllegalArgumentException("EntityReference start and length exceed array length!");
} else {
for(int i = refStart; i < refEnd; ++i) {
Ref<ECS_TYPE> ref = refs[i];
if (ref.isValid()) {
throw new IllegalArgumentException("EntityReference is already in use!");
}
if (ref.getStore() != this) {
throw new IllegalArgumentException("EntityReference is not for this store!");
}
}
this.assertThread();
this.assertWriteProcessing();
CommandBuffer<ECS_TYPE> commandBuffer = this.takeCommandBuffer();
ComponentRegistry.Data<ECS_TYPE> data = this.registry._internal_getData();
this.processing.lock();
try {
SystemType<ECS_TYPE, HolderSystem<ECS_TYPE>> systemType = this.registry.getHolderSystemType();
BitSet systemIndexes = data.getSystemIndexesForType(systemType);
int systemIndex = -1;
while((systemIndex = systemIndexes.nextSetBit(systemIndex + 1)) >= 0) {
HolderSystem<ECS_TYPE> system = (HolderSystem)data.getSystem(systemIndex, systemType);
for(int i = holderStart; i < holderEnd; ++i) {
if (system.test(this.registry, holders[i].getArchetype())) {
system.onEntityAdd(holders[i], reason, this);
}
}
}
int firstIndex = this.entitiesSize;
this.entitiesSize += length;
int oldLength = this.refs.length;
if (oldLength <= this.entitiesSize) {
systemIndex = ArrayUtil.grow(this.entitiesSize);
this.refs = (Ref[])Arrays.copyOf(this.refs, systemIndex);
this.entityToArchetypeChunk = Arrays.copyOf(this.entityToArchetypeChunk, systemIndex);
this.entityChunkIndex = Arrays.copyOf(this.entityChunkIndex, systemIndex);
Arrays.fill(this.entityToArchetypeChunk, oldLength, systemIndex, -2147483648);
Arrays.fill(this.entityChunkIndex, oldLength, systemIndex, -2147483648);
}
System.arraycopy(refs, refStart, this.refs, firstIndex, length);
systemIndex = refStart;
for(int entityIndex = firstIndex; systemIndex < refEnd; ++entityIndex) {
refs[systemIndex].setIndex(entityIndex);
++systemIndex;
}
systemIndex = 0;
for(int entityIndex = firstIndex; systemIndex < length; ++entityIndex) {
Ref<ECS_TYPE> ref = refs[refStart + systemIndex];
Holder<ECS_TYPE> holder = holders[holderStart + systemIndex];
int archetypeIndex = this.findOrCreateArchetypeChunk(holder.getArchetype());
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[archetypeIndex];
int chunkEntityRef = archetypeChunk.addEntity(ref, holder);
this.entityToArchetypeChunk[entityIndex] = archetypeIndex;
this.entityChunkIndex[entityIndex] = chunkEntityRef;
++systemIndex;
}
SystemType<ECS_TYPE, RefSystem<ECS_TYPE>> systemType = this.registry.getRefSystemType();
BitSet systemIndexes = data.getSystemIndexesForType(systemType);
int systemIndex = -1;
while((systemIndex = systemIndexes.nextSetBit(systemIndex + 1)) >= 0) {
for(int i = refStart; i < refEnd; ++i) {
Ref<ECS_TYPE> ref = refs[i];
int archetypeIndex = this.entityToArchetypeChunk[ref.getIndex()];
BitSet entityProcessedBySystemIndexes = this.archetypeChunkIndexesToSystemIndex[archetypeIndex];
if (entityProcessedBySystemIndexes.get(systemIndex)) {
RefSystem<ECS_TYPE> system = (RefSystem)data.getSystem(systemIndex, systemType);
boolean oldDisableProcessingAssert = this.disableProcessingAssert;
this.disableProcessingAssert = system instanceof DisableProcessingAssert;
commandBuffer.track(ref);
system.onEntityAdded(ref, reason, this, commandBuffer);
if (commandBuffer.consumeWasTrackedRefRemoved()) {
int remaining = refEnd - i;
if (remaining > 1) {
System.arraycopy(refs, i + 1, refs, i, remaining - 1);
refs[refEnd - 1] = ref;
--i;
}
--refEnd;
--length;
}
this.disableProcessingAssert = oldDisableProcessingAssert;
}
}
}
} finally {
this.processing.unlock();
}
commandBuffer.consume();
}
}
@Nonnull
public Holder<ECS_TYPE> copyEntity(@Nonnull Ref<ECS_TYPE> ref) {
return this.copyEntity(ref, this.registry.newHolder());
}
@Nonnull
public Holder<ECS_TYPE> copyEntity(@Nonnull Ref<ECS_TYPE> ref, @Nonnull Holder<ECS_TYPE> holder) {
this.assertThread();
ref.validate();
int refIndex = ref.getIndex();
int archetypeIndex = this.entityToArchetypeChunk[refIndex];
return this.archetypeChunks[archetypeIndex].copyEntity(this.entityChunkIndex[refIndex], holder);
}
@Nonnull
public Holder<ECS_TYPE> copySerializableEntity(@Nonnull Ref<ECS_TYPE> ref) {
return this.copySerializableEntity(ref, this.registry.newHolder());
}
@Nonnull
public Holder<ECS_TYPE> copySerializableEntity(@Nonnull Ref<ECS_TYPE> ref, @Nonnull Holder<ECS_TYPE> holder) {
this.assertThread();
ref.validate();
int refIndex = ref.getIndex();
int archetypeIndex = this.entityToArchetypeChunk[refIndex];
return this.archetypeChunks[archetypeIndex].copySerializableEntity(this.registry.getData(), this.entityChunkIndex[refIndex], holder);
}
@Nonnull
public Archetype<ECS_TYPE> getArchetype(@Nonnull Ref<ECS_TYPE> ref) {
this.assertThread();
ref.validate();
int archetypeIndex = this.entityToArchetypeChunk[ref.getIndex()];
return this.archetypeChunks[archetypeIndex].getArchetype();
}
@Nonnull
protected Archetype<ECS_TYPE> __internal_getArchetype(@Nonnull Ref<ECS_TYPE> ref) {
ref.validate();
int archetypeIndex = this.entityToArchetypeChunk[ref.getIndex()];
return this.archetypeChunks[archetypeIndex].getArchetype();
}
@Nonnull
public Holder<ECS_TYPE> removeEntity(@Nonnull Ref<ECS_TYPE> ref, @Nonnull RemoveReason reason) {
return this.removeEntity(ref, this.registry.newHolder(), reason);
}
@Nonnull
public Holder<ECS_TYPE> removeEntity(@Nonnull Ref<ECS_TYPE> ref, @Nonnull Holder<ECS_TYPE> holder, @Nonnull RemoveReason reason) {
return this.removeEntity(ref, holder, reason, (Throwable)null);
}
@Nonnull
Holder<ECS_TYPE> removeEntity(@Nonnull Ref<ECS_TYPE> ref, @Nonnull Holder<ECS_TYPE> holder, @Nonnull RemoveReason reason, @Nullable Throwable proxyReason) {
this.assertThread();
this.assertWriteProcessing();
ref.validate();
CommandBuffer<ECS_TYPE> commandBuffer = this.takeCommandBuffer();
int entityIndex = ref.getIndex();
int archetypeIndex = this.entityToArchetypeChunk[entityIndex];
int chunkEntityRef = this.entityChunkIndex[entityIndex];
ComponentRegistry.Data<ECS_TYPE> data = this.registry._internal_getData();
this.processing.lock();
try {
SystemType<ECS_TYPE, RefSystem<ECS_TYPE>> systemType = this.registry.getRefSystemType();
BitSet systemIndexes = data.getSystemIndexesForType(systemType);
BitSet entityProcessedBySystemIndexes = this.archetypeChunkIndexesToSystemIndex[archetypeIndex];
int systemIndex = -1;
while((systemIndex = systemIndexes.nextSetBit(systemIndex + 1)) >= 0) {
if (entityProcessedBySystemIndexes.get(systemIndex)) {
((RefSystem)data.getSystem(systemIndex, systemType)).onEntityRemove(ref, reason, this, commandBuffer);
}
}
int lastIndex = this.entitiesSize - 1;
if (entityIndex != lastIndex) {
Ref<ECS_TYPE> lastEntityRef = this.refs[lastIndex];
int lastSelfEntityRef = this.entityToArchetypeChunk[lastIndex];
systemIndex = this.entityChunkIndex[lastIndex];
lastEntityRef.setIndex(entityIndex);
this.refs[entityIndex] = lastEntityRef;
this.entityToArchetypeChunk[entityIndex] = lastSelfEntityRef;
this.entityChunkIndex[entityIndex] = systemIndex;
}
this.refs[lastIndex] = null;
this.entityToArchetypeChunk[lastIndex] = -2147483648;
this.entityChunkIndex[lastIndex] = -2147483648;
this.entitiesSize = lastIndex;
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[archetypeIndex];
archetypeChunk.removeEntity(chunkEntityRef, holder);
if (archetypeChunk.size() == 0) {
this.removeArchetypeChunk(archetypeIndex);
}
ref.invalidate(proxyReason);
} finally {
this.processing.unlock();
}
commandBuffer.consume();
this.processing.lock();
try {
SystemType<ECS_TYPE, HolderSystem<ECS_TYPE>> systemType = this.registry.getHolderSystemType();
BitSet systemIndexes = data.getSystemIndexesForType(systemType);
int systemIndex = -1;
while((systemIndex = systemIndexes.nextSetBit(systemIndex + 1)) >= 0) {
HolderSystem<ECS_TYPE> system = (HolderSystem)data.getSystem(systemIndex, systemType);
if (system.test(this.registry, holder.getArchetype())) {
system.onEntityRemoved(holder, reason, this);
}
}
} finally {
this.processing.unlock();
}
return holder;
}
@Nonnull
public Holder<ECS_TYPE>[] removeEntities(@Nonnull Ref<ECS_TYPE>[] refs, @Nonnull RemoveReason reason) {
return this.removeEntities(refs, 0, refs.length, reason);
}
@Nonnull
public Holder<ECS_TYPE>[] removeEntities(@Nonnull Ref<ECS_TYPE>[] refs, int start, int length, @Nonnull RemoveReason reason) {
Holder<ECS_TYPE>[] holders = new Holder[length];
for(int i = 0; i < length; ++i) {
holders[i] = this.registry.newHolder();
}
return this.removeEntities(refs, start, holders, 0, length, reason);
}
@Nonnull
public Holder<ECS_TYPE>[] removeEntities(@Nonnull Ref<ECS_TYPE>[] refs, @Nonnull Holder<ECS_TYPE>[] holders, @Nonnull RemoveReason reason) {
if (refs.length != holders.length) {
throw new IllegalArgumentException("EntityHolder and EntityReference array length doesn't match!");
} else {
return this.removeEntities(refs, 0, holders, 0, refs.length, reason);
}
}
@Nonnull
public Holder<ECS_TYPE>[] removeEntities(@Nonnull Ref<ECS_TYPE>[] refArr, int refStart, @Nonnull Holder<ECS_TYPE>[] holders, int holderStart, int length, @Nonnull RemoveReason reason) {
int refEnd = refStart + length;
int holderEnd = holderStart + length;
if (refArr.length < refEnd) {
throw new IllegalArgumentException("EntityReference start and length exceed array length!");
} else if (holders.length < holderEnd) {
throw new IllegalArgumentException("EntityHolder start and length exceed array length!");
} else {
for(int i = refStart; i < refEnd; ++i) {
refArr[i].validate();
}
this.assertThread();
this.assertWriteProcessing();
CommandBuffer<ECS_TYPE> commandBuffer = this.takeCommandBuffer();
ComponentRegistry.Data<ECS_TYPE> data = this.registry._internal_getData();
this.processing.lock();
try {
SystemType<ECS_TYPE, RefSystem<ECS_TYPE>> systemType = this.registry.getRefSystemType();
BitSet systemIndexes = data.getSystemIndexesForType(systemType);
int systemIndex = -1;
while((systemIndex = systemIndexes.nextSetBit(systemIndex + 1)) >= 0) {
for(int i = refStart; i < refEnd; ++i) {
Ref<ECS_TYPE> ref = refArr[i];
int archetypeIndex = this.entityToArchetypeChunk[ref.getIndex()];
BitSet entityProcessedBySystemIndexes = this.archetypeChunkIndexesToSystemIndex[archetypeIndex];
if (entityProcessedBySystemIndexes.get(systemIndex)) {
((RefSystem)data.getSystem(systemIndex, systemType)).onEntityRemove(refArr[i], reason, this, commandBuffer);
}
}
}
for(int i = 0; i < length; ++i) {
int entityIndex = refArr[refStart + i].getIndex();
systemIndex = this.entityToArchetypeChunk[entityIndex];
int chunkEntityRef = this.entityChunkIndex[entityIndex];
int lastIndex = this.entitiesSize - 1;
if (entityIndex != lastIndex) {
Ref<ECS_TYPE> lastEntityRef = this.refs[lastIndex];
int lastSelfEntityRef = this.entityToArchetypeChunk[lastIndex];
int lastEntityChunkIndex = this.entityChunkIndex[lastIndex];
lastEntityRef.setIndex(entityIndex);
this.refs[entityIndex] = lastEntityRef;
this.entityToArchetypeChunk[entityIndex] = lastSelfEntityRef;
this.entityChunkIndex[entityIndex] = lastEntityChunkIndex;
}
this.refs[lastIndex] = null;
this.entityToArchetypeChunk[lastIndex] = -2147483648;
this.entityChunkIndex[lastIndex] = -2147483648;
this.entitiesSize = lastIndex;
Holder<ECS_TYPE> holder = holders[holderStart + i];
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[systemIndex];
archetypeChunk.removeEntity(chunkEntityRef, holder);
if (archetypeChunk.size() == 0) {
this.removeArchetypeChunk(systemIndex);
}
}
for(int i = refStart; i < refEnd; ++i) {
refArr[i].invalidate();
}
} finally {
this.processing.unlock();
}
commandBuffer.consume();
this.processing.lock();
try {
SystemType<ECS_TYPE, HolderSystem<ECS_TYPE>> systemType = this.registry.getHolderSystemType();
BitSet systemIndexes = data.getSystemIndexesForType(systemType);
int systemIndex = -1;
while((systemIndex = systemIndexes.nextSetBit(systemIndex + 1)) >= 0) {
HolderSystem<ECS_TYPE> system = (HolderSystem)data.getSystem(systemIndex, systemType);
for(int i = holderStart; i < holderEnd; ++i) {
if (system.test(this.registry, holders[i].getArchetype())) {
system.onEntityRemoved(holders[i], reason, this);
}
}
}
} finally {
this.processing.unlock();
}
return holders;
}
}
public <T extends Component<ECS_TYPE>> void ensureComponent(@Nonnull Ref<ECS_TYPE> ref, @Nonnull ComponentType<ECS_TYPE, T> componentType) {
this.assertThread();
this.assertWriteProcessing();
componentType.validateRegistry(this.registry);
componentType.validate();
CommandBuffer<ECS_TYPE> commandBuffer = this.takeCommandBuffer();
int archetypeIndex = this.entityToArchetypeChunk[ref.getIndex()];
this.processing.lock();
try {
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[archetypeIndex];
if (!archetypeChunk.getArchetype().contains(componentType)) {
T component = this.registry._internal_getData().createComponent(componentType);
this.datachunk_addComponent(ref, archetypeIndex, componentType, component, commandBuffer);
}
} finally {
this.processing.unlock();
}
commandBuffer.consume();
}
@Nonnull
public <T extends Component<ECS_TYPE>> T ensureAndGetComponent(@Nonnull Ref<ECS_TYPE> ref, @Nonnull ComponentType<ECS_TYPE, T> componentType) {
this.assertThread();
this.assertWriteProcessing();
int refIndex = ref.getIndex();
componentType.validateRegistry(this.registry);
componentType.validate();
CommandBuffer<ECS_TYPE> commandBuffer = this.takeCommandBuffer();
int archetypeIndex = this.entityToArchetypeChunk[refIndex];
this.processing.lock();
T component;
try {
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[archetypeIndex];
component = archetypeChunk.getComponent(this.entityChunkIndex[refIndex], componentType);
if (component == null) {
component = this.registry._internal_getData().createComponent(componentType);
this.datachunk_addComponent(ref, archetypeIndex, componentType, component, commandBuffer);
}
} finally {
this.processing.unlock();
}
commandBuffer.consume();
return component;
}
@Nonnull
public <T extends Component<ECS_TYPE>> T addComponent(@Nonnull Ref<ECS_TYPE> ref, @Nonnull ComponentType<ECS_TYPE, T> componentType) {
this.assertThread();
this.assertWriteProcessing();
T component = this.registry._internal_getData().createComponent(componentType);
this.addComponent(ref, componentType, component);
return component;
}
public <T extends Component<ECS_TYPE>> void addComponent(@Nonnull Ref<ECS_TYPE> ref, @Nonnull ComponentType<ECS_TYPE, T> componentType, @Nonnull T component) {
this.assertThread();
this.assertWriteProcessing();
ref.validate();
componentType.validateRegistry(this.registry);
componentType.validate();
Objects.requireNonNull(component);
CommandBuffer<ECS_TYPE> commandBuffer = this.takeCommandBuffer();
int archetypeIndex = this.entityToArchetypeChunk[ref.getIndex()];
this.processing.lock();
try {
this.datachunk_addComponent(ref, archetypeIndex, componentType, component, commandBuffer);
} finally {
this.processing.unlock();
}
commandBuffer.consume();
}
public <T extends Component<ECS_TYPE>> void replaceComponent(@Nonnull Ref<ECS_TYPE> ref, @Nonnull ComponentType<ECS_TYPE, T> componentType, @Nonnull T component) {
this.assertThread();
this.assertWriteProcessing();
ref.validate();
componentType.validateRegistry(this.registry);
componentType.validate();
Objects.requireNonNull(component);
CommandBuffer<ECS_TYPE> commandBuffer = this.takeCommandBuffer();
int archetypeIndex = this.entityToArchetypeChunk[ref.getIndex()];
this.processing.lock();
try {
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[archetypeIndex];
int chunkEntityRef = this.entityChunkIndex[ref.getIndex()];
T oldComponent = archetypeChunk.getComponent(chunkEntityRef, componentType);
archetypeChunk.setComponent(chunkEntityRef, componentType, component);
BitSet entityProcessedBySystemIndexes = this.archetypeChunkIndexesToSystemIndex[archetypeIndex];
ComponentRegistry.Data<ECS_TYPE> data = this.registry._internal_getData();
BitSet systemIndexes = data.getSystemIndexesForType(this.registry.getRefChangeSystemType());
int systemIndex = -1;
while((systemIndex = systemIndexes.nextSetBit(systemIndex + 1)) >= 0) {
if (entityProcessedBySystemIndexes.get(systemIndex)) {
RefChangeSystem<ECS_TYPE, T> system = (RefChangeSystem)data.getSystem(systemIndex);
if (system.componentType().getIndex() == componentType.getIndex()) {
system.onComponentSet(ref, oldComponent, component, this, commandBuffer);
}
}
}
} finally {
this.processing.unlock();
}
commandBuffer.consume();
}
public <T extends Component<ECS_TYPE>> void putComponent(@Nonnull Ref<ECS_TYPE> ref, @Nonnull ComponentType<ECS_TYPE, T> componentType, @Nonnull T component) {
this.assertThread();
this.assertWriteProcessing();
ref.validate();
componentType.validateRegistry(this.registry);
componentType.validate();
Objects.requireNonNull(component);
CommandBuffer<ECS_TYPE> commandBuffer = this.takeCommandBuffer();
int archetypeIndex = this.entityToArchetypeChunk[ref.getIndex()];
this.processing.lock();
try {
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[archetypeIndex];
if (archetypeChunk.getArchetype().contains(componentType)) {
int chunkEntityRef = this.entityChunkIndex[ref.getIndex()];
T oldComponent = archetypeChunk.getComponent(chunkEntityRef, componentType);
archetypeChunk.setComponent(chunkEntityRef, componentType, component);
BitSet entityProcessedBySystemIndexes = this.archetypeChunkIndexesToSystemIndex[archetypeIndex];
ComponentRegistry.Data<ECS_TYPE> data = this.registry._internal_getData();
BitSet systemIndexes = data.getSystemIndexesForType(this.registry.getRefChangeSystemType());
int systemIndex = -1;
while((systemIndex = systemIndexes.nextSetBit(systemIndex + 1)) >= 0) {
if (entityProcessedBySystemIndexes.get(systemIndex)) {
RefChangeSystem<ECS_TYPE, T> system = (RefChangeSystem)data.getSystem(systemIndex);
if (system.componentType().getIndex() == componentType.getIndex()) {
system.onComponentSet(ref, oldComponent, component, this, commandBuffer);
}
}
}
} else {
this.datachunk_addComponent(ref, archetypeIndex, componentType, component, commandBuffer);
}
} finally {
this.processing.unlock();
}
commandBuffer.consume();
}
public <T extends Component<ECS_TYPE>> T getComponent(@Nonnull Ref<ECS_TYPE> ref, @Nonnull ComponentType<ECS_TYPE, T> componentType) {
this.assertThread();
return (T)this.__internal_getComponent(ref, componentType);
}
@Nullable
protected <T extends Component<ECS_TYPE>> T __internal_getComponent(@Nonnull Ref<ECS_TYPE> ref, @Nonnull ComponentType<ECS_TYPE, T> componentType) {
ref.validate();
componentType.validateRegistry(this.registry);
componentType.validate();
int archetypeIndex = this.entityToArchetypeChunk[ref.getIndex()];
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[archetypeIndex];
return (T)archetypeChunk.getComponent(this.entityChunkIndex[ref.getIndex()], componentType);
}
public <T extends Component<ECS_TYPE>> void removeComponent(@Nonnull Ref<ECS_TYPE> ref, @Nonnull ComponentType<ECS_TYPE, T> componentType) {
this.assertThread();
this.assertWriteProcessing();
ref.validate();
componentType.validateRegistry(this.registry);
componentType.validate();
CommandBuffer<ECS_TYPE> commandBuffer = this.takeCommandBuffer();
int entityIndex = ref.getIndex();
int fromArchetypeIndex = this.entityToArchetypeChunk[entityIndex];
this.processing.lock();
try {
ArchetypeChunk<ECS_TYPE> fromArchetypeChunk = this.archetypeChunks[fromArchetypeIndex];
Holder<ECS_TYPE> holder = this.registry._internal_newEntityHolder();
fromArchetypeChunk.removeEntity(this.entityChunkIndex[entityIndex], holder);
T component = holder.getComponent(componentType);
assert component != null;
holder.removeComponent(componentType);
int toArchetypeIndex = this.findOrCreateArchetypeChunk(holder.getArchetype());
ArchetypeChunk<ECS_TYPE> toArchetypeChunk = this.archetypeChunks[toArchetypeIndex];
int chunkEntityRef = toArchetypeChunk.addEntity(ref, holder);
this.entityToArchetypeChunk[entityIndex] = toArchetypeIndex;
this.entityChunkIndex[entityIndex] = chunkEntityRef;
BitSet entityProcessedBySystemIndexes = this.archetypeChunkIndexesToSystemIndex[fromArchetypeIndex];
ComponentRegistry.Data<ECS_TYPE> data = this.registry._internal_getData();
BitSet systemIndexes = data.getSystemIndexesForType(this.registry.getRefChangeSystemType());
int systemIndex = -1;
while((systemIndex = systemIndexes.nextSetBit(systemIndex + 1)) >= 0) {
if (entityProcessedBySystemIndexes.get(systemIndex)) {
RefChangeSystem<ECS_TYPE, T> system = (RefChangeSystem)data.getSystem(systemIndex);
if (system.componentType().getIndex() == componentType.getIndex()) {
system.onComponentRemoved(ref, component, this, commandBuffer);
}
}
}
if (fromArchetypeChunk.size() == 0) {
this.removeArchetypeChunk(fromArchetypeIndex);
}
} finally {
this.processing.unlock();
}
commandBuffer.consume();
}
public <T extends Component<ECS_TYPE>> void tryRemoveComponent(@Nonnull Ref<ECS_TYPE> ref, @Nonnull ComponentType<ECS_TYPE, T> componentType) {
this.removeComponentIfExists(ref, componentType);
}
public <T extends Component<ECS_TYPE>> boolean removeComponentIfExists(@Nonnull Ref<ECS_TYPE> ref, @Nonnull ComponentType<ECS_TYPE, T> componentType) {
this.assertThread();
this.assertWriteProcessing();
ref.validate();
componentType.validateRegistry(this.registry);
componentType.validate();
CommandBuffer<ECS_TYPE> commandBuffer = this.takeCommandBuffer();
int entityIndex = ref.getIndex();
int fromArchetypeIndex = this.entityToArchetypeChunk[entityIndex];
this.processing.lock();
boolean result;
try {
ArchetypeChunk<ECS_TYPE> fromArchetypeChunk = this.archetypeChunks[fromArchetypeIndex];
if (!fromArchetypeChunk.getArchetype().contains(componentType)) {
result = false;
} else {
Holder<ECS_TYPE> holder = this.registry._internal_newEntityHolder();
fromArchetypeChunk.removeEntity(this.entityChunkIndex[entityIndex], holder);
T component = holder.getComponent(componentType);
assert component != null;
holder.removeComponent(componentType);
int toArchetypeIndex = this.findOrCreateArchetypeChunk(holder.getArchetype());
ArchetypeChunk<ECS_TYPE> toArchetypeChunk = this.archetypeChunks[toArchetypeIndex];
int chunkEntityRef = toArchetypeChunk.addEntity(ref, holder);
this.entityToArchetypeChunk[entityIndex] = toArchetypeIndex;
this.entityChunkIndex[entityIndex] = chunkEntityRef;
BitSet entityProcessedBySystemIndexes = this.archetypeChunkIndexesToSystemIndex[fromArchetypeIndex];
ComponentRegistry.Data<ECS_TYPE> data = this.registry._internal_getData();
BitSet systemIndexes = data.getSystemIndexesForType(this.registry.getRefChangeSystemType());
int systemIndex = -1;
while((systemIndex = systemIndexes.nextSetBit(systemIndex + 1)) >= 0) {
if (entityProcessedBySystemIndexes.get(systemIndex)) {
RefChangeSystem<ECS_TYPE, T> system = (RefChangeSystem)data.getSystem(systemIndex);
if (system.componentType().getIndex() == componentType.getIndex()) {
system.onComponentRemoved(ref, component, this, commandBuffer);
}
}
}
if (fromArchetypeChunk.size() == 0) {
this.removeArchetypeChunk(fromArchetypeIndex);
}
result = true;
}
} finally {
this.processing.unlock();
}
commandBuffer.consume();
return result;
}
public <T extends Resource<ECS_TYPE>> void replaceResource(@Nonnull ResourceType<ECS_TYPE, T> resourceType, @Nonnull T resource) {
this.assertThread();
resourceType.validateRegistry(this.registry);
Objects.requireNonNull(resource);
this.resources[resourceType.getIndex()] = resource;
}
@Nonnull
public <T extends Resource<ECS_TYPE>> T getResource(@Nonnull ResourceType<ECS_TYPE, T> resourceType) {
resourceType.validateRegistry(this.registry);
return (T)this.resources[resourceType.getIndex()];
}
@Nonnull
protected <T extends Resource<ECS_TYPE>> T __internal_getResource(@Nonnull ResourceType<ECS_TYPE, T> resourceType) {
resourceType.validateRegistry(this.registry);
return (T)this.resources[resourceType.getIndex()];
}
public void forEachChunk(@Nonnull BiConsumer<ArchetypeChunk<ECS_TYPE>, CommandBuffer<ECS_TYPE>> consumer) {
if (this.shutdown) {
throw new IllegalStateException("Store is shutdown!");
} else {
this.assertThread();
CommandBuffer<ECS_TYPE> commandBuffer = this.takeCommandBuffer();
this.processing.lock();
try {
for(int archetypeIndex = 0; archetypeIndex < this.archetypeSize; ++archetypeIndex) {
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[archetypeIndex];
if (archetypeChunk != null) {
consumer.accept(archetypeChunk, commandBuffer);
}
}
} finally {
this.processing.unlock();
}
commandBuffer.consume();
}
}
public boolean forEachChunk(@Nonnull BiPredicate<ArchetypeChunk<ECS_TYPE>, CommandBuffer<ECS_TYPE>> predicate) {
if (this.shutdown) {
throw new IllegalStateException("Store is shutdown!");
} else {
this.assertThread();
CommandBuffer<ECS_TYPE> commandBuffer = this.takeCommandBuffer();
boolean result = false;
this.processing.lock();
try {
for(int archetypeIndex = 0; archetypeIndex < this.archetypeSize; ++archetypeIndex) {
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[archetypeIndex];
if (archetypeChunk != null && predicate.test(archetypeChunk, commandBuffer)) {
result = true;
break;
}
}
} finally {
this.processing.unlock();
}
commandBuffer.consume();
return result;
}
}
public void forEachChunk(Query<ECS_TYPE> query, @Nonnull BiConsumer<ArchetypeChunk<ECS_TYPE>, CommandBuffer<ECS_TYPE>> consumer) {
if (this.shutdown) {
throw new IllegalStateException("Store is shutdown!");
} else {
this.assertThread();
CommandBuffer<ECS_TYPE> commandBuffer = this.takeCommandBuffer();
this.processing.lock();
try {
if (query instanceof ExactArchetypeQuery) {
ExactArchetypeQuery<ECS_TYPE> exactQuery = (ExactArchetypeQuery)query;
int archetypeIndex = this.archetypeToIndexMap.getInt(exactQuery.getArchetype());
if (archetypeIndex != -2147483648) {
consumer.accept(this.archetypeChunks[archetypeIndex], commandBuffer);
}
} else {
for(int archetypeIndex = 0; archetypeIndex < this.archetypeSize; ++archetypeIndex) {
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[archetypeIndex];
if (archetypeChunk != null && query.test(archetypeChunk.getArchetype())) {
consumer.accept(this.archetypeChunks[archetypeIndex], commandBuffer);
}
}
}
} finally {
this.processing.unlock();
}
commandBuffer.consume();
}
}
public boolean forEachChunk(Query<ECS_TYPE> query, @Nonnull BiPredicate<ArchetypeChunk<ECS_TYPE>, CommandBuffer<ECS_TYPE>> predicate) {
if (this.shutdown) {
throw new IllegalStateException("Store is shutdown!");
} else {
this.assertThread();
CommandBuffer<ECS_TYPE> commandBuffer = this.takeCommandBuffer();
boolean result = false;
this.processing.lock();
try {
if (query instanceof ExactArchetypeQuery) {
ExactArchetypeQuery<ECS_TYPE> exactQuery = (ExactArchetypeQuery)query;
int archetypeIndex = this.archetypeToIndexMap.getInt(exactQuery.getArchetype());
if (archetypeIndex != -2147483648) {
result = predicate.test(this.archetypeChunks[archetypeIndex], commandBuffer);
}
} else {
for(int archetypeIndex = 0; archetypeIndex < this.archetypeSize; ++archetypeIndex) {
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[archetypeIndex];
if (archetypeChunk != null && query.test(archetypeChunk.getArchetype()) && predicate.test(this.archetypeChunks[archetypeIndex], commandBuffer)) {
result = true;
break;
}
}
}
} finally {
this.processing.unlock();
}
commandBuffer.consume();
return result;
}
}
public void forEachChunk(int systemIndex, @Nonnull BiConsumer<ArchetypeChunk<ECS_TYPE>, CommandBuffer<ECS_TYPE>> consumer) {
if (this.shutdown) {
throw new IllegalStateException("Store is shutdown!");
} else {
this.assertThread();
CommandBuffer<ECS_TYPE> commandBuffer = this.takeCommandBuffer();
this.processing.lock();
try {
BitSet indexes = this.systemIndexToArchetypeChunkIndexes[systemIndex];
int index = -1;
while((index = indexes.nextSetBit(index + 1)) >= 0) {
consumer.accept(this.archetypeChunks[index], commandBuffer);
}
} finally {
this.processing.unlock();
}
commandBuffer.consume();
}
}
public boolean forEachChunk(int systemIndex, @Nonnull BiPredicate<ArchetypeChunk<ECS_TYPE>, CommandBuffer<ECS_TYPE>> predicate) {
if (this.shutdown) {
throw new IllegalStateException("Store is shutdown!");
} else {
this.assertThread();
CommandBuffer<ECS_TYPE> commandBuffer = this.takeCommandBuffer();
boolean result = false;
this.processing.lock();
try {
BitSet indexes = this.systemIndexToArchetypeChunkIndexes[systemIndex];
int index = -1;
while((index = indexes.nextSetBit(index + 1)) >= 0) {
if (predicate.test(this.archetypeChunks[index], commandBuffer)) {
result = true;
break;
}
}
} finally {
this.processing.unlock();
}
commandBuffer.consume();
return result;
}
}
public void forEachEntityParallel(IntBiObjectConsumer<ArchetypeChunk<ECS_TYPE>, CommandBuffer<ECS_TYPE>> consumer) {
if (this.shutdown) {
throw new IllegalStateException("Store is shutdown!");
} else {
this.assertThread();
CommandBuffer<ECS_TYPE> commandBuffer = this.takeCommandBuffer();
this.forEachTask.init();
this.processing.lock();
try {
for(int archetypeIndex = 0; archetypeIndex < this.archetypeSize; ++archetypeIndex) {
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[archetypeIndex];
if (archetypeChunk != null) {
int size = archetypeChunk.size();
if (size != 0) {
ParallelRangeTask<ForEachTaskData<ECS_TYPE>> systemTask = this.forEachTask.appendTask();
systemTask.init(0, size);
int i = 0;
for(int systemTaskSize = systemTask.size(); i < systemTaskSize; ++i) {
(systemTask.get(i)).init(consumer, archetypeChunk, commandBuffer.fork());
}
}
}
}
ForEachTaskData.invokeParallelTask(this.forEachTask, commandBuffer);
} finally {
this.processing.unlock();
}
commandBuffer.consume();
}
}
public void forEachEntityParallel(Query<ECS_TYPE> query, IntBiObjectConsumer<ArchetypeChunk<ECS_TYPE>, CommandBuffer<ECS_TYPE>> consumer) {
if (this.shutdown) {
throw new IllegalStateException("Store is shutdown!");
} else {
this.assertThread();
CommandBuffer<ECS_TYPE> commandBuffer = this.takeCommandBuffer();
this.forEachTask.init();
this.processing.lock();
try {
if (query instanceof ExactArchetypeQuery) {
ExactArchetypeQuery<ECS_TYPE> exactQuery = (ExactArchetypeQuery)query;
int archetypeIndex = this.archetypeToIndexMap.getInt(exactQuery.getArchetype());
if (archetypeIndex != -2147483648) {
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[archetypeIndex];
int archetypeChunkSize = archetypeChunk.size();
if (archetypeChunkSize != 0) {
ParallelRangeTask<ForEachTaskData<ECS_TYPE>> systemTask = this.forEachTask.appendTask();
systemTask.init(0, archetypeChunkSize);
int i = 0;
for(int systemSize = systemTask.size(); i < systemSize; ++i) {
(systemTask.get(i)).init(consumer, archetypeChunk, commandBuffer.fork());
}
}
}
} else {
for(int archetypeIndex = 0; archetypeIndex < this.archetypeSize; ++archetypeIndex) {
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[archetypeIndex];
if (archetypeChunk != null && query.test(archetypeChunk.getArchetype())) {
int archetypeChunkSize = archetypeChunk.size();
if (archetypeChunkSize != 0) {
ParallelRangeTask<ForEachTaskData<ECS_TYPE>> systemTask = this.forEachTask.appendTask();
systemTask.init(0, archetypeChunkSize);
int i = 0;
for(int systemTaskSize = systemTask.size(); i < systemTaskSize; ++i) {
(systemTask.get(i)).init(consumer, archetypeChunk, commandBuffer.fork());
}
}
}
}
}
ForEachTaskData.invokeParallelTask(this.forEachTask, commandBuffer);
} finally {
this.processing.unlock();
}
commandBuffer.consume();
}
}
public <T extends ArchetypeDataSystem<ECS_TYPE, Q, R>, Q, R> void fetch(@Nonnull SystemType<ECS_TYPE, T> systemType, Q query, @Nonnull List<R> results) {
if (this.shutdown) {
throw new IllegalStateException("Store is shutdown!");
} else {
this.assertThread();
ComponentRegistry.Data<ECS_TYPE> data = this.registry._internal_getData();
CommandBuffer<ECS_TYPE> commandBuffer = this.takeCommandBuffer();
this.fetchTask.init();
BitSet systemIndexes = data.getSystemIndexesForType(systemType);
this.processing.lock();
try {
int systemIndex = -1;
while((systemIndex = systemIndexes.nextSetBit(systemIndex + 1)) >= 0) {
T system = (T)(data.getSystem(systemIndex, systemType));
BitSet indexes = this.systemIndexToArchetypeChunkIndexes[systemIndex];
int index = -1;
while((index = indexes.nextSetBit(index + 1)) >= 0) {
((ArchetypeDataSystem)system).fetch(this.archetypeChunks[index], this, commandBuffer, query, results);
}
}
EntityDataSystem.SystemTaskData.invokeParallelTask(this.fetchTask, commandBuffer, results);
} finally {
this.processing.unlock();
}
commandBuffer.consume();
}
}
public <T extends EntityDataSystem<ECS_TYPE, Q, R>, Q, R> void fetch(@Nonnull Collection<Ref<ECS_TYPE>> refs, @Nonnull SystemType<ECS_TYPE, T> systemType, Q query, @Nonnull List<R> results) {
if (this.shutdown) {
throw new IllegalStateException("Store is shutdown!");
} else {
this.assertThread();
ComponentRegistry.Data<ECS_TYPE> data = this.registry._internal_getData();
CommandBuffer<ECS_TYPE> commandBuffer = this.takeCommandBuffer();
this.fetchTask.init();
BitSet systemIndexes = data.getSystemIndexesForType(systemType);
this.processing.lock();
try {
int systemIndex = -1;
while((systemIndex = systemIndexes.nextSetBit(systemIndex + 1)) >= 0) {
T system = (T)(data.getSystem(systemIndex, systemType));
for(Ref<ECS_TYPE> ref : refs) {
int entityIndex = ref.getIndex();
int archetypeIndex = this.entityToArchetypeChunk[entityIndex];
BitSet entityProcessedBySystemIndexes = this.archetypeChunkIndexesToSystemIndex[archetypeIndex];
if (entityProcessedBySystemIndexes.get(systemIndex)) {
int index = this.entityChunkIndex[entityIndex];
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[archetypeIndex];
((EntityDataSystem)system).fetch(index, archetypeChunk, this, commandBuffer, query, results);
}
}
}
EntityDataSystem.SystemTaskData.invokeParallelTask(this.fetchTask, commandBuffer, results);
} finally {
this.processing.unlock();
}
commandBuffer.consume();
}
}
public <Event extends EcsEvent> void invoke(@Nonnull Ref<ECS_TYPE> ref, @Nonnull Event param) {
EntityEventType<ECS_TYPE, ?> eventType = this.registry.getEntityEventTypeForClass(param.getClass());
if (eventType != null) {
this.invoke(eventType, ref, param);
}
}
public <Event extends EcsEvent> void invoke(@Nonnull EntityEventType<ECS_TYPE, Event> systemType, @Nonnull Ref<ECS_TYPE> ref, @Nonnull Event param) {
if (this.shutdown) {
throw new IllegalStateException("Store is shutdown!");
} else {
this.assertThread();
ComponentRegistry.Data<ECS_TYPE> data = this.registry._internal_getData();
CommandBuffer<ECS_TYPE> commandBuffer = this.takeCommandBuffer();
commandBuffer.track(ref);
BitSet systemIndexes = data.getSystemIndexesForType(systemType);
this.processing.lock();
try {
int entityIndex = ref.getIndex();
int archetypeIndex = this.entityToArchetypeChunk[entityIndex];
BitSet entityProcessedBySystemIndexes = this.archetypeChunkIndexesToSystemIndex[archetypeIndex];
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[archetypeIndex];
int index = this.entityChunkIndex[entityIndex];
int systemIndex = -1;
while((systemIndex = systemIndexes.nextSetBit(systemIndex + 1)) >= 0) {
systemIndex = entityProcessedBySystemIndexes.nextSetBit(systemIndex);
if (systemIndex < 0) {
break;
}
if (systemIndexes.get(systemIndex)) {
EntityEventSystem<ECS_TYPE, Event> system = (EntityEventSystem)data.getSystem(systemIndex, systemType);
system.handleInternal(index, archetypeChunk, this, commandBuffer, param);
if (commandBuffer.consumeWasTrackedRefRemoved()) {
break;
}
}
}
} finally {
this.processing.unlock();
}
commandBuffer.consume();
}
}
public <Event extends EcsEvent> void invoke(@Nonnull Event param) {
WorldEventType<ECS_TYPE, ?> eventType = this.registry.getWorldEventTypeForClass(param.getClass());
if (eventType != null) {
this.invoke(eventType, param);
}
}
public <Event extends EcsEvent> void invoke(@Nonnull WorldEventType<ECS_TYPE, Event> systemType, @Nonnull Event param) {
if (this.shutdown) {
throw new IllegalStateException("Store is shutdown!");
} else {
this.assertThread();
ComponentRegistry.Data<ECS_TYPE> data = this.registry._internal_getData();
CommandBuffer<ECS_TYPE> commandBuffer = this.takeCommandBuffer();
BitSet systemIndexes = data.getSystemIndexesForType(systemType);
this.processing.lock();
try {
int systemIndex = -1;
while((systemIndex = systemIndexes.nextSetBit(systemIndex + 1)) >= 0) {
WorldEventSystem<ECS_TYPE, Event> system = (WorldEventSystem)data.getSystem(systemIndex, systemType);
system.handleInternal(this, commandBuffer, param);
}
} finally {
this.processing.unlock();
}
commandBuffer.consume();
}
}
protected <Event extends EcsEvent> void internal_invoke(CommandBuffer<ECS_TYPE> sourceCommandBuffer, Ref<ECS_TYPE> ref, Event param) {
EntityEventType<ECS_TYPE, ?> eventType = this.registry.getEntityEventTypeForClass(param.getClass());
if (eventType != null) {
this.internal_invoke(sourceCommandBuffer, eventType, ref, param);
}
}
protected <Event extends EcsEvent> void internal_invoke(CommandBuffer<ECS_TYPE> sourceCommandBuffer, @Nonnull EntityEventType<ECS_TYPE, Event> systemType, Ref<ECS_TYPE> ref, Event param) {
ComponentRegistry.Data<ECS_TYPE> data = this.registry._internal_getData();
CommandBuffer<ECS_TYPE> commandBuffer = sourceCommandBuffer.fork();
commandBuffer.track(ref);
BitSet systemIndexes = data.getSystemIndexesForType(systemType);
int entityIndex = ref.getIndex();
int archetypeIndex = this.entityToArchetypeChunk[entityIndex];
BitSet entityProcessedBySystemIndexes = this.archetypeChunkIndexesToSystemIndex[archetypeIndex];
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[archetypeIndex];
int index = this.entityChunkIndex[entityIndex];
int systemIndex = -1;
while((systemIndex = systemIndexes.nextSetBit(systemIndex + 1)) >= 0) {
systemIndex = entityProcessedBySystemIndexes.nextSetBit(systemIndex);
if (systemIndex < 0) {
break;
}
if (systemIndexes.get(systemIndex)) {
EntityEventSystem<ECS_TYPE, Event> system = (EntityEventSystem)data.getSystem(systemIndex, systemType);
system.handleInternal(index, archetypeChunk, this, commandBuffer, param);
if (commandBuffer.consumeWasTrackedRefRemoved()) {
break;
}
}
}
commandBuffer.mergeParallel(sourceCommandBuffer);
}
protected <Event extends EcsEvent> void internal_invoke(CommandBuffer<ECS_TYPE> sourceCommandBuffer, Event param) {
WorldEventType<ECS_TYPE, ?> eventType = this.registry.getWorldEventTypeForClass(param.getClass());
if (eventType != null) {
this.internal_invoke(sourceCommandBuffer, eventType, param);
}
}
protected <Event extends EcsEvent> void internal_invoke(CommandBuffer<ECS_TYPE> sourceCommandBuffer, @Nonnull WorldEventType<ECS_TYPE, Event> systemType, Event param) {
ComponentRegistry.Data<ECS_TYPE> data = this.registry._internal_getData();
BitSet systemIndexes = data.getSystemIndexesForType(systemType);
int systemIndex = -1;
while((systemIndex = systemIndexes.nextSetBit(systemIndex + 1)) >= 0) {
WorldEventSystem<ECS_TYPE, Event> system = (WorldEventSystem)data.getSystem(systemIndex, systemType);
system.handleInternal(this, sourceCommandBuffer, param);
}
}
public void tick(float dt) {
this.tickInternal(dt, this.registry.getTickingSystemType());
}
public void pausedTick(float dt) {
if (this.shutdown) {
throw new IllegalStateException("Store is shutdown!");
} else {
this.assertThread();
this.tickInternal(dt, this.registry.getRunWhenPausedSystemType());
}
}
private <Tickable extends TickableSystem<ECS_TYPE>> void tickInternal(float dt, SystemType<ECS_TYPE, Tickable> tickingSystemType) {
if (this.shutdown) {
throw new IllegalStateException("Store is shutdown!");
} else {
this.assertThread();
this.registry.getDataUpdateLock().readLock().lock();
try {
ComponentRegistry.Data<ECS_TYPE> data = this.registry.doDataUpdate();
BitSet systemIndexes = data.getSystemIndexesForType(tickingSystemType);
int systemIndex = -1;
while((systemIndex = systemIndexes.nextSetBit(systemIndex + 1)) >= 0) {
Tickable tickingSystem = (Tickable)(data.getSystem(systemIndex, tickingSystemType));
long start = System.nanoTime();
tickingSystem.tick(dt, systemIndex, this);
long end = System.nanoTime();
this.systemMetrics[systemIndex].add(end, end - start);
}
} finally {
this.registry.getDataUpdateLock().readLock().unlock();
}
}
}
public void tick(ArchetypeTickingSystem<ECS_TYPE> system, float dt, int systemIndex) {
if (this.shutdown) {
throw new IllegalStateException("Store is shutdown!");
} else {
this.assertThread();
CommandBuffer<ECS_TYPE> commandBuffer = this.takeCommandBuffer();
this.parallelTask.init();
boolean oldDisableProcessingAssert = this.disableProcessingAssert;
this.disableProcessingAssert = system instanceof DisableProcessingAssert;
this.processing.lock();
try {
BitSet indexes = this.systemIndexToArchetypeChunkIndexes[systemIndex];
int index = -1;
while((index = indexes.nextSetBit(index + 1)) >= 0) {
system.tick(dt, this.archetypeChunks[index], this, commandBuffer);
}
EntityTickingSystem.SystemTaskData.invokeParallelTask(this.parallelTask, commandBuffer);
} finally {
this.processing.unlock();
this.disableProcessingAssert = oldDisableProcessingAssert;
}
commandBuffer.consume();
}
}
void updateData(@Nonnull ComponentRegistry.Data<ECS_TYPE> oldData, @Nonnull ComponentRegistry.Data<ECS_TYPE> data) {
if (this.shutdown) {
throw new IllegalStateException("Store is shutdown!");
} else {
int resourceSize = data.getResourceSize();
this.resources = (Resource[])Arrays.copyOf(this.resources, resourceSize);
for(int index = 0; index < this.resources.length; ++index) {
ResourceType<ECS_TYPE, ? extends Resource<ECS_TYPE>> resourceType = data.getResourceType(index);
if (this.resources[index] == null && resourceType != null) {
this.resources[index] = (Resource)this.resourceStorage.load(this, data, resourceType).join();
} else if (this.resources[index] != null && resourceType == null) {
this.resources[index] = null;
}
}
boolean systemChanged = false;
for(int i = 0; i < data.getDataChangeCount(); ++i) {
DataChange dataChange = data.getDataChange(i);
systemChanged |= dataChange instanceof SystemChange;
this.updateData(oldData, data, dataChange);
}
HistoricMetric[] oldSystemMetrics = this.systemMetrics;
this.systemMetrics = new HistoricMetric[data.getSystemSize()];
SystemType<ECS_TYPE, TickableSystem<ECS_TYPE>> tickingSystemType = this.registry.getTickableSystemType();
BitSet systemIndexes = data.getSystemIndexesForType(tickingSystemType);
int systemIndex = -1;
while((systemIndex = systemIndexes.nextSetBit(systemIndex + 1)) >= 0) {
ISystem<ECS_TYPE> system = data.getSystem(systemIndex);
int oldSystemIndex = oldData.indexOf(system);
if (oldSystemIndex >= 0) {
this.systemMetrics[systemIndex] = oldSystemMetrics[oldSystemIndex];
} else {
this.systemMetrics[systemIndex] = HistoricMetric.builder(33333333L, TimeUnit.NANOSECONDS).addPeriod(1L, TimeUnit.SECONDS).addPeriod(1L, TimeUnit.MINUTES).addPeriod(5L, TimeUnit.MINUTES).build();
}
}
if (systemChanged) {
this.updateArchetypeIndexes(data);
}
}
}
private void updateData(@Nonnull ComponentRegistry.Data<ECS_TYPE> oldData, @Nonnull ComponentRegistry.Data<ECS_TYPE> newData, DataChange dataChange) {
this.processing.lock();
try {
this.updateData0(oldData, newData, dataChange);
} finally {
this.processing.unlock();
}
if (dataChange instanceof SystemChange) {
SystemChange<ECS_TYPE> systemChange = (SystemChange)dataChange;
ISystem<ECS_TYPE> system = systemChange.getSystem();
switch (systemChange.getType()) {
case REGISTERED:
if (system instanceof StoreSystem) {
((StoreSystem)system).onSystemAddedToStore(this);
}
break;
case UNREGISTERED:
if (system instanceof StoreSystem) {
((StoreSystem)system).onSystemRemovedFromStore(this);
}
}
}
}
private void updateData0(@Nonnull ComponentRegistry.Data<ECS_TYPE> oldData, @Nonnull ComponentRegistry.Data<ECS_TYPE> newData, DataChange dataChange) {
if (dataChange instanceof ComponentChange) {
ComponentChange<ECS_TYPE, ? extends Component<ECS_TYPE>> componentChange = (ComponentChange)dataChange;
ComponentType<ECS_TYPE, ? extends Component<ECS_TYPE>> componentType = componentChange.getComponentType();
ComponentType<ECS_TYPE, UnknownComponents<ECS_TYPE>> unknownComponentType = this.registry.getUnknownComponentType();
switch (componentChange.getType()) {
case REGISTERED:
String componentId = newData.getComponentId(componentType);
Codec<Component<ECS_TYPE>> componentCodec = newData.<Component<ECS_TYPE>>getComponentCodec(componentType);
if (componentCodec != null) {
Holder<ECS_TYPE> tempInternalEntityHolder = this.registry._internal_newEntityHolder();
int oldArchetypeSize = this.archetypeSize;
for(int archetypeIndex = 0; archetypeIndex < oldArchetypeSize; ++archetypeIndex) {
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[archetypeIndex];
if (archetypeChunk != null) {
Archetype<ECS_TYPE> archetype = archetypeChunk.getArchetype();
if (!archetype.contains(componentType) && archetype.contains(unknownComponentType)) {
Archetype<ECS_TYPE> newArchetype = Archetype.add(archetype, componentType);
int toArchetypeIndex = this.findOrCreateArchetypeChunk(newArchetype);
ArchetypeChunk<ECS_TYPE> toArchetypeChunk = this.archetypeChunks[toArchetypeIndex];
archetypeChunk.transferSomeTo(tempInternalEntityHolder, toArchetypeChunk, (index) -> {
UnknownComponents<ECS_TYPE> unknownComponents = (UnknownComponents)archetypeChunk.getComponent(index, unknownComponentType);
assert unknownComponents != null;
return unknownComponents.contains(componentId);
}, (entity) -> {
UnknownComponents<ECS_TYPE> unknownComponents = (UnknownComponents)entity.getComponent(unknownComponentType);
assert unknownComponents != null;
Component<ECS_TYPE> component = unknownComponents.removeComponent(componentId, componentCodec);
entity.addComponent(componentType, component);
}, (newChunkEntityRef, ref) -> {
this.entityToArchetypeChunk[ref.getIndex()] = toArchetypeIndex;
this.entityChunkIndex[ref.getIndex()] = newChunkEntityRef;
});
if (archetypeChunk.size() == 0) {
this.archetypeToIndexMap.removeInt(this.archetypeChunks[archetypeIndex].getArchetype());
this.archetypeChunks[archetypeIndex] = null;
for(int systemIndex = 0; systemIndex < oldData.getSystemSize(); ++systemIndex) {
this.systemIndexToArchetypeChunkIndexes[systemIndex].clear(archetypeIndex);
}
this.archetypeChunkIndexesToSystemIndex[archetypeIndex].clear();
this.archetypeChunkReuse.set(archetypeIndex);
}
if (toArchetypeChunk.size() == 0) {
this.archetypeToIndexMap.removeInt(this.archetypeChunks[toArchetypeIndex].getArchetype());
this.archetypeChunks[toArchetypeIndex] = null;
for(int systemIndex = 0; systemIndex < oldData.getSystemSize(); ++systemIndex) {
this.systemIndexToArchetypeChunkIndexes[systemIndex].clear(toArchetypeIndex);
}
this.archetypeChunkIndexesToSystemIndex[toArchetypeIndex].clear();
this.archetypeChunkReuse.set(toArchetypeIndex);
}
}
}
}
}
break;
case UNREGISTERED:
Holder<ECS_TYPE> tempInternalEntityHolder = this.registry._internal_newEntityHolder();
String componentId = oldData.getComponentId(componentType);
Codec<Component<ECS_TYPE>> componentCodec = oldData.<Component<ECS_TYPE>>getComponentCodec(componentType);
int oldArchetypeSize = this.archetypeSize;
for(int archetypeIndex = 0; archetypeIndex < oldArchetypeSize; ++archetypeIndex) {
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[archetypeIndex];
if (archetypeChunk != null) {
Archetype<ECS_TYPE> archetype = archetypeChunk.getArchetype();
if (archetype.contains(componentType)) {
this.archetypeToIndexMap.removeInt(this.archetypeChunks[archetypeIndex].getArchetype());
this.archetypeChunks[archetypeIndex] = null;
for(int systemIndex = 0; systemIndex < oldData.getSystemSize(); ++systemIndex) {
this.systemIndexToArchetypeChunkIndexes[systemIndex].clear(archetypeIndex);
}
this.archetypeChunkIndexesToSystemIndex[archetypeIndex].clear();
this.archetypeChunkReuse.set(archetypeIndex);
Archetype<ECS_TYPE> newArchetype = Archetype.remove(archetype, componentType);
if (componentCodec != null && !newArchetype.contains(unknownComponentType)) {
newArchetype = Archetype.add(newArchetype, unknownComponentType);
}
int toArchetypeIndex = this.findOrCreateArchetypeChunk(newArchetype);
ArchetypeChunk<ECS_TYPE> toArchetypeChunk = this.archetypeChunks[toArchetypeIndex];
archetypeChunk.transferTo(tempInternalEntityHolder, toArchetypeChunk, (entity) -> {
if (componentCodec != null) {
UnknownComponents<ECS_TYPE> unknownComponents;
if (entity.getArchetype().contains(unknownComponentType)) {
unknownComponents = (UnknownComponents)entity.getComponent(unknownComponentType);
assert unknownComponents != null;
} else {
unknownComponents = new UnknownComponents<ECS_TYPE>();
entity.addComponent(unknownComponentType, unknownComponents);
}
Component<ECS_TYPE> component = entity.getComponent(componentType);
unknownComponents.addComponent(componentId, component, componentCodec);
}
entity.removeComponent(componentType);
}, (newChunkEntityRef, ref) -> {
this.entityToArchetypeChunk[ref.getIndex()] = toArchetypeIndex;
this.entityChunkIndex[ref.getIndex()] = newChunkEntityRef;
});
}
}
}
int highestUsedIndex = this.archetypeChunkReuse.previousClearBit(oldArchetypeSize - 1);
this.archetypeSize = highestUsedIndex + 1;
this.archetypeChunkReuse.clear(this.archetypeSize, oldArchetypeSize);
}
} else if (dataChange instanceof SystemChange) {
SystemChange<ECS_TYPE> systemChange = (SystemChange)dataChange;
ISystem<ECS_TYPE> system = systemChange.getSystem();
switch (systemChange.getType()) {
case REGISTERED:
if (system instanceof ArchetypeChunkSystem) {
ArchetypeChunkSystem<ECS_TYPE> archetypeChunkSystem = (ArchetypeChunkSystem)system;
for(int archetypeIndex = 0; archetypeIndex < this.archetypeSize; ++archetypeIndex) {
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[archetypeIndex];
if (archetypeChunk != null && archetypeChunkSystem.test(this.registry, archetypeChunk.getArchetype())) {
archetypeChunkSystem.onSystemAddedToArchetypeChunk(archetypeChunk);
}
}
}
break;
case UNREGISTERED:
if (system instanceof ArchetypeChunkSystem) {
ArchetypeChunkSystem<ECS_TYPE> archetypeChunkSystem = (ArchetypeChunkSystem)system;
for(int archetypeIndex = 0; archetypeIndex < this.archetypeSize; ++archetypeIndex) {
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[archetypeIndex];
if (archetypeChunk != null && archetypeChunkSystem.test(this.registry, archetypeChunk.getArchetype())) {
archetypeChunkSystem.onSystemRemovedFromArchetypeChunk(archetypeChunk);
}
}
}
}
}
}
private void updateArchetypeIndexes(@Nonnull ComponentRegistry.Data<ECS_TYPE> data) {
int systemSize = data.getSystemSize();
int oldLength = this.systemIndexToArchetypeChunkIndexes.length;
if (oldLength < systemSize) {
this.systemIndexToArchetypeChunkIndexes = (BitSet[])Arrays.copyOf(this.systemIndexToArchetypeChunkIndexes, systemSize);
for(int i = oldLength; i < systemSize; ++i) {
this.systemIndexToArchetypeChunkIndexes[i] = new BitSet(this.archetypeSize);
}
}
for(int systemIndex = 0; systemIndex < oldLength; ++systemIndex) {
this.systemIndexToArchetypeChunkIndexes[systemIndex].clear();
}
for(int archetypeIndex = 0; archetypeIndex < this.archetypeSize; ++archetypeIndex) {
this.archetypeChunkIndexesToSystemIndex[archetypeIndex].clear();
}
SystemType<ECS_TYPE, QuerySystem<ECS_TYPE>> entityQuerySystemType = this.registry.getQuerySystemType();
BitSet systemIndexes = data.getSystemIndexesForType(entityQuerySystemType);
int systemIndex = -1;
while((systemIndex = systemIndexes.nextSetBit(systemIndex + 1)) >= 0) {
QuerySystem<ECS_TYPE> system = (QuerySystem)data.getSystem(systemIndex, entityQuerySystemType);
BitSet archetypeChunkIndexes = this.systemIndexToArchetypeChunkIndexes[systemIndex];
for(int archetypeIndex = 0; archetypeIndex < this.archetypeSize; ++archetypeIndex) {
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[archetypeIndex];
if (archetypeChunk != null && system.test(this.registry, archetypeChunk.getArchetype())) {
archetypeChunkIndexes.set(archetypeIndex);
this.archetypeChunkIndexesToSystemIndex[archetypeIndex].set(systemIndex);
}
}
}
}
public void assertWriteProcessing() {
if (this.processing.isHeld() && !this.disableProcessingAssert) {
throw new IllegalStateException("Store is currently processing! Ensure you aren't calling a store method from a system.");
}
}
@Deprecated
public boolean isProcessing() {
return this.processing.isHeld();
}
public void assertThread() {
Thread currentThread = Thread.currentThread();
if (!currentThread.equals(this.thread) && this.thread.isAlive()) {
String var10002 = String.valueOf(this.thread);
throw new IllegalStateException("Assert not in thread! " + var10002 + " but was in " + String.valueOf(currentThread));
}
}
public boolean isInThread() {
return Thread.currentThread().equals(this.thread);
}
public boolean isAliveInDifferentThread() {
return this.thread.isAlive() && !Thread.currentThread().equals(this.thread);
}
@Nonnull
public String toString() {
String var10000 = String.valueOf(this.getClass());
return "Store{super()=" + var10000 + "@" + this.hashCode() + ", registry=" + String.valueOf(this.registry.getClass()) + "@" + this.registry.hashCode() + ", shutdown=" + this.shutdown + ", storeIndex=" + this.storeIndex + ", systemIndexToArchetypeChunkIndexes=" + Arrays.toString(this.systemIndexToArchetypeChunkIndexes) + ", archetypeSize=" + this.archetypeSize + ", archetypeChunks=" + Arrays.toString(this.archetypeChunks) + "}";
}
private <T extends Component<ECS_TYPE>> void datachunk_addComponent(@Nonnull Ref<ECS_TYPE> ref, int fromArchetypeIndex, @Nonnull ComponentType<ECS_TYPE, T> componentType, @Nonnull T component, @Nonnull CommandBuffer<ECS_TYPE> commandBuffer) {
int entityIndex = ref.getIndex();
ArchetypeChunk<ECS_TYPE> fromArchetypeChunk = this.archetypeChunks[fromArchetypeIndex];
int oldChunkEntityRef = this.entityChunkIndex[entityIndex];
Holder<ECS_TYPE> holder = this.registry._internal_newEntityHolder();
fromArchetypeChunk.removeEntity(oldChunkEntityRef, holder);
holder.addComponent(componentType, component);
int toArchetypeIndex = this.findOrCreateArchetypeChunk(holder.getArchetype());
ArchetypeChunk<ECS_TYPE> toArchetypeChunk = this.archetypeChunks[toArchetypeIndex];
int chunkEntityRef = toArchetypeChunk.addEntity(ref, holder);
this.entityToArchetypeChunk[entityIndex] = toArchetypeIndex;
this.entityChunkIndex[entityIndex] = chunkEntityRef;
BitSet entityProcessedBySystemIndexes = this.archetypeChunkIndexesToSystemIndex[toArchetypeIndex];
ComponentRegistry.Data<ECS_TYPE> data = this.registry._internal_getData();
BitSet systemIndexes = data.getSystemIndexesForType(this.registry.getRefChangeSystemType());
int systemIndex = -1;
while((systemIndex = systemIndexes.nextSetBit(systemIndex + 1)) >= 0) {
if (entityProcessedBySystemIndexes.get(systemIndex)) {
RefChangeSystem<ECS_TYPE, T> system = (RefChangeSystem)data.getSystem(systemIndex);
if (system.componentType().getIndex() == componentType.getIndex()) {
system.onComponentAdded(ref, component, this, commandBuffer);
}
}
}
if (fromArchetypeChunk.size() == 0) {
this.removeArchetypeChunk(fromArchetypeIndex);
}
}
private int findOrCreateArchetypeChunk(@Nonnull Archetype<ECS_TYPE> archetype) {
int archetypeIndex = this.archetypeToIndexMap.getInt(archetype);
if (archetypeIndex != -2147483648) {
return archetypeIndex;
} else {
ComponentRegistry.Data<ECS_TYPE> data = this.registry._internal_getData();
if (this.archetypeChunkReuse.isEmpty()) {
archetypeIndex = this.archetypeSize++;
} else {
archetypeIndex = this.archetypeChunkReuse.nextSetBit(0);
this.archetypeChunkReuse.clear(archetypeIndex);
}
int oldLength = this.archetypeChunks.length;
if (oldLength <= archetypeIndex) {
int newLength = ArrayUtil.grow(archetypeIndex);
this.archetypeChunks = (ArchetypeChunk[])Arrays.copyOf(this.archetypeChunks, newLength);
this.archetypeChunkIndexesToSystemIndex = (BitSet[])Arrays.copyOf(this.archetypeChunkIndexesToSystemIndex, newLength);
int systemSize = data.getSystemSize();
for(int i = oldLength; i < newLength; ++i) {
this.archetypeChunkIndexesToSystemIndex[i] = new BitSet(systemSize);
}
}
ArchetypeChunk<ECS_TYPE> archetypeChunk = new ArchetypeChunk<ECS_TYPE>(this, archetype);
this.archetypeChunks[archetypeIndex] = archetypeChunk;
this.archetypeToIndexMap.put(archetype, archetypeIndex);
BitSet archetypeChunkToSystemIndex = this.archetypeChunkIndexesToSystemIndex[archetypeIndex];
SystemType<ECS_TYPE, QuerySystem<ECS_TYPE>> entityQuerySystemType = this.registry.getQuerySystemType();
BitSet systemIndexes = data.getSystemIndexesForType(entityQuerySystemType);
int systemIndex = -1;
while((systemIndex = systemIndexes.nextSetBit(systemIndex + 1)) >= 0) {
QuerySystem<ECS_TYPE> system = (QuerySystem)data.getSystem(systemIndex, entityQuerySystemType);
if (system.test(this.registry, archetype)) {
this.systemIndexToArchetypeChunkIndexes[systemIndex].set(archetypeIndex);
archetypeChunkToSystemIndex.set(systemIndex);
if (system instanceof ArchetypeChunkSystem) {
((ArchetypeChunkSystem)system).onSystemAddedToArchetypeChunk(archetypeChunk);
}
}
}
return archetypeIndex;
}
}
private void removeArchetypeChunk(int archetypeIndex) {
ArchetypeChunk<ECS_TYPE> archetypeChunk = this.archetypeChunks[archetypeIndex];
Archetype<ECS_TYPE> archetype = archetypeChunk.getArchetype();
this.archetypeToIndexMap.removeInt(archetype);
this.archetypeChunks[archetypeIndex] = null;
this.archetypeChunkIndexesToSystemIndex[archetypeIndex].clear();
ComponentRegistry.Data<ECS_TYPE> data = this.registry._internal_getData();
BitSet systemIndexes = data.getSystemIndexesForType(this.registry.getQuerySystemType());
int systemIndex = -1;
while((systemIndex = systemIndexes.nextSetBit(systemIndex + 1)) >= 0) {
this.systemIndexToArchetypeChunkIndexes[systemIndex].clear(archetypeIndex);
ISystem<ECS_TYPE> system = data.getSystem(systemIndex);
if (system instanceof ArchetypeChunkSystem<ECS_TYPE> archetypeChunkSystem) {
if (archetypeChunkSystem.test(this.registry, archetype)) {
archetypeChunkSystem.onSystemRemovedFromArchetypeChunk(archetypeChunk);
}
}
}
if (archetypeIndex == this.archetypeSize - 1) {
int highestUsedIndex = this.archetypeChunkReuse.previousClearBit(archetypeIndex - 1);
this.archetypeSize = highestUsedIndex + 1;
this.archetypeChunkReuse.clear(this.archetypeSize, archetypeIndex);
} else {
this.archetypeChunkReuse.set(archetypeIndex);
}
}
static {
METRICS_REGISTRY = (new MetricsRegistry()).register("ArchetypeChunkCount", Store::getArchetypeChunkCount, Codec.INTEGER).register("EntityCount", Store::getEntityCount, Codec.INTEGER).register("Systems", (componentStore) -> {
ComponentRegistry.Data<?> data = componentStore.getRegistry().getData();
HistoricMetric[] systemMetrics = componentStore.getSystemMetrics();
SystemMetricData[] systemMetricData = new SystemMetricData[data.getSystemSize()];
for(int systemIndex = 0; systemIndex < data.getSystemSize(); ++systemIndex) {
ISystem<?> system = data.getSystem(systemIndex);
MetricResults metrics = null;
if (system instanceof MetricSystem metricSystem) {
metrics = metricSystem.toMetricResults(componentStore);
}
systemMetricData[systemIndex] = new SystemMetricData(system.getClass().getName(), componentStore.getArchetypeChunkCountFor(systemIndex), componentStore.getEntityCountFor(systemIndex), system instanceof TickingSystem ? systemMetrics[systemIndex] : null, metrics);
}
return systemMetricData;
}, new ArrayCodec(SystemMetricData.CODEC, (x$0) -> new SystemMetricData[x$0])).register("ArchetypeChunks", Store::collectArchetypeChunkData, new ArrayCodec(ArchetypeChunkData.CODEC, (x$0) -> new ArchetypeChunkData[x$0]));
}
private static class ProcessingCounter implements Lock {
private int count = 0;
private ProcessingCounter() {
}
public boolean isHeld() {
return this.count > 0;
}
public void lock() {
++this.count;
}
public void lockInterruptibly() {
throw new UnsupportedOperationException("lockInterruptibly() is not supported");
}
public boolean tryLock() {
throw new UnsupportedOperationException("tryLock() is not supported");
}
public boolean tryLock(long time, @Nonnull TimeUnit unit) {
throw new UnsupportedOperationException("tryLock() is not supported");
}
public void unlock() {
--this.count;
}
@Nonnull
public Condition newCondition() {
throw new UnsupportedOperationException("Conditions are not supported");
}
}
}