Class ID mapping
This commit is contained in:
@@ -17,6 +17,12 @@ public class Annotations{
|
||||
public @interface Component{
|
||||
}
|
||||
|
||||
/** Indicates that a method is implemented by the annotation processor. */
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface InternalImpl{
|
||||
}
|
||||
|
||||
/** Indicates priority of a method in an entity. Methods with higher priority are done last. */
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package mindustry.annotations;
|
||||
|
||||
import arc.files.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import com.squareup.javapoet.*;
|
||||
@@ -30,6 +31,7 @@ public abstract class BaseProcessor extends AbstractProcessor{
|
||||
protected int round;
|
||||
protected int rounds = 1;
|
||||
protected RoundEnvironment env;
|
||||
protected Fi rootDirectory;
|
||||
|
||||
public static String getMethodName(Element element){
|
||||
return ((TypeElement)element.getEnclosingElement()).getQualifiedName().toString() + "." + element.getSimpleName();
|
||||
@@ -113,6 +115,17 @@ public abstract class BaseProcessor extends AbstractProcessor{
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv){
|
||||
if(round++ >= rounds) return false; //only process 1 round
|
||||
if(rootDirectory == null){
|
||||
try{
|
||||
String path = Fi.get(filer.getResource(StandardLocation.CLASS_OUTPUT, "no", "no")
|
||||
.toUri().toURL().toString().substring(System.getProperty("os.name").contains("Windows") ? 6 : "file:".length()))
|
||||
.parent().parent().parent().parent().parent().parent().parent().toString().replace("%20", " ");
|
||||
rootDirectory = Fi.get(path);
|
||||
}catch(IOException e){
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
this.env = roundEnv;
|
||||
try{
|
||||
process(roundEnv);
|
||||
|
||||
@@ -5,29 +5,22 @@ import arc.scene.style.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.serialization.*;
|
||||
import com.squareup.javapoet.*;
|
||||
import mindustry.annotations.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.annotations.*;
|
||||
|
||||
import javax.annotation.processing.*;
|
||||
import javax.lang.model.*;
|
||||
import javax.lang.model.element.*;
|
||||
import javax.tools.Diagnostic.*;
|
||||
import javax.tools.*;
|
||||
import java.util.*;
|
||||
|
||||
@SupportedAnnotationTypes("mindustry.annotations.Annotations.StyleDefaults")
|
||||
public class AssetsProcess extends BaseProcessor{
|
||||
private String path;
|
||||
|
||||
@Override
|
||||
public void process(RoundEnvironment env) throws Exception{
|
||||
path = Fi.get(BaseProcessor.filer.createResource(StandardLocation.CLASS_OUTPUT, "no", "no")
|
||||
.toUri().toURL().toString().substring(System.getProperty("os.name").contains("Windows") ? 6 : "file:".length()))
|
||||
.parent().parent().parent().parent().parent().parent().toString();
|
||||
path = path.replace("%20", " ");
|
||||
|
||||
processSounds("Sounds", path + "/assets/sounds", "arc.audio.Sound");
|
||||
processSounds("Musics", path + "/assets/music", "arc.audio.Music");
|
||||
processSounds("Sounds", rootDirectory + "/core/assets/sounds", "arc.audio.Sound");
|
||||
processSounds("Musics", rootDirectory + "/core/assets/music", "arc.audio.Music");
|
||||
processUI(env.getElementsAnnotatedWith(StyleDefaults.class));
|
||||
}
|
||||
|
||||
@@ -38,8 +31,8 @@ public class AssetsProcess extends BaseProcessor{
|
||||
MethodSpec.Builder load = MethodSpec.methodBuilder("load").addModifiers(Modifier.PUBLIC, Modifier.STATIC);
|
||||
MethodSpec.Builder loadStyles = MethodSpec.methodBuilder("loadStyles").addModifiers(Modifier.PUBLIC, Modifier.STATIC);
|
||||
MethodSpec.Builder icload = MethodSpec.methodBuilder("load").addModifiers(Modifier.PUBLIC, Modifier.STATIC);
|
||||
String resources = path + "/assets-raw/sprites/ui";
|
||||
Jval icons = Jval.read(Fi.get(path + "/assets-raw/fontgen/config.json").readString());
|
||||
String resources = rootDirectory + "/core/assets-raw/sprites/ui";
|
||||
Jval icons = Jval.read(Fi.get(rootDirectory + "/core/assets-raw/fontgen/config.json").readString());
|
||||
|
||||
ictype.addField(FieldSpec.builder(ParameterizedTypeName.get(ObjectMap.class, String.class, TextureRegionDrawable.class),
|
||||
"icons", Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL).initializer("new ObjectMap<>()").build());
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package mindustry.annotations.impl;
|
||||
|
||||
import arc.files.*;
|
||||
import arc.func.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import arc.util.io.*;
|
||||
import com.squareup.javapoet.*;
|
||||
import com.squareup.javapoet.TypeSpec.*;
|
||||
import com.sun.source.tree.*;
|
||||
@@ -21,7 +23,7 @@ import java.lang.annotation.*;
|
||||
"mindustry.annotations.Annotations.BaseComponent"
|
||||
})
|
||||
public class EntityProcess extends BaseProcessor{
|
||||
Array<Definition> definitions = new Array<>();
|
||||
Array<EntityDefinition> definitions = new Array<>();
|
||||
Array<GroupDefinition> groupDefs = new Array<>();
|
||||
Array<Stype> baseComponents;
|
||||
ObjectMap<String, Stype> componentNames = new ObjectMap<>();
|
||||
@@ -161,7 +163,7 @@ public class EntityProcess extends BaseProcessor{
|
||||
//only write the block if it's a void method with several entries
|
||||
boolean writeBlock = first.ret().toString().equals("void") && entry.value.size > 1;
|
||||
|
||||
if((entry.value.first().is(Modifier.ABSTRACT) || entry.value.first().is(Modifier.NATIVE)) && entry.value.size == 1){
|
||||
if((entry.value.first().is(Modifier.ABSTRACT) || entry.value.first().is(Modifier.NATIVE)) && entry.value.size == 1 && !entry.value.first().has(InternalImpl.class)){
|
||||
err(entry.value.first().up().getSimpleName() + "#" + entry.value.first() + " is an abstract method and must be implemented in some component", type);
|
||||
}
|
||||
|
||||
@@ -208,7 +210,7 @@ public class EntityProcess extends BaseProcessor{
|
||||
builder.addMethod(mbuilder.build());
|
||||
}
|
||||
|
||||
definitions.add(new Definition(builder, type, components, groups));
|
||||
definitions.add(new EntityDefinition("mindustry.gen." + name, builder, type, components, groups));
|
||||
}
|
||||
|
||||
//generate groups
|
||||
@@ -216,6 +218,7 @@ public class EntityProcess extends BaseProcessor{
|
||||
MethodSpec.Builder groupInit = MethodSpec.methodBuilder("init").addModifiers(Modifier.PUBLIC, Modifier.STATIC);
|
||||
for(GroupDefinition group : groupDefs){
|
||||
Stype ctype = group.components.first();
|
||||
//class names for interface/group
|
||||
ClassName itype = ClassName.bestGuess("mindustry.gen." + interfaceName(ctype));
|
||||
ClassName groupc = ClassName.bestGuess("mindustry.entities.EntityGroup");
|
||||
|
||||
@@ -226,16 +229,61 @@ public class EntityProcess extends BaseProcessor{
|
||||
groupInit.addStatement("$L = new $T<>($L, $L)", group.name, groupc, group.def.spatial(), group.def.mapping());
|
||||
}
|
||||
|
||||
//write the groups
|
||||
groupsBuilder.addMethod(groupInit.build());
|
||||
|
||||
write(groupsBuilder);
|
||||
|
||||
//load map of sync IDs
|
||||
StringMap map = new StringMap();
|
||||
Fi idProps = rootDirectory.child("annotations/src/main/resources/classids.properties");
|
||||
if(!idProps.exists()) idProps.writeString("");
|
||||
PropertiesUtils.load(map, idProps.reader());
|
||||
//next ID to be used in generation
|
||||
Integer max = map.values().toArray().map(Integer::parseInt).max(i -> i);
|
||||
int maxID = max == null ? 0 : max + 1;
|
||||
|
||||
//assign IDs
|
||||
definitions.sort(Structs.comparing(t -> t.base.toString()));
|
||||
for(EntityDefinition def : definitions){
|
||||
String name = def.base.fullName();
|
||||
if(map.containsKey(name)){
|
||||
def.classID = map.getInt(name);
|
||||
}else{
|
||||
def.classID = maxID++;
|
||||
map.put(name, def.classID + "");
|
||||
}
|
||||
}
|
||||
|
||||
//write assigned IDs
|
||||
PropertiesUtils.store(map, idProps.writer(false), "Maps entity names to IDs. Autogenerated.");
|
||||
|
||||
//build mapping class for sync IDs
|
||||
TypeSpec.Builder idBuilder = TypeSpec.classBuilder("ClassMapping").addModifiers(Modifier.PUBLIC)
|
||||
.addField(FieldSpec.builder(TypeName.get(Prov[].class), "mapping", Modifier.PRIVATE, Modifier.STATIC).initializer("new Prov[256]").build())
|
||||
.addMethod(MethodSpec.methodBuilder("map").addModifiers(Modifier.PUBLIC, Modifier.STATIC)
|
||||
.returns(TypeName.get(Prov.class)).addParameter(int.class, "id").addStatement("return mapping[id]").build());
|
||||
|
||||
CodeBlock.Builder idStore = CodeBlock.builder();
|
||||
|
||||
//store the mappings
|
||||
for(EntityDefinition def : definitions){
|
||||
//store mapping
|
||||
idStore.addStatement("mapping[$L] = $L::new", def.classID, def.name);
|
||||
//return mapping
|
||||
def.builder.addMethod(MethodSpec.methodBuilder("classId").addAnnotation(Override.class)
|
||||
.returns(int.class).addModifiers(Modifier.PUBLIC).addStatement("return " + def.classID).build());
|
||||
}
|
||||
|
||||
idBuilder.addStaticBlock(idStore.build());
|
||||
|
||||
write(idBuilder);
|
||||
}else{
|
||||
//round 2: generate actual classes and implement interfaces
|
||||
Array<Stype> interfaces = types(EntityInterface.class);
|
||||
|
||||
//implement each definition
|
||||
for(Definition def : definitions){
|
||||
for(EntityDefinition def : definitions){
|
||||
|
||||
//get interface for each component
|
||||
for(Stype comp : def.components){
|
||||
@@ -369,14 +417,17 @@ public class EntityProcess extends BaseProcessor{
|
||||
}
|
||||
}
|
||||
|
||||
class Definition{
|
||||
class EntityDefinition{
|
||||
final Array<GroupDefinition> groups;
|
||||
final Array<Stype> components;
|
||||
final TypeSpec.Builder builder;
|
||||
final Stype base;
|
||||
final String name;
|
||||
int classID;
|
||||
|
||||
public Definition(Builder builder, Stype base, Array<Stype> components, Array<GroupDefinition> groups){
|
||||
public EntityDefinition(String name, Builder builder, Stype base, Array<Stype> components, Array<GroupDefinition> groups){
|
||||
this.builder = builder;
|
||||
this.name = name;
|
||||
this.base = base;
|
||||
this.groups = groups;
|
||||
this.components = components;
|
||||
|
||||
@@ -16,6 +16,10 @@ public class Stype extends Selement<TypeElement>{
|
||||
return new Stype((TypeElement)BaseProcessor.typeu.asElement(mirror));
|
||||
}
|
||||
|
||||
public String fullName(){
|
||||
return mirror().toString();
|
||||
}
|
||||
|
||||
public Array<Stype> interfaces(){
|
||||
return Array.with(e.getInterfaces()).map(Stype::of);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user