From c443eee15d241b4a049b47ecb76c4c0958aaeda5 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 6 Jun 2018 20:56:59 -0400 Subject: [PATCH] Annotation system bugs fixed --- .../src/io/anuke/annotations/Annotations.java | 8 ++--- .../src/io/anuke/annotations/IOFinder.java | 34 ++++++++++++++----- .../RemoteMethodAnnotationProcessor.java | 27 +++++---------- .../annotations/RemoteReadGenerator.java | 2 +- .../annotations/RemoteWriteGenerator.java | 5 +-- .../io/anuke/mindustry/core/NetClient.java | 1 + .../io/anuke/mindustry/core/NetServer.java | 3 +- .../src/io/anuke/mindustry/net/NetEvents.java | 13 +++++++ core/src/io/anuke/mindustry/net/Packets.java | 2 ++ 9 files changed, 60 insertions(+), 35 deletions(-) diff --git a/annotations/src/io/anuke/annotations/Annotations.java b/annotations/src/io/anuke/annotations/Annotations.java index 60904a29d2..e6e7705dde 100644 --- a/annotations/src/io/anuke/annotations/Annotations.java +++ b/annotations/src/io/anuke/annotations/Annotations.java @@ -15,10 +15,10 @@ public class Annotations { @Target(ElementType.METHOD) @Retention(RetentionPolicy.CLASS) public @interface Remote { - /**Whether this method can be invoked on remote clients.*/ - boolean client() default true; - /**Whether this method can be invoked on the remote server.*/ - boolean server() default false; + /**Whether this method can be invoked from remote clients.*/ + boolean client() default false; + /**Whether this method can be invoked from the remote server.*/ + 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. * Only affects client methods.*/ boolean one() default false; diff --git a/annotations/src/io/anuke/annotations/IOFinder.java b/annotations/src/io/anuke/annotations/IOFinder.java index aec7208efc..769cc79072 100644 --- a/annotations/src/io/anuke/annotations/IOFinder.java +++ b/annotations/src/io/anuke/annotations/IOFinder.java @@ -5,10 +5,10 @@ import io.anuke.annotations.Annotations.WriteClass; import javax.annotation.processing.RoundEnvironment; import javax.lang.model.element.Element; +import javax.lang.model.type.MirroredTypeException; import javax.tools.Diagnostic.Kind; import java.util.HashMap; 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} * and {@link io.anuke.annotations.Annotations.ReadClass} annotations.*/ @@ -26,30 +26,48 @@ public class IOFinder { //look for writers first for(Element writer : writers){ WriteClass writean = writer.getAnnotation(WriteClass.class); - Class type = writean.value(); + String typeName = getValue(writean); //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); } //make sure there's only one write method - Stream stream = readers.stream().filter(elem -> elem.getAnnotation(ReadClass.class).value() == type); - if(stream.count() == 0){ + long count = readers.stream().filter(elem -> getValue(elem.getAnnotation(ReadClass.class)).equals(typeName)).count(); + if(count == 0){ 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); } - Element reader = stream.findFirst().get(); + Element reader = readers.stream().filter(elem -> getValue(elem.getAnnotation(ReadClass.class)).equals(typeName)).findFirst().get(); //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; } + 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.*/ public static class ClassSerializer{ /**Fully qualified method name of the reader.*/ diff --git a/annotations/src/io/anuke/annotations/RemoteMethodAnnotationProcessor.java b/annotations/src/io/anuke/annotations/RemoteMethodAnnotationProcessor.java index 638e801f53..c42df9f7a7 100644 --- a/annotations/src/io/anuke/annotations/RemoteMethodAnnotationProcessor.java +++ b/annotations/src/io/anuke/annotations/RemoteMethodAnnotationProcessor.java @@ -19,23 +19,11 @@ import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; -//TODO document -//TODO split up into more classes -//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 + +/**The annotation processor for generating remote method call code.*/ @SupportedSourceVersion(SourceVersion.RELEASE_8) @SupportedAnnotationTypes({ - "io.anuke.annotations.Annotations.RemoteClient", - "io.anuke.annotations.Annotations.RemoteServer", - "io.anuke.annotations.Annotations.Local", - "io.anuke.annotations.Annotations.Unreliable", - "io.anuke.annotations.Annotations.In", + "io.anuke.annotations.Annotations.Remote", "io.anuke.annotations.Annotations.WriteClass", "io.anuke.annotations.Annotations.ReadClass", }) @@ -125,10 +113,10 @@ public class RemoteMethodAnnotationProcessor extends AbstractProcessor { RemoteReadGenerator readgen = new RemoteReadGenerator(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 - 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) writegen.generateFor(classes, packageName); @@ -136,7 +124,7 @@ public class RemoteMethodAnnotationProcessor extends AbstractProcessor { //create class for storing unique method hash TypeSpec.Builder hashBuilder = TypeSpec.classBuilder("MethodHash").addModifiers(Modifier.PUBLIC); 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 TypeSpec spec = hashBuilder.build(); @@ -145,6 +133,7 @@ public class RemoteMethodAnnotationProcessor extends AbstractProcessor { return true; }catch (Exception e){ + e.printStackTrace(); throw new RuntimeException(e); } } diff --git a/annotations/src/io/anuke/annotations/RemoteReadGenerator.java b/annotations/src/io/anuke/annotations/RemoteReadGenerator.java index 6068fb175b..7a053ede6f 100644 --- a/annotations/src/io/anuke/annotations/RemoteReadGenerator.java +++ b/annotations/src/io/anuke/annotations/RemoteReadGenerator.java @@ -113,7 +113,7 @@ public class RemoteReadGenerator { //end control flow if necessary if(started){ 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(); } diff --git a/annotations/src/io/anuke/annotations/RemoteWriteGenerator.java b/annotations/src/io/anuke/annotations/RemoteWriteGenerator.java index 1838ea152d..7086611528 100644 --- a/annotations/src/io/anuke/annotations/RemoteWriteGenerator.java +++ b/annotations/src/io/anuke/annotations/RemoteWriteGenerator.java @@ -42,7 +42,7 @@ public class RemoteWriteGenerator { //write the 'send even to one player' variant, which is only applicable on the server 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){ ExecutableElement elem = methodEntry.element; @@ -134,7 +135,7 @@ public class RemoteWriteGenerator { } //add statement for writing it - method.addStatement(ser.writeMethod + "(buffer, " + varName +")"); + method.addStatement(ser.writeMethod + "(TEMP_BUFFER, " + varName +")"); } } diff --git a/core/src/io/anuke/mindustry/core/NetClient.java b/core/src/io/anuke/mindustry/core/NetClient.java index e9abc9c46f..889edaa58e 100644 --- a/core/src/io/anuke/mindustry/core/NetClient.java +++ b/core/src/io/anuke/mindustry/core/NetClient.java @@ -80,6 +80,7 @@ public class NetClient extends Module { Net.handleClient(InvokePacket.class, packet -> { //TODO invoke it + }); } diff --git a/core/src/io/anuke/mindustry/core/NetServer.java b/core/src/io/anuke/mindustry/core/NetServer.java index 0d4e24b76b..d8204e4319 100644 --- a/core/src/io/anuke/mindustry/core/NetServer.java +++ b/core/src/io/anuke/mindustry/core/NetServer.java @@ -4,6 +4,7 @@ import com.badlogic.gdx.utils.IntMap; import com.badlogic.gdx.utils.TimeUtils; import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.entities.Player; +import io.anuke.mindustry.gen.RemoteReadServer; import io.anuke.mindustry.net.Administration; import io.anuke.mindustry.net.Administration.PlayerInfo; import io.anuke.mindustry.net.Net; @@ -49,7 +50,7 @@ public class NetServer extends Module{ Net.handleServer(InvokePacket.class, (id, packet) -> { //TODO implement - //CallServer.readPacket(packet.writeBuffer, packet.type, connections.get(id)); + RemoteReadServer.readPacket(packet.writeBuffer, packet.type, connections.get(id)); }); } diff --git a/core/src/io/anuke/mindustry/net/NetEvents.java b/core/src/io/anuke/mindustry/net/NetEvents.java index 2b338fc885..9106c96b40 100644 --- a/core/src/io/anuke/mindustry/net/NetEvents.java +++ b/core/src/io/anuke/mindustry/net/NetEvents.java @@ -1,5 +1,18 @@ 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 { + @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); + } } diff --git a/core/src/io/anuke/mindustry/net/Packets.java b/core/src/io/anuke/mindustry/net/Packets.java index 026f3e8e14..9bdf56d74f 100644 --- a/core/src/io/anuke/mindustry/net/Packets.java +++ b/core/src/io/anuke/mindustry/net/Packets.java @@ -3,6 +3,7 @@ package io.anuke.mindustry.net; import com.badlogic.gdx.utils.TimeUtils; import io.anuke.mindustry.Vars; 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.UnimportantPacket; @@ -38,6 +39,7 @@ public class Packets { if(Net.client()){ //TODO implement //CallClient.readPacket(buffer, type); + RemoteReadClient.readPacket(buffer, type); }else{ byte[] bytes = new byte[writeLength]; buffer.get(bytes);