Faster entity removal
This commit is contained in:
@@ -232,9 +232,15 @@ public class EntityProcess extends BaseProcessor{
|
|||||||
Stype repr = types.first();
|
Stype repr = types.first();
|
||||||
String groupType = repr.annotation(Component.class).base() ? baseName(repr) : interfaceName(repr);
|
String groupType = repr.annotation(Component.class).base() ? baseName(repr) : interfaceName(repr);
|
||||||
|
|
||||||
|
String name = group.name().startsWith("g") ? group.name().substring(1) : group.name();
|
||||||
|
|
||||||
boolean collides = an.collide();
|
boolean collides = an.collide();
|
||||||
groupDefs.add(new GroupDefinition(group.name().startsWith("g") ? group.name().substring(1) : group.name(),
|
groupDefs.add(new GroupDefinition(name,
|
||||||
ClassName.bestGuess(packageName + "." + groupType), types, an.spatial(), an.mapping(), collides));
|
ClassName.bestGuess(packageName + "." + groupType), types, an.spatial(), an.mapping(), collides));
|
||||||
|
|
||||||
|
TypeSpec.Builder accessor = TypeSpec.interfaceBuilder("IndexableEntity__" + name);
|
||||||
|
accessor.addMethod(MethodSpec.methodBuilder("setIndex__" + name).addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC).addParameter(int.class, "index").returns(void.class).build());
|
||||||
|
write(accessor);
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectMap<String, Selement> usedNames = new ObjectMap<>();
|
ObjectMap<String, Selement> usedNames = new ObjectMap<>();
|
||||||
@@ -394,6 +400,13 @@ public class EntityProcess extends BaseProcessor{
|
|||||||
//entities with no sync comp and no serialization gen no code
|
//entities with no sync comp and no serialization gen no code
|
||||||
boolean hasIO = ann.genio() && (components.contains(s -> s.name().contains("Sync")) || ann.serialize());
|
boolean hasIO = ann.genio() && (components.contains(s -> s.name().contains("Sync")) || ann.serialize());
|
||||||
|
|
||||||
|
//implement indexable interfaces.
|
||||||
|
for(GroupDefinition def : groups){
|
||||||
|
builder.addSuperinterface(tname(packageName + ".IndexableEntity__" + def.name));
|
||||||
|
builder.addMethod(MethodSpec.methodBuilder("setIndex__" + def.name).addParameter(int.class, "index").addModifiers(Modifier.PUBLIC).addAnnotation(Override.class)
|
||||||
|
.addCode("index__$L = index;", def.name).build());
|
||||||
|
}
|
||||||
|
|
||||||
//add all methods from components
|
//add all methods from components
|
||||||
for(ObjectMap.Entry<String, Seq<Smethod>> entry : methods){
|
for(ObjectMap.Entry<String, Seq<Smethod>> entry : methods){
|
||||||
if(entry.value.contains(m -> m.has(Replace.class))){
|
if(entry.value.contains(m -> m.has(Replace.class))){
|
||||||
@@ -446,8 +459,15 @@ public class EntityProcess extends BaseProcessor{
|
|||||||
mbuilder.addStatement("if(added == $L) return", first.name().equals("add"));
|
mbuilder.addStatement("if(added == $L) return", first.name().equals("add"));
|
||||||
|
|
||||||
for(GroupDefinition def : groups){
|
for(GroupDefinition def : groups){
|
||||||
//remove/add from each group, assume imported
|
if(first.name().equals("add")){
|
||||||
mbuilder.addStatement("Groups.$L.$L(this)", def.name, first.name());
|
//remove/add from each group, assume imported
|
||||||
|
mbuilder.addStatement("index__$L = Groups.$L.addIndex(this)", def.name, def.name);
|
||||||
|
}else{
|
||||||
|
//remove/add from each group, assume imported
|
||||||
|
mbuilder.addStatement("Groups.$L.removeIndex(this, index__$L);", def.name, def.name);
|
||||||
|
|
||||||
|
mbuilder.addStatement("index__$L = -1", def.name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -577,6 +597,13 @@ public class EntityProcess extends BaseProcessor{
|
|||||||
|
|
||||||
skipDeprecated(builder);
|
skipDeprecated(builder);
|
||||||
|
|
||||||
|
if(!legacy){
|
||||||
|
//add group index int variables
|
||||||
|
for(GroupDefinition def : groups){
|
||||||
|
builder.addField(FieldSpec.builder(int.class, "index__" + def.name, Modifier.PROTECTED).initializer("-1").build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
definitions.add(new EntityDefinition(packageName + "." + name, builder, type, typeIsBase ? null : baseClass, components, groups, allFieldSpecs, legacy));
|
definitions.add(new EntityDefinition(packageName + "." + name, builder, type, typeIsBase ? null : baseClass, components, groups, allFieldSpecs, legacy));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -592,7 +619,7 @@ public class EntityProcess extends BaseProcessor{
|
|||||||
groupsBuilder.addField(ParameterizedTypeName.get(
|
groupsBuilder.addField(ParameterizedTypeName.get(
|
||||||
ClassName.bestGuess("mindustry.entities.EntityGroup"), itype), group.name, Modifier.PUBLIC, Modifier.STATIC);
|
ClassName.bestGuess("mindustry.entities.EntityGroup"), itype), group.name, Modifier.PUBLIC, Modifier.STATIC);
|
||||||
|
|
||||||
groupInit.addStatement("$L = new $T<>($L.class, $L, $L)", group.name, groupc, itype, group.spatial, group.mapping);
|
groupInit.addStatement("$L = new $T<>($L.class, $L, $L, (e, pos) -> (($L.IndexableEntity__$L)e).setIndex__$L(pos))", group.name, groupc, itype, group.spatial, group.mapping, packageName, group.name, group.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
//write the groups
|
//write the groups
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ public class EntityGroup<T extends Entityc> implements Iterable<T>{
|
|||||||
private final Seq<T> intersectArray = new Seq<>();
|
private final Seq<T> intersectArray = new Seq<>();
|
||||||
private final Rect viewport = new Rect();
|
private final Rect viewport = new Rect();
|
||||||
private final Rect intersectRect = new Rect();
|
private final Rect intersectRect = new Rect();
|
||||||
|
private final EntityIndexer indexer;
|
||||||
private IntMap<T> map;
|
private IntMap<T> map;
|
||||||
private QuadTree tree;
|
private QuadTree tree;
|
||||||
private boolean clearing;
|
private boolean clearing;
|
||||||
@@ -36,6 +37,10 @@ public class EntityGroup<T extends Entityc> implements Iterable<T>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public EntityGroup(Class<T> type, boolean spatial, boolean mapping){
|
public EntityGroup(Class<T> type, boolean spatial, boolean mapping){
|
||||||
|
this(type, spatial, mapping, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityGroup(Class<T> type, boolean spatial, boolean mapping, EntityIndexer indexer){
|
||||||
array = new Seq<>(false, 32, type);
|
array = new Seq<>(false, 32, type);
|
||||||
|
|
||||||
if(spatial){
|
if(spatial){
|
||||||
@@ -45,6 +50,8 @@ public class EntityGroup<T extends Entityc> implements Iterable<T>{
|
|||||||
if(mapping){
|
if(mapping){
|
||||||
map = new IntMap<>();
|
map = new IntMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.indexer = indexer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return entities with colliding IDs, or an empty array. */
|
/** @return entities with colliding IDs, or an empty array. */
|
||||||
@@ -107,7 +114,7 @@ public class EntityGroup<T extends Entityc> implements Iterable<T>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean useTree(){
|
public boolean useTree(){
|
||||||
return map != null;
|
return tree != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean mappingEnabled(){
|
public boolean mappingEnabled(){
|
||||||
@@ -183,12 +190,25 @@ public class EntityGroup<T extends Entityc> implements Iterable<T>{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int addIndex(T type){
|
||||||
|
int index = array.size;
|
||||||
|
add(type);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
public void remove(T type){
|
public void remove(T type){
|
||||||
if(clearing) return;
|
if(clearing) return;
|
||||||
if(type == null) throw new RuntimeException("Cannot remove a null entity!");
|
if(type == null) throw new RuntimeException("Cannot remove a null entity!");
|
||||||
int idx = array.indexOf(type, true);
|
int idx = array.indexOf(type, true);
|
||||||
if(idx != -1){
|
if(idx != -1){
|
||||||
array.remove(idx);
|
array.remove(idx);
|
||||||
|
|
||||||
|
//fix incorrect HEAD index since it was swapped
|
||||||
|
if(array.size > 0 && idx != array.size){
|
||||||
|
var swapped = array.items[idx];
|
||||||
|
indexer.change(swapped, idx);
|
||||||
|
}
|
||||||
|
|
||||||
if(map != null){
|
if(map != null){
|
||||||
map.remove(type.id());
|
map.remove(type.id());
|
||||||
}
|
}
|
||||||
@@ -200,6 +220,32 @@ public class EntityGroup<T extends Entityc> implements Iterable<T>{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void removeIndex(T type, int position){
|
||||||
|
if(clearing) return;
|
||||||
|
if(type == null) throw new RuntimeException("Cannot remove a null entity!");
|
||||||
|
if(position != -1 && position < array.size){
|
||||||
|
|
||||||
|
//swap head with current
|
||||||
|
if(array.size > 1){
|
||||||
|
var head = array.items[array.size - 1];
|
||||||
|
indexer.change(head, position);
|
||||||
|
array.items[position] = head;
|
||||||
|
}
|
||||||
|
|
||||||
|
array.size --;
|
||||||
|
array.items[array.size] = null;
|
||||||
|
|
||||||
|
if(map != null){
|
||||||
|
map.remove(type.id());
|
||||||
|
}
|
||||||
|
|
||||||
|
//fix iteration index when removing
|
||||||
|
if(index >= position){
|
||||||
|
index --;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void clear(){
|
public void clear(){
|
||||||
clearing = true;
|
clearing = true;
|
||||||
|
|
||||||
|
|||||||
7
core/src/mindustry/entities/EntityIndexer.java
Normal file
7
core/src/mindustry/entities/EntityIndexer.java
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package mindustry.entities;
|
||||||
|
|
||||||
|
import mindustry.gen.*;
|
||||||
|
|
||||||
|
public interface EntityIndexer{
|
||||||
|
void change(Entityc t, int index);
|
||||||
|
}
|
||||||
@@ -137,6 +137,12 @@ public class CanvasBlock extends Block{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(){
|
public void draw(){
|
||||||
|
if(!renderer.drawDisplays){
|
||||||
|
super.draw();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(blending == 0){
|
if(blending == 0){
|
||||||
super.draw();
|
super.draw();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user