Annotation system bugs fixed
This commit is contained in:
@@ -15,10 +15,10 @@ public class Annotations {
|
|||||||
@Target(ElementType.METHOD)
|
@Target(ElementType.METHOD)
|
||||||
@Retention(RetentionPolicy.CLASS)
|
@Retention(RetentionPolicy.CLASS)
|
||||||
public @interface Remote {
|
public @interface Remote {
|
||||||
/**Whether this method can be invoked on remote clients.*/
|
/**Whether this method can be invoked from remote clients.*/
|
||||||
boolean client() default true;
|
boolean client() default false;
|
||||||
/**Whether this method can be invoked on the remote server.*/
|
/**Whether this method can be invoked from the remote server.*/
|
||||||
boolean server() default false;
|
boolean server() default true;
|
||||||
/**Whether a client-specific method is generated that accepts a connecton ID and sends to only one player. Default is false.
|
/**Whether a client-specific method is generated that accepts a connecton ID and sends to only one player. Default is false.
|
||||||
* Only affects client methods.*/
|
* Only affects client methods.*/
|
||||||
boolean one() default false;
|
boolean one() default false;
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import io.anuke.annotations.Annotations.WriteClass;
|
|||||||
|
|
||||||
import javax.annotation.processing.RoundEnvironment;
|
import javax.annotation.processing.RoundEnvironment;
|
||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
|
import javax.lang.model.type.MirroredTypeException;
|
||||||
import javax.tools.Diagnostic.Kind;
|
import javax.tools.Diagnostic.Kind;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
/**This class finds reader and writer methods annotated by the {@link io.anuke.annotations.Annotations.WriteClass}
|
/**This class finds reader and writer methods annotated by the {@link io.anuke.annotations.Annotations.WriteClass}
|
||||||
* and {@link io.anuke.annotations.Annotations.ReadClass} annotations.*/
|
* and {@link io.anuke.annotations.Annotations.ReadClass} annotations.*/
|
||||||
@@ -26,30 +26,48 @@ public class IOFinder {
|
|||||||
//look for writers first
|
//look for writers first
|
||||||
for(Element writer : writers){
|
for(Element writer : writers){
|
||||||
WriteClass writean = writer.getAnnotation(WriteClass.class);
|
WriteClass writean = writer.getAnnotation(WriteClass.class);
|
||||||
Class<?> type = writean.value();
|
String typeName = getValue(writean);
|
||||||
|
|
||||||
//make sure there's only one read method
|
//make sure there's only one read method
|
||||||
if(readers.stream().filter(elem -> elem.getAnnotation(ReadClass.class).value() == type).count() > 1){
|
if(readers.stream().filter(elem -> getValue(elem.getAnnotation(ReadClass.class)).equals(typeName)).count() > 1){
|
||||||
Utils.messager.printMessage(Kind.ERROR, "Multiple writer methods for type: ", writer);
|
Utils.messager.printMessage(Kind.ERROR, "Multiple writer methods for type: ", writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
//make sure there's only one write method
|
//make sure there's only one write method
|
||||||
Stream<? extends Element> stream = readers.stream().filter(elem -> elem.getAnnotation(ReadClass.class).value() == type);
|
long count = readers.stream().filter(elem -> getValue(elem.getAnnotation(ReadClass.class)).equals(typeName)).count();
|
||||||
if(stream.count() == 0){
|
if(count == 0){
|
||||||
Utils.messager.printMessage(Kind.ERROR, "Writer method does not have an accompanying reader: ", writer);
|
Utils.messager.printMessage(Kind.ERROR, "Writer method does not have an accompanying reader: ", writer);
|
||||||
}else if(stream.count() > 1){
|
}else if(count > 1){
|
||||||
Utils.messager.printMessage(Kind.ERROR, "Writer method has multiple reader for type: ", writer);
|
Utils.messager.printMessage(Kind.ERROR, "Writer method has multiple reader for type: ", writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
Element reader = stream.findFirst().get();
|
Element reader = readers.stream().filter(elem -> getValue(elem.getAnnotation(ReadClass.class)).equals(typeName)).findFirst().get();
|
||||||
|
|
||||||
//add to result list
|
//add to result list
|
||||||
result.put(type.getName(), new ClassSerializer(Utils.getMethodName(reader), Utils.getMethodName(writer), type.getName()));
|
result.put(typeName, new ClassSerializer(Utils.getMethodName(reader), Utils.getMethodName(writer), typeName));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getValue(WriteClass write){
|
||||||
|
try {
|
||||||
|
Class<?> type = write.value();
|
||||||
|
return type.getName();
|
||||||
|
}catch (MirroredTypeException e){
|
||||||
|
return e.getTypeMirror().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getValue(ReadClass read){
|
||||||
|
try {
|
||||||
|
Class<?> type = read.value();
|
||||||
|
return type.getName();
|
||||||
|
}catch (MirroredTypeException e){
|
||||||
|
return e.getTypeMirror().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**Information about read/write methods for a specific class type.*/
|
/**Information about read/write methods for a specific class type.*/
|
||||||
public static class ClassSerializer{
|
public static class ClassSerializer{
|
||||||
/**Fully qualified method name of the reader.*/
|
/**Fully qualified method name of the reader.*/
|
||||||
|
|||||||
@@ -19,23 +19,11 @@ import java.util.Objects;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
//TODO document
|
|
||||||
//TODO split up into more classes
|
/**The annotation processor for generating remote method call code.*/
|
||||||
//TODO somehow use annotations to generate serializers for each type?
|
|
||||||
//TODO documentation
|
|
||||||
//TODO custom hash to verify server/client compatibility, just in case!
|
|
||||||
//TODO specify creation class for putting each method
|
|
||||||
//TODO unified Call.functionName() class for more unified usage
|
|
||||||
//TODO error reporting for invalid usage, e.g. method IDs
|
|
||||||
//TODO automatically disable calling on server/client when it's not necessary
|
|
||||||
//TODO autogenerate methods for calling functions for specific clients
|
|
||||||
@SupportedSourceVersion(SourceVersion.RELEASE_8)
|
@SupportedSourceVersion(SourceVersion.RELEASE_8)
|
||||||
@SupportedAnnotationTypes({
|
@SupportedAnnotationTypes({
|
||||||
"io.anuke.annotations.Annotations.RemoteClient",
|
"io.anuke.annotations.Annotations.Remote",
|
||||||
"io.anuke.annotations.Annotations.RemoteServer",
|
|
||||||
"io.anuke.annotations.Annotations.Local",
|
|
||||||
"io.anuke.annotations.Annotations.Unreliable",
|
|
||||||
"io.anuke.annotations.Annotations.In",
|
|
||||||
"io.anuke.annotations.Annotations.WriteClass",
|
"io.anuke.annotations.Annotations.WriteClass",
|
||||||
"io.anuke.annotations.Annotations.ReadClass",
|
"io.anuke.annotations.Annotations.ReadClass",
|
||||||
})
|
})
|
||||||
@@ -125,10 +113,10 @@ public class RemoteMethodAnnotationProcessor extends AbstractProcessor {
|
|||||||
RemoteReadGenerator readgen = new RemoteReadGenerator(serializers);
|
RemoteReadGenerator readgen = new RemoteReadGenerator(serializers);
|
||||||
RemoteWriteGenerator writegen = new RemoteWriteGenerator(serializers);
|
RemoteWriteGenerator writegen = new RemoteWriteGenerator(serializers);
|
||||||
|
|
||||||
//generate client readers
|
|
||||||
readgen.generateFor(methods.stream().filter(method -> method.client).collect(Collectors.toList()), readClientName, packageName, false);
|
|
||||||
//generate server readers
|
//generate server readers
|
||||||
readgen.generateFor(methods.stream().filter(method -> method.server).collect(Collectors.toList()), readServerName, packageName, true);
|
readgen.generateFor(methods.stream().filter(method -> method.client).collect(Collectors.toList()), readServerName, packageName, true);
|
||||||
|
//generate client readers
|
||||||
|
readgen.generateFor(methods.stream().filter(method -> method.server).collect(Collectors.toList()), readClientName, packageName, false);
|
||||||
|
|
||||||
//generate the methods to invoke (write)
|
//generate the methods to invoke (write)
|
||||||
writegen.generateFor(classes, packageName);
|
writegen.generateFor(classes, packageName);
|
||||||
@@ -136,7 +124,7 @@ public class RemoteMethodAnnotationProcessor extends AbstractProcessor {
|
|||||||
//create class for storing unique method hash
|
//create class for storing unique method hash
|
||||||
TypeSpec.Builder hashBuilder = TypeSpec.classBuilder("MethodHash").addModifiers(Modifier.PUBLIC);
|
TypeSpec.Builder hashBuilder = TypeSpec.classBuilder("MethodHash").addModifiers(Modifier.PUBLIC);
|
||||||
hashBuilder.addField(FieldSpec.builder(int.class, "HASH", Modifier.STATIC, Modifier.PUBLIC, Modifier.FINAL)
|
hashBuilder.addField(FieldSpec.builder(int.class, "HASH", Modifier.STATIC, Modifier.PUBLIC, Modifier.FINAL)
|
||||||
.initializer("$1L)", Objects.hash(methods)).build());
|
.initializer("$1L", Objects.hash(methods)).build());
|
||||||
|
|
||||||
//build and write resulting hash class
|
//build and write resulting hash class
|
||||||
TypeSpec spec = hashBuilder.build();
|
TypeSpec spec = hashBuilder.build();
|
||||||
@@ -145,6 +133,7 @@ public class RemoteMethodAnnotationProcessor extends AbstractProcessor {
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
}catch (Exception e){
|
}catch (Exception e){
|
||||||
|
e.printStackTrace();
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ public class RemoteReadGenerator {
|
|||||||
//end control flow if necessary
|
//end control flow if necessary
|
||||||
if(started){
|
if(started){
|
||||||
readBlock.nextControlFlow("else");
|
readBlock.nextControlFlow("else");
|
||||||
readBlock.addStatement("throw new $1N(\"Invalid read method ID: \" + id + \"\")"); //handle invalid method IDs
|
readBlock.addStatement("throw new $1N(\"Invalid read method ID: \" + id + \"\")", RuntimeException.class.getName()); //handle invalid method IDs
|
||||||
readBlock.endControlFlow();
|
readBlock.endControlFlow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ public class RemoteWriteGenerator {
|
|||||||
|
|
||||||
//write the 'send even to one player' variant, which is only applicable on the server
|
//write the 'send even to one player' variant, which is only applicable on the server
|
||||||
if(methodEntry.server && methodEntry.oneVariant){
|
if(methodEntry.server && methodEntry.oneVariant){
|
||||||
writeMethodVariant(classBuilder, methodEntry, true);
|
writeMethodVariant(classBuilder, methodEntry, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,6 +52,7 @@ public class RemoteWriteGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**Creates a specific variant for a method entry.*/
|
||||||
private void writeMethodVariant(TypeSpec.Builder classBuilder, MethodEntry methodEntry, boolean toAll){
|
private void writeMethodVariant(TypeSpec.Builder classBuilder, MethodEntry methodEntry, boolean toAll){
|
||||||
ExecutableElement elem = methodEntry.element;
|
ExecutableElement elem = methodEntry.element;
|
||||||
|
|
||||||
@@ -134,7 +135,7 @@ public class RemoteWriteGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//add statement for writing it
|
//add statement for writing it
|
||||||
method.addStatement(ser.writeMethod + "(buffer, " + varName +")");
|
method.addStatement(ser.writeMethod + "(TEMP_BUFFER, " + varName +")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ public class NetClient extends Module {
|
|||||||
|
|
||||||
Net.handleClient(InvokePacket.class, packet -> {
|
Net.handleClient(InvokePacket.class, packet -> {
|
||||||
//TODO invoke it
|
//TODO invoke it
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.badlogic.gdx.utils.IntMap;
|
|||||||
import com.badlogic.gdx.utils.TimeUtils;
|
import com.badlogic.gdx.utils.TimeUtils;
|
||||||
import io.anuke.mindustry.core.GameState.State;
|
import io.anuke.mindustry.core.GameState.State;
|
||||||
import io.anuke.mindustry.entities.Player;
|
import io.anuke.mindustry.entities.Player;
|
||||||
|
import io.anuke.mindustry.gen.RemoteReadServer;
|
||||||
import io.anuke.mindustry.net.Administration;
|
import io.anuke.mindustry.net.Administration;
|
||||||
import io.anuke.mindustry.net.Administration.PlayerInfo;
|
import io.anuke.mindustry.net.Administration.PlayerInfo;
|
||||||
import io.anuke.mindustry.net.Net;
|
import io.anuke.mindustry.net.Net;
|
||||||
@@ -49,7 +50,7 @@ public class NetServer extends Module{
|
|||||||
|
|
||||||
Net.handleServer(InvokePacket.class, (id, packet) -> {
|
Net.handleServer(InvokePacket.class, (id, packet) -> {
|
||||||
//TODO implement
|
//TODO implement
|
||||||
//CallServer.readPacket(packet.writeBuffer, packet.type, connections.get(id));
|
RemoteReadServer.readPacket(packet.writeBuffer, packet.type, connections.get(id));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,18 @@
|
|||||||
package io.anuke.mindustry.net;
|
package io.anuke.mindustry.net;
|
||||||
|
|
||||||
|
import io.anuke.annotations.Annotations.Remote;
|
||||||
|
import io.anuke.mindustry.entities.Player;
|
||||||
|
import io.anuke.mindustry.world.Tile;
|
||||||
|
|
||||||
public class NetEvents {
|
public class NetEvents {
|
||||||
|
|
||||||
|
@Remote(unreliable = true, one = true)
|
||||||
|
public static void callClientMethod(int something, Player player, String str, boolean bool){
|
||||||
|
System.out.println("Called " + something + " ? " + bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Remote(local = false)
|
||||||
|
public static void someOtherMethod(Tile tile){
|
||||||
|
System.out.println("Called with tile " + tile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package io.anuke.mindustry.net;
|
|||||||
import com.badlogic.gdx.utils.TimeUtils;
|
import com.badlogic.gdx.utils.TimeUtils;
|
||||||
import io.anuke.mindustry.Vars;
|
import io.anuke.mindustry.Vars;
|
||||||
import io.anuke.mindustry.entities.Player;
|
import io.anuke.mindustry.entities.Player;
|
||||||
|
import io.anuke.mindustry.gen.RemoteReadClient;
|
||||||
import io.anuke.mindustry.net.Packet.ImportantPacket;
|
import io.anuke.mindustry.net.Packet.ImportantPacket;
|
||||||
import io.anuke.mindustry.net.Packet.UnimportantPacket;
|
import io.anuke.mindustry.net.Packet.UnimportantPacket;
|
||||||
|
|
||||||
@@ -38,6 +39,7 @@ public class Packets {
|
|||||||
if(Net.client()){
|
if(Net.client()){
|
||||||
//TODO implement
|
//TODO implement
|
||||||
//CallClient.readPacket(buffer, type);
|
//CallClient.readPacket(buffer, type);
|
||||||
|
RemoteReadClient.readPacket(buffer, type);
|
||||||
}else{
|
}else{
|
||||||
byte[] bytes = new byte[writeLength];
|
byte[] bytes = new byte[writeLength];
|
||||||
buffer.get(bytes);
|
buffer.get(bytes);
|
||||||
|
|||||||
Reference in New Issue
Block a user