mirror of
https://github.com/Anuken/Mindustry.git
synced 2025-07-06 16:27:25 +07:00
Faster entity removal
This commit is contained in:
@ -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){
|
||||
if(first.name().equals("add")){
|
||||
//remove/add from each group, assume imported
|
||||
mbuilder.addStatement("Groups.$L.$L(this)", def.name, first.name());
|
||||
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
|
||||
|
@ -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;
|
||||
|
||||
|
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
|
||||
public void draw(){
|
||||
if(!renderer.drawDisplays){
|
||||
super.draw();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(blending == 0){
|
||||
super.draw();
|
||||
}
|
||||
|
Reference in New Issue
Block a user