1
0
mirror of https://github.com/Anuken/Mindustry.git synced 2024-09-11 08:15:35 +03:00

Faster entity removal

This commit is contained in:
Anuken 2022-12-14 16:58:58 -05:00
parent 7f292b14a7
commit 243c50be02
4 changed files with 91 additions and 5 deletions

View File

@ -232,9 +232,15 @@ public class EntityProcess extends BaseProcessor{
Stype repr = types.first();
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();
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));
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<>();
@ -394,6 +400,13 @@ public class EntityProcess extends BaseProcessor{
//entities with no sync comp and no serialization gen no code
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
for(ObjectMap.Entry<String, Seq<Smethod>> entry : methods){
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"));
for(GroupDefinition def : groups){
//remove/add from each group, assume imported
mbuilder.addStatement("Groups.$L.$L(this)", def.name, first.name());
if(first.name().equals("add")){
//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);
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));
}
@ -592,7 +619,7 @@ public class EntityProcess extends BaseProcessor{
groupsBuilder.addField(ParameterizedTypeName.get(
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

View File

@ -20,6 +20,7 @@ public class EntityGroup<T extends Entityc> implements Iterable<T>{
private final Seq<T> intersectArray = new Seq<>();
private final Rect viewport = new Rect();
private final Rect intersectRect = new Rect();
private final EntityIndexer indexer;
private IntMap<T> map;
private QuadTree tree;
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){
this(type, spatial, mapping, null);
}
public EntityGroup(Class<T> type, boolean spatial, boolean mapping, EntityIndexer indexer){
array = new Seq<>(false, 32, type);
if(spatial){
@ -45,6 +50,8 @@ public class EntityGroup<T extends Entityc> implements Iterable<T>{
if(mapping){
map = new IntMap<>();
}
this.indexer = indexer;
}
/** @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(){
return map != null;
return tree != null;
}
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){
if(clearing) return;
if(type == null) throw new RuntimeException("Cannot remove a null entity!");
int idx = array.indexOf(type, true);
if(idx != -1){
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){
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(){
clearing = true;

View File

@ -0,0 +1,7 @@
package mindustry.entities;
import mindustry.gen.*;
public interface EntityIndexer{
void change(Entityc t, int index);
}

View File

@ -137,6 +137,12 @@ public class CanvasBlock extends Block{
@Override
public void draw(){
if(!renderer.drawDisplays){
super.draw();
return;
}
if(blending == 0){
super.draw();
}