Autogeneration of some IO code
This commit is contained in:
@@ -24,6 +24,12 @@ public class Annotations{
|
||||
public @interface Replace{
|
||||
}
|
||||
|
||||
/** Indicates that a component field is imported from other components. */
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Import{
|
||||
}
|
||||
|
||||
/** Indicates that a component field is read-only. */
|
||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@@ -70,6 +76,7 @@ public class Annotations{
|
||||
Class[] value();
|
||||
boolean isFinal() default true;
|
||||
boolean pooled() default false;
|
||||
boolean serialize() default true;
|
||||
}
|
||||
|
||||
/** Indicates an internal interface for entity components. */
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package mindustry.annotations.entity;
|
||||
|
||||
import arc.util.*;
|
||||
import com.squareup.javapoet.*;
|
||||
import com.squareup.javapoet.MethodSpec.*;
|
||||
import mindustry.annotations.*;
|
||||
|
||||
import javax.lang.model.element.*;
|
||||
|
||||
public class EntityIO{
|
||||
final TypeElement contentElem = BaseProcessor.elementu.getTypeElement("mindustry.ctype.Content");
|
||||
final MethodSpec.Builder builder;
|
||||
final boolean write;
|
||||
|
||||
EntityIO(Builder builder, boolean write){
|
||||
this.builder = builder;
|
||||
this.write = write;
|
||||
}
|
||||
|
||||
void io(TypeName type, String field) throws Exception{
|
||||
TypeElement element = BaseProcessor.elementu.getTypeElement(type.toString());
|
||||
|
||||
if(type.isPrimitive()){
|
||||
s(type.toString(), field);
|
||||
}else if(type.toString().equals("java.lang.String")){
|
||||
s("UTF", field);
|
||||
}else if(element != null && BaseProcessor.typeu.isSubtype(element.asType(), contentElem.asType())){
|
||||
if(write){
|
||||
s("short", field + ".id");
|
||||
}else{
|
||||
st(field + " = mindustry.Vars.content.getByID(mindustry.ctype.ContentType.$L, input.readShort())", BaseProcessor.simpleName(type.toString()).toLowerCase().replace("type", ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void cont(String text, Object... fmt){
|
||||
builder.beginControlFlow(text, fmt);
|
||||
}
|
||||
|
||||
private void cont(){
|
||||
builder.endControlFlow();
|
||||
}
|
||||
|
||||
private void st(String text, Object... args){
|
||||
builder.addStatement(text, args);
|
||||
}
|
||||
|
||||
private void s(String type, String field){
|
||||
if(write){
|
||||
builder.addStatement("output.write$L($L)", Strings.capitalize(type), field);
|
||||
}else{
|
||||
builder.addStatement("$L = input.read$L()", field, Strings.capitalize(type));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package mindustry.annotations.impl;
|
||||
package mindustry.annotations.entity;
|
||||
|
||||
import arc.files.*;
|
||||
import arc.func.*;
|
||||
@@ -118,7 +118,7 @@ public class EntityProcess extends BaseProcessor{
|
||||
.build())).addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT).build());
|
||||
}
|
||||
|
||||
for(Svar field : component.fields().select(e -> !e.is(Modifier.STATIC) && !e.is(Modifier.PRIVATE) && !e.is(Modifier.TRANSIENT))){
|
||||
for(Svar field : component.fields().select(e -> !e.is(Modifier.STATIC) && !e.is(Modifier.PRIVATE) && !e.has(Import.class))){
|
||||
String cname = field.name();
|
||||
|
||||
//getter
|
||||
@@ -221,19 +221,32 @@ public class EntityProcess extends BaseProcessor{
|
||||
Array<GroupDefinition> groups = groupDefs.select(g -> (!g.components.isEmpty() && !g.components.contains(s -> !components.contains(s))) || g.manualInclusions.contains(type));
|
||||
ObjectMap<String, Array<Smethod>> methods = new ObjectMap<>();
|
||||
ObjectMap<FieldSpec, Svar> specVariables = new ObjectMap<>();
|
||||
ObjectSet<String> usedFields = new ObjectSet<>();
|
||||
|
||||
//add serialize() boolean
|
||||
builder.addMethod(MethodSpec.methodBuilder("serialize").addModifiers(Modifier.PUBLIC, Modifier.FINAL).returns(boolean.class).addStatement("return " + ann.serialize()).build());
|
||||
|
||||
//add all components
|
||||
for(Stype comp : components){
|
||||
|
||||
//write fields to the class; ignoring transient ones
|
||||
Array<Svar> fields = comp.fields().select(f -> !f.is(Modifier.TRANSIENT));
|
||||
Array<Svar> fields = comp.fields().select(f -> !f.has(Import.class));
|
||||
for(Svar f : fields){
|
||||
if(!usedFields.add(f.name())){
|
||||
err("Field '" + f.name() + "' of component '" + comp.name() + "' re-defines a field in entity '" + type.name() + "'");
|
||||
continue;
|
||||
}
|
||||
|
||||
FieldSpec.Builder fbuilder = FieldSpec.builder(f.tname(), f.name());
|
||||
//keep statics/finals
|
||||
if(f.is(Modifier.STATIC)){
|
||||
fbuilder.addModifiers(Modifier.STATIC);
|
||||
if(f.is(Modifier.FINAL)) fbuilder.addModifiers(Modifier.FINAL);
|
||||
}
|
||||
//add transient modifier for serialization
|
||||
if(f.is(Modifier.TRANSIENT)){
|
||||
fbuilder.addModifiers(Modifier.TRANSIENT);
|
||||
}
|
||||
//add initializer if it exists
|
||||
if(varInitializers.containsKey(f)){
|
||||
fbuilder.initializer(varInitializers.get(f));
|
||||
@@ -312,6 +325,18 @@ public class EntityProcess extends BaseProcessor{
|
||||
}
|
||||
}
|
||||
|
||||
//SPECIAL CASE: I/O code
|
||||
//note that serialization is generated even for non-serializing entities for manual usage
|
||||
if(first.name().equals("read") || first.name().equals("write")){
|
||||
EntityIO writer = new EntityIO(mbuilder, first.name().equals("write"));
|
||||
//write or read each non-transient field
|
||||
for(FieldSpec spec : builder.fieldSpecs){
|
||||
if(!spec.hasModifier(Modifier.TRANSIENT) && !spec.hasModifier(Modifier.STATIC) && !spec.hasModifier(Modifier.FINAL)){
|
||||
writer.io(spec.type, "this." + spec.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(Smethod elem : entry.value){
|
||||
if(elem.is(Modifier.ABSTRACT) || elem.is(Modifier.NATIVE) || !methodBlocks.containsKey(elem)) continue;
|
||||
|
||||
Reference in New Issue
Block a user