Compare commits
166 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03fe3a04ba | ||
|
|
68e403557a | ||
|
|
c5b88c2763 | ||
|
|
0cbd9a1fcc | ||
|
|
3102931cb4 | ||
|
|
fb302d49c7 | ||
|
|
a4a3e7fc48 | ||
|
|
eb87e5f265 | ||
|
|
9c2569d4f5 | ||
|
|
ce3f4ed0fb | ||
|
|
1b94eed9d3 | ||
|
|
aafecfebbb | ||
|
|
5bbe4af71b | ||
|
|
de9a14c903 | ||
|
|
5ab47f4fe0 | ||
|
|
435860eda4 | ||
|
|
5611a8684c | ||
|
|
f06550fc3c | ||
|
|
652c143ff6 | ||
|
|
64ade54336 | ||
|
|
e6507a84ef | ||
|
|
91148a7fde | ||
|
|
e02f370228 | ||
|
|
5aa1e30006 | ||
|
|
ad7c72015c | ||
|
|
d99f9740e8 | ||
|
|
d1840e7c2a | ||
|
|
e173eb55ca | ||
|
|
d6b5f6a311 | ||
|
|
eaa0b53f30 | ||
|
|
f14df52490 | ||
|
|
29a6b1a8da | ||
|
|
b15a40fcbd | ||
|
|
9da2d1ee9a | ||
|
|
6882a9a355 | ||
|
|
941449c502 | ||
|
|
baab36bfc5 | ||
|
|
f3893533a4 | ||
|
|
0a53c4c1be | ||
|
|
d7eb0d3ba3 | ||
|
|
3a2fef3bd7 | ||
|
|
9ccf95971e | ||
|
|
9b36125b0c | ||
|
|
0ffcd0b94c | ||
|
|
a6801af128 | ||
|
|
30ea039246 | ||
|
|
5a5945cc52 | ||
|
|
e5fd3dec4c | ||
|
|
7b586ea043 | ||
|
|
e98808bc46 | ||
|
|
bc37415a10 | ||
|
|
619b2ba897 | ||
|
|
37a9311202 | ||
|
|
e9f37ea68e | ||
|
|
59431b223b | ||
|
|
da5755b7c1 | ||
|
|
70c06b58ef | ||
|
|
4a2c6c571f | ||
|
|
a5fd881f8d | ||
|
|
d59b23b835 | ||
|
|
e06d8eabec | ||
|
|
ce7eccf524 | ||
|
|
8bb533f646 | ||
|
|
39b35dd9cb | ||
|
|
ff06a005a0 | ||
|
|
fd500f5405 | ||
|
|
67106abb9b | ||
|
|
ea6490cf9f | ||
|
|
627321304d | ||
|
|
d2c2fd7d5f | ||
|
|
fea9f51513 | ||
|
|
4709b5dddc | ||
|
|
b4be655d0c | ||
|
|
19da1e1306 | ||
|
|
9bc24ae47a | ||
|
|
aef5fd85b2 | ||
|
|
ad84329688 | ||
|
|
ae6d33cad1 | ||
|
|
ad9dd83032 | ||
|
|
382ca09f6e | ||
|
|
c978410cb3 | ||
|
|
5eb3f0f3de | ||
|
|
acb3438cc8 | ||
|
|
a9f07f3603 | ||
|
|
4c369dd17c | ||
|
|
c458c77322 | ||
|
|
b93692ad41 | ||
|
|
d84217300c | ||
|
|
49ab7ceb77 | ||
|
|
7ddfcbfabd | ||
|
|
da2aee7d31 | ||
|
|
4c45716149 | ||
|
|
9f20ff151c | ||
|
|
5f7fc3441c | ||
|
|
62179233ef | ||
|
|
376e3d6ef1 | ||
|
|
51bc5c3b74 | ||
|
|
a45a14025d | ||
|
|
eabebcefc7 | ||
|
|
e1a215ae0b | ||
|
|
63d84bead3 | ||
|
|
d872656bc5 | ||
|
|
51b4824c92 | ||
|
|
b4e9e6be32 | ||
|
|
737e3145ec | ||
|
|
2721aa550d | ||
|
|
f92b91c17b | ||
|
|
221b28c153 | ||
|
|
7c2541afa2 | ||
|
|
bfa24cca4c | ||
|
|
9da505119b | ||
|
|
677debd475 | ||
|
|
864c73f791 | ||
|
|
9ed7719464 | ||
|
|
187e1f5848 | ||
|
|
36782a2454 | ||
|
|
6a48a1e0a3 | ||
|
|
d0faecbea5 | ||
|
|
b5ccd36315 | ||
|
|
97cfc33abb | ||
|
|
867a642859 | ||
|
|
d99cad8793 | ||
|
|
2a11f65e10 | ||
|
|
89e1c5afc0 | ||
|
|
a2933e030a | ||
|
|
d21c47a582 | ||
|
|
5ad0193a86 | ||
|
|
881eca636d | ||
|
|
d849a3a87f | ||
|
|
5ebc04ab29 | ||
|
|
379f860a6b | ||
|
|
65211a6021 | ||
|
|
9395fa99be | ||
|
|
b7e1adb8b1 | ||
|
|
315260f7f5 | ||
|
|
69069e2ef3 | ||
|
|
de143a8e16 | ||
|
|
b9e8694e68 | ||
|
|
cd1ed97e52 | ||
|
|
a61234d21e | ||
|
|
9499b9dfaf | ||
|
|
9baaacc8ac | ||
|
|
db3d4b170f | ||
|
|
621233a5b3 | ||
|
|
9a3245c23e | ||
|
|
6fe2697185 | ||
|
|
d7ea0bc21e | ||
|
|
adbfb15932 | ||
|
|
fda6ea4b45 | ||
|
|
93cada6a16 | ||
|
|
0d5dd146ef | ||
|
|
1207fb1440 | ||
|
|
8584fae07a | ||
|
|
0a661766be | ||
|
|
fb6cb4829f | ||
|
|
e14a36a97e | ||
|
|
ca69aafd11 | ||
|
|
923d576a5f | ||
|
|
081edde1f2 | ||
|
|
1ab81fa4ab | ||
|
|
69711151a5 | ||
|
|
aefc4ed83c | ||
|
|
83f44abb5a | ||
|
|
f2bc3e78d7 | ||
|
|
2fe6a3525b | ||
|
|
78fb427120 |
2
.gitignore
vendored
@@ -22,6 +22,7 @@ logs/
|
|||||||
/server/build/
|
/server/build/
|
||||||
changelog
|
changelog
|
||||||
saves/
|
saves/
|
||||||
|
/core/assets-raw/fontgen/out/
|
||||||
core/assets/saves/
|
core/assets/saves/
|
||||||
/core/assets/saves/
|
/core/assets/saves/
|
||||||
steam_appid.txt
|
steam_appid.txt
|
||||||
@@ -30,6 +31,7 @@ steam_appid.txt
|
|||||||
/android/assets/mindustry-maps/
|
/android/assets/mindustry-maps/
|
||||||
/android/assets/mindustry-saves/
|
/android/assets/mindustry-saves/
|
||||||
/core/assets/gifexport/
|
/core/assets/gifexport/
|
||||||
|
/annotations/src/main/resources/META-INF/services
|
||||||
/core/assets/version.properties
|
/core/assets/version.properties
|
||||||
/core/assets/locales
|
/core/assets/locales
|
||||||
/ios/src/mindustry/gen/
|
/ios/src/mindustry/gen/
|
||||||
|
|||||||
@@ -21,13 +21,15 @@ First, make sure you have [JDK 8](https://adoptopenjdk.net/) installed. Open a t
|
|||||||
|
|
||||||
#### Windows
|
#### Windows
|
||||||
|
|
||||||
_Running:_ `gradlew desktop:run`
|
_Running:_ `gradlew.bat desktop:run`
|
||||||
_Building:_ `gradlew desktop:dist`
|
_Building:_ `gradlew.bat desktop:dist`
|
||||||
|
_Sprite Packing:_ `gradlew.bat tools:pack`
|
||||||
|
|
||||||
#### Linux/Mac OS
|
#### Linux/Mac OS
|
||||||
|
|
||||||
_Running:_ `./gradlew desktop:run`
|
_Running:_ `./gradlew desktop:run`
|
||||||
_Building:_ `./gradlew desktop:dist`
|
_Building:_ `./gradlew desktop:dist`
|
||||||
|
_Sprite Packing:_ `./gradlew tools:pack`
|
||||||
|
|
||||||
#### Server
|
#### Server
|
||||||
|
|
||||||
|
|||||||
26
SERVERLIST.md
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
### Adding a server to the list
|
||||||
|
|
||||||
|
Mindustry now has a public list of servers that everyone can see and connect to.
|
||||||
|
This is done by letting clients `GET` a [JSON list of servers](https://github.com/Anuken/Mindustry/blob/master/servers.json) in this repository.
|
||||||
|
|
||||||
|
You may want to add your server to this list. The steps for getting this done are as follows:
|
||||||
|
|
||||||
|
1. **Ensure your server is properly moderated.** For the most part, this applies to survival servers, but PvP servers can be affected as well.
|
||||||
|
You'll need to either hire some moderators, or make use of (currently non-existent) anti-grief and anti-curse plugins.
|
||||||
|
*Consider enabling a rate limit:* `config messageRateLimit 2` will make it so that players can only send messages every 2 seconds, for example.
|
||||||
|
2. **Set an approppriate MOTD, name and description.** This is set with `config <name/desc/motd> <value>`. "Approppriate" means that:
|
||||||
|
- Your name or description must reflect the type of server you're hosting.
|
||||||
|
Since new players may be exposed to the server list early on, put in a phrase like "Co-op survival" or "PvP" so players know what they're getting into. Yes, this is also displayed in the server mode info text, but having extra info in the name doesn't hurt.
|
||||||
|
- Make sure players know where to refer to for server support. It should be fairly clear that the server owner is not me, but you.
|
||||||
|
- Try to be professional in your text; use common sense.
|
||||||
|
3. **Get some good maps.** *(optional, but highly recommended)*. Add some maps to your server and set the map rotation to custom-only. You can get maps from the Steam workshop by subscribing and exporting them; using the `#maps` channel on Discord is also an option.
|
||||||
|
4. **Check your server configuration.** *(optional)* I would recommend adding a message rate limit of 1 second (`config messageRateLimit 1`), and disabling connect/disconnect messages to reduce spam (`config showConnectMessages false`).
|
||||||
|
5. Finally, **submit a pull request** to add your server's IP to the list.
|
||||||
|
This should be fairly straightforward: Press the edit button on the [server file](https://github.com/Anuken/Mindustry/blob/master/servers.json), then add a JSON object with a single key, indicating your server address.
|
||||||
|
For example, if your server address is `google.com`, you would add a comma after the last entry and insert:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"address": "google.com"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Then, press the *'submit pull request'* button and I'll take a look at your server. If I have any issues with it, I'll let you know in the PR comments.
|
||||||
@@ -81,7 +81,7 @@ public class AndroidLauncher extends AndroidApplication{
|
|||||||
if(VERSION.SDK_INT >= VERSION_CODES.Q){
|
if(VERSION.SDK_INT >= VERSION_CODES.Q){
|
||||||
Intent intent = new Intent(open ? Intent.ACTION_OPEN_DOCUMENT : Intent.ACTION_CREATE_DOCUMENT);
|
Intent intent = new Intent(open ? Intent.ACTION_OPEN_DOCUMENT : Intent.ACTION_CREATE_DOCUMENT);
|
||||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||||
intent.setType(extension.equals("zip") ? "application/zip" : "*/*");
|
intent.setType(extension.equals("zip") && !open ? "application/zip" : "*/*");
|
||||||
addResultListener(i -> startActivityForResult(intent, i), (code, in) -> {
|
addResultListener(i -> startActivityForResult(intent, i), (code, in) -> {
|
||||||
if(code == Activity.RESULT_OK && in != null && in.getData() != null){
|
if(code == Activity.RESULT_OK && in != null && in.getData() != null){
|
||||||
Uri uri = in.getData();
|
Uri uri = in.getData();
|
||||||
@@ -150,10 +150,12 @@ public class AndroidLauncher extends AndroidApplication{
|
|||||||
}});
|
}});
|
||||||
checkFiles(getIntent());
|
checkFiles(getIntent());
|
||||||
|
|
||||||
|
|
||||||
//new external folder
|
//new external folder
|
||||||
Fi data = Core.files.absolute(getContext().getExternalFilesDir(null).getAbsolutePath());
|
Fi data = Core.files.absolute(getContext().getExternalFilesDir(null).getAbsolutePath());
|
||||||
|
Core.settings.setDataDirectory(data);
|
||||||
|
|
||||||
//moved to internal storage if there's no file indicating that it moved
|
//move to internal storage if there's no file indicating that it moved
|
||||||
if(!Core.files.local("files_moved").exists()){
|
if(!Core.files.local("files_moved").exists()){
|
||||||
Log.info("Moving files to external storage...");
|
Log.info("Moving files to external storage...");
|
||||||
|
|
||||||
@@ -161,17 +163,16 @@ public class AndroidLauncher extends AndroidApplication{
|
|||||||
//current local storage folder
|
//current local storage folder
|
||||||
Fi src = Core.files.absolute(Core.files.getLocalStoragePath());
|
Fi src = Core.files.absolute(Core.files.getLocalStoragePath());
|
||||||
for(Fi fi : src.list()){
|
for(Fi fi : src.list()){
|
||||||
fi.copyTo(data.child(fi.name()));
|
fi.copyTo(data);
|
||||||
}
|
}
|
||||||
//create marker
|
//create marker
|
||||||
Core.files.local("files_moved").writeString("files moved to " + data);
|
Core.files.local("files_moved").writeString("files moved to " + data);
|
||||||
|
Core.files.local("files_moved_103").writeString("files moved again");
|
||||||
Log.info("Files moved.");
|
Log.info("Files moved.");
|
||||||
}catch(Throwable t){
|
}catch(Throwable t){
|
||||||
Log.err("Failed to move files!");
|
Log.err("Failed to move files!");
|
||||||
t.printStackTrace();
|
t.printStackTrace();
|
||||||
}
|
}
|
||||||
}else{
|
|
||||||
Core.settings.setDataDirectory(data);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,36 @@ package mindustry.annotations;
|
|||||||
import java.lang.annotation.*;
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
public class Annotations{
|
public class Annotations{
|
||||||
|
//region entity interfaces
|
||||||
|
|
||||||
|
/** Indicates multiple inheritance on a component type. */
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
public @interface Depends{
|
||||||
|
Class[] value();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Indicates that a component def is present on all entities. */
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
public @interface BaseComponent{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Indicates an entity definition. */
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
public @interface EntityDef{
|
||||||
|
Class[] value();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Indicates an internal interface for entity components. */
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
public @interface EntityInterface{
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
//region misc. utility
|
||||||
|
|
||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@@ -29,6 +59,9 @@ public class Annotations{
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
//region struct
|
||||||
|
|
||||||
/** Marks a class as a special value type struct. Class name must end in 'Struct'. */
|
/** Marks a class as a special value type struct. Class name must end in 'Struct'. */
|
||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@@ -44,6 +77,9 @@ public class Annotations{
|
|||||||
int value();
|
int value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
//region remote
|
||||||
|
|
||||||
public enum PacketPriority{
|
public enum PacketPriority{
|
||||||
/** Gets put in a queue and processed if not connected. */
|
/** Gets put in a queue and processed if not connected. */
|
||||||
normal,
|
normal,
|
||||||
@@ -138,4 +174,6 @@ public class Annotations{
|
|||||||
public @interface ReadClass{
|
public @interface ReadClass{
|
||||||
Class<?> value();
|
Class<?> value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,19 @@
|
|||||||
package mindustry.annotations;
|
package mindustry.annotations;
|
||||||
|
|
||||||
|
import arc.struct.*;
|
||||||
|
import arc.util.*;
|
||||||
|
import com.squareup.javapoet.*;
|
||||||
|
import com.sun.source.util.*;
|
||||||
|
import mindustry.annotations.util.*;
|
||||||
|
|
||||||
import javax.annotation.processing.*;
|
import javax.annotation.processing.*;
|
||||||
import javax.lang.model.*;
|
import javax.lang.model.*;
|
||||||
import javax.lang.model.element.*;
|
import javax.lang.model.element.*;
|
||||||
|
import javax.lang.model.util.*;
|
||||||
|
import javax.tools.Diagnostic.*;
|
||||||
|
import javax.tools.*;
|
||||||
|
import java.io.*;
|
||||||
|
import java.lang.annotation.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@SupportedSourceVersion(SourceVersion.RELEASE_8)
|
@SupportedSourceVersion(SourceVersion.RELEASE_8)
|
||||||
@@ -10,21 +21,99 @@ public abstract class BaseProcessor extends AbstractProcessor{
|
|||||||
/** Name of the base package to put all the generated classes. */
|
/** Name of the base package to put all the generated classes. */
|
||||||
public static final String packageName = "mindustry.gen";
|
public static final String packageName = "mindustry.gen";
|
||||||
|
|
||||||
private int round;
|
public static Types typeu;
|
||||||
|
public static Elements elementu;
|
||||||
|
public static Filer filer;
|
||||||
|
public static Messager messager;
|
||||||
|
public static Trees trees;
|
||||||
|
|
||||||
@Override
|
protected int round;
|
||||||
public synchronized void init(ProcessingEnvironment processingEnv){
|
protected int rounds = 1;
|
||||||
super.init(processingEnv);
|
protected RoundEnvironment env;
|
||||||
//put all relevant utils into utils class
|
|
||||||
Utils.typeUtils = processingEnv.getTypeUtils();
|
public static String getMethodName(Element element){
|
||||||
Utils.elementUtils = processingEnv.getElementUtils();
|
return ((TypeElement)element.getEnclosingElement()).getQualifiedName().toString() + "." + element.getSimpleName();
|
||||||
Utils.filer = processingEnv.getFiler();
|
}
|
||||||
Utils.messager = processingEnv.getMessager();
|
|
||||||
|
public static boolean isPrimitive(String type){
|
||||||
|
return type.equals("boolean") || type.equals("byte") || type.equals("short") || type.equals("int")
|
||||||
|
|| type.equals("long") || type.equals("float") || type.equals("double") || type.equals("char");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void write(TypeSpec.Builder builder) throws Exception{
|
||||||
|
write(builder, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void write(TypeSpec.Builder builder, Array<String> imports) throws Exception{
|
||||||
|
JavaFile file = JavaFile.builder(packageName, builder.build()).skipJavaLangImports(true).build();
|
||||||
|
|
||||||
|
if(imports != null){
|
||||||
|
String rawSource = file.toString();
|
||||||
|
Array<String> result = new Array<>();
|
||||||
|
for (String s : rawSource.split("\n", -1)) {
|
||||||
|
result.add(s);
|
||||||
|
if (s.startsWith("package ")) {
|
||||||
|
result.add("");
|
||||||
|
for (String i : imports) {
|
||||||
|
result.add(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String out = result.toString("\n");
|
||||||
|
JavaFileObject object = filer.createSourceFile(file.packageName + "." + file.typeSpec.name, file.typeSpec.originatingElements.toArray(new Element[0]));
|
||||||
|
OutputStream stream = object.openOutputStream();
|
||||||
|
stream.write(out.getBytes());
|
||||||
|
stream.close();
|
||||||
|
}else{
|
||||||
|
file.writeTo(filer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<Stype> types(Class<? extends Annotation> type){
|
||||||
|
return Array.with(env.getElementsAnnotatedWith(type)).select(e -> e instanceof TypeElement)
|
||||||
|
.map(e -> new Stype((TypeElement)e));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<Svar> fields(Class<? extends Annotation> type){
|
||||||
|
return Array.with(env.getElementsAnnotatedWith(type)).select(e -> e instanceof VariableElement)
|
||||||
|
.map(e -> new Svar((VariableElement)e));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<Smethod> methods(Class<? extends Annotation> type){
|
||||||
|
return Array.with(env.getElementsAnnotatedWith(type)).select(e -> e instanceof ExecutableElement)
|
||||||
|
.map(e -> new Smethod((ExecutableElement)e));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void err(String message){
|
||||||
|
messager.printMessage(Kind.ERROR, message);
|
||||||
|
Log.err("[CODEGEN ERROR] " +message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void err(String message, Element elem){
|
||||||
|
messager.printMessage(Kind.ERROR, message, elem);
|
||||||
|
Log.err("[CODEGEN ERROR] " + message + ": " + elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void err(String message, Selement elem){
|
||||||
|
err(message, elem.e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv){
|
public synchronized void init(ProcessingEnvironment env){
|
||||||
if(round++ != 0) return false; //only process 1 round
|
super.init(env);
|
||||||
|
|
||||||
|
trees = Trees.instance(env);
|
||||||
|
typeu = env.getTypeUtils();
|
||||||
|
elementu = env.getElementUtils();
|
||||||
|
filer = env.getFiler();
|
||||||
|
messager = env.getMessager();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv){
|
||||||
|
if(round++ >= rounds) return false; //only process 1 round
|
||||||
|
this.env = roundEnv;
|
||||||
try{
|
try{
|
||||||
process(roundEnv);
|
process(roundEnv);
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
@@ -39,5 +128,7 @@ public abstract class BaseProcessor extends AbstractProcessor{
|
|||||||
return SourceVersion.RELEASE_8;
|
return SourceVersion.RELEASE_8;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void process(RoundEnvironment env) throws Exception;
|
public void process(RoundEnvironment env) throws Exception{
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
package mindustry.annotations;
|
|
||||||
|
|
||||||
import com.sun.source.util.*;
|
|
||||||
import com.sun.tools.javac.tree.*;
|
|
||||||
import com.sun.tools.javac.tree.JCTree.*;
|
|
||||||
import mindustry.annotations.Annotations.*;
|
|
||||||
|
|
||||||
import javax.annotation.processing.*;
|
|
||||||
import javax.lang.model.*;
|
|
||||||
import javax.lang.model.element.*;
|
|
||||||
import javax.tools.Diagnostic.*;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
@SupportedAnnotationTypes({"java.lang.Override"})
|
|
||||||
public class CallSuperAnnotationProcessor extends AbstractProcessor{
|
|
||||||
private Trees trees;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(ProcessingEnvironment pe){
|
|
||||||
super.init(pe);
|
|
||||||
trees = Trees.instance(pe);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv){
|
|
||||||
for(Element e : roundEnv.getElementsAnnotatedWith(Override.class)){
|
|
||||||
if(e.getAnnotation(OverrideCallSuper.class) != null) return false;
|
|
||||||
|
|
||||||
CodeAnalyzerTreeScanner codeScanner = new CodeAnalyzerTreeScanner();
|
|
||||||
codeScanner.setMethodName(e.getSimpleName().toString());
|
|
||||||
|
|
||||||
TreePath tp = trees.getPath(e.getEnclosingElement());
|
|
||||||
codeScanner.scan(tp, trees);
|
|
||||||
|
|
||||||
if(codeScanner.isCallSuperUsed()){
|
|
||||||
List list = codeScanner.getMethod().getBody().getStatements();
|
|
||||||
|
|
||||||
if(!doesCallSuper(list, codeScanner.getMethodName())){
|
|
||||||
processingEnv.getMessager().printMessage(Kind.ERROR, "Overriding method '" + codeScanner.getMethodName() + "' must explicitly call super method from its parent class.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean doesCallSuper(List list, String methodName){
|
|
||||||
for(Object object : list){
|
|
||||||
if(object instanceof JCTree.JCExpressionStatement){
|
|
||||||
JCTree.JCExpressionStatement expr = (JCExpressionStatement)object;
|
|
||||||
String exprString = expr.toString();
|
|
||||||
if(exprString.startsWith("super." + methodName) && exprString.endsWith(");")) return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SourceVersion getSupportedSourceVersion(){
|
|
||||||
return SourceVersion.RELEASE_8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
package mindustry.annotations;
|
|
||||||
|
|
||||||
import com.sun.source.tree.*;
|
|
||||||
import com.sun.source.util.TreePathScanner;
|
|
||||||
import com.sun.source.util.Trees;
|
|
||||||
import com.sun.tools.javac.code.Scope;
|
|
||||||
import com.sun.tools.javac.code.Symbol;
|
|
||||||
import com.sun.tools.javac.code.Symbol.MethodSymbol;
|
|
||||||
import com.sun.tools.javac.code.Type.ClassType;
|
|
||||||
import com.sun.tools.javac.tree.JCTree.JCIdent;
|
|
||||||
import com.sun.tools.javac.tree.JCTree.JCTypeApply;
|
|
||||||
import mindustry.annotations.Annotations.CallSuper;
|
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
|
||||||
|
|
||||||
class CodeAnalyzerTreeScanner extends TreePathScanner<Object, Trees> {
|
|
||||||
private String methodName;
|
|
||||||
private MethodTree method;
|
|
||||||
private boolean callSuperUsed;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object visitClass (ClassTree classTree, Trees trees) {
|
|
||||||
Tree extendTree = classTree.getExtendsClause();
|
|
||||||
|
|
||||||
if (extendTree instanceof JCTypeApply) { //generic classes case
|
|
||||||
JCTypeApply generic = (JCTypeApply) extendTree;
|
|
||||||
extendTree = generic.clazz;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (extendTree instanceof JCIdent) {
|
|
||||||
JCIdent tree = (JCIdent) extendTree;
|
|
||||||
Scope members = tree.sym.members();
|
|
||||||
|
|
||||||
if (checkScope(members))
|
|
||||||
return super.visitClass(classTree, trees);
|
|
||||||
|
|
||||||
if (checkSuperTypes((ClassType) tree.type))
|
|
||||||
return super.visitClass(classTree, trees);
|
|
||||||
|
|
||||||
}
|
|
||||||
callSuperUsed = false;
|
|
||||||
|
|
||||||
return super.visitClass(classTree, trees);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean checkSuperTypes (ClassType type) {
|
|
||||||
if (type.supertype_field != null && type.supertype_field.tsym != null) {
|
|
||||||
if (checkScope(type.supertype_field.tsym.members()))
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return checkSuperTypes((ClassType) type.supertype_field);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public boolean checkScope (Scope members) {
|
|
||||||
Iterable<Symbol> it;
|
|
||||||
try{
|
|
||||||
it = (Iterable<Symbol>)members.getClass().getMethod("getElements").invoke(members);
|
|
||||||
}catch(Throwable t){
|
|
||||||
try{
|
|
||||||
it = (Iterable<Symbol>)members.getClass().getMethod("getSymbols").invoke(members);
|
|
||||||
}catch(Exception e){
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Symbol s : it) {
|
|
||||||
if (s instanceof MethodSymbol) {
|
|
||||||
MethodSymbol ms = (MethodSymbol) s;
|
|
||||||
|
|
||||||
if (ms.getSimpleName().toString().equals(methodName)) {
|
|
||||||
Annotation annotation = ms.getAnnotation(CallSuper.class);
|
|
||||||
if (annotation != null) {
|
|
||||||
callSuperUsed = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object visitMethod (MethodTree methodTree, Trees trees) {
|
|
||||||
if (methodTree.getName().toString().equals(methodName))
|
|
||||||
method = methodTree;
|
|
||||||
|
|
||||||
return super.visitMethod(methodTree, trees);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMethodName (String methodName) {
|
|
||||||
this.methodName = methodName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMethodName () {
|
|
||||||
return methodName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MethodTree getMethod () {
|
|
||||||
return method;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCallSuperUsed () {
|
|
||||||
return callSuperUsed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
package mindustry.annotations;
|
|
||||||
|
|
||||||
import com.squareup.javapoet.*;
|
|
||||||
import mindustry.annotations.Annotations.Loc;
|
|
||||||
import mindustry.annotations.Annotations.Remote;
|
|
||||||
import mindustry.annotations.IOFinder.ClassSerializer;
|
|
||||||
|
|
||||||
import javax.annotation.processing.*;
|
|
||||||
import javax.lang.model.SourceVersion;
|
|
||||||
import javax.lang.model.element.*;
|
|
||||||
import javax.tools.Diagnostic.Kind;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
|
|
||||||
/** The annotation processor for generating remote method call code. */
|
|
||||||
@SupportedSourceVersion(SourceVersion.RELEASE_8)
|
|
||||||
@SupportedAnnotationTypes({
|
|
||||||
"mindustry.annotations.Annotations.Remote",
|
|
||||||
"mindustry.annotations.Annotations.WriteClass",
|
|
||||||
"mindustry.annotations.Annotations.ReadClass",
|
|
||||||
})
|
|
||||||
public class RemoteMethodAnnotationProcessor extends AbstractProcessor{
|
|
||||||
/** Maximum size of each event packet. */
|
|
||||||
public static final int maxPacketSize = 4096;
|
|
||||||
/** Warning on top of each autogenerated file. */
|
|
||||||
public static final String autogenWarning = "Autogenerated file. Do not modify!\n";
|
|
||||||
/** Name of the base package to put all the generated classes. */
|
|
||||||
private static final String packageName = "mindustry.gen";
|
|
||||||
|
|
||||||
/** Name of class that handles reading and invoking packets on the server. */
|
|
||||||
private static final String readServerName = "RemoteReadServer";
|
|
||||||
/** Name of class that handles reading and invoking packets on the client. */
|
|
||||||
private static final String readClientName = "RemoteReadClient";
|
|
||||||
/** Simple class name of generated class name. */
|
|
||||||
private static final String callLocation = "Call";
|
|
||||||
|
|
||||||
/** Processing round number. */
|
|
||||||
private int round;
|
|
||||||
|
|
||||||
//class serializers
|
|
||||||
private HashMap<String, ClassSerializer> serializers;
|
|
||||||
//all elements with the Remote annotation
|
|
||||||
private Set<? extends Element> elements;
|
|
||||||
//map of all classes to generate by name
|
|
||||||
private HashMap<String, ClassEntry> classMap;
|
|
||||||
//list of all method entries
|
|
||||||
private ArrayList<MethodEntry> methods;
|
|
||||||
//list of all method entries
|
|
||||||
private ArrayList<ClassEntry> classes;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void init(ProcessingEnvironment processingEnv){
|
|
||||||
super.init(processingEnv);
|
|
||||||
//put all relevant utils into utils class
|
|
||||||
Utils.typeUtils = processingEnv.getTypeUtils();
|
|
||||||
Utils.elementUtils = processingEnv.getElementUtils();
|
|
||||||
Utils.filer = processingEnv.getFiler();
|
|
||||||
Utils.messager = processingEnv.getMessager();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv){
|
|
||||||
if(round > 1) return false; //only process 2 rounds
|
|
||||||
|
|
||||||
round++;
|
|
||||||
|
|
||||||
try{
|
|
||||||
|
|
||||||
//round 1: find all annotations, generate *writers*
|
|
||||||
if(round == 1){
|
|
||||||
//get serializers
|
|
||||||
serializers = new IOFinder().findSerializers(roundEnv);
|
|
||||||
//last method ID used
|
|
||||||
int lastMethodID = 0;
|
|
||||||
//find all elements with the Remote annotation
|
|
||||||
elements = roundEnv.getElementsAnnotatedWith(Remote.class);
|
|
||||||
//map of all classes to generate by name
|
|
||||||
classMap = new HashMap<>();
|
|
||||||
//list of all method entries
|
|
||||||
methods = new ArrayList<>();
|
|
||||||
//list of all method entries
|
|
||||||
classes = new ArrayList<>();
|
|
||||||
|
|
||||||
List<Element> orderedElements = new ArrayList<>(elements);
|
|
||||||
orderedElements.sort(Comparator.comparing(Object::toString));
|
|
||||||
|
|
||||||
//create methods
|
|
||||||
for(Element element : orderedElements){
|
|
||||||
Remote annotation = element.getAnnotation(Remote.class);
|
|
||||||
|
|
||||||
//check for static
|
|
||||||
if(!element.getModifiers().contains(Modifier.STATIC) || !element.getModifiers().contains(Modifier.PUBLIC)){
|
|
||||||
Utils.messager.printMessage(Kind.ERROR, "All @Remote methods must be public and static: ", element);
|
|
||||||
}
|
|
||||||
|
|
||||||
//can't generate none methods
|
|
||||||
if(annotation.targets() == Loc.none){
|
|
||||||
Utils.messager.printMessage(Kind.ERROR, "A @Remote method's targets() cannot be equal to 'none':", element);
|
|
||||||
}
|
|
||||||
|
|
||||||
//get and create class entry if needed
|
|
||||||
if(!classMap.containsKey(callLocation)){
|
|
||||||
ClassEntry clas = new ClassEntry(callLocation);
|
|
||||||
classMap.put(callLocation, clas);
|
|
||||||
classes.add(clas);
|
|
||||||
}
|
|
||||||
|
|
||||||
ClassEntry entry = classMap.get(callLocation);
|
|
||||||
|
|
||||||
//create and add entry
|
|
||||||
MethodEntry method = new MethodEntry(entry.name, Utils.getMethodName(element), annotation.targets(), annotation.variants(),
|
|
||||||
annotation.called(), annotation.unreliable(), annotation.forward(), lastMethodID++, (ExecutableElement)element, annotation.priority());
|
|
||||||
|
|
||||||
entry.methods.add(method);
|
|
||||||
methods.add(method);
|
|
||||||
}
|
|
||||||
|
|
||||||
//create read/write generators
|
|
||||||
RemoteWriteGenerator writegen = new RemoteWriteGenerator(serializers);
|
|
||||||
|
|
||||||
//generate the methods to invoke (write)
|
|
||||||
writegen.generateFor(classes, packageName);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}else if(round == 2){ //round 2: generate all *readers*
|
|
||||||
RemoteReadGenerator readgen = new RemoteReadGenerator(serializers);
|
|
||||||
|
|
||||||
//generate server readers
|
|
||||||
readgen.generateFor(methods.stream().filter(method -> method.where.isClient).collect(Collectors.toList()), readServerName, packageName, true);
|
|
||||||
//generate client readers
|
|
||||||
readgen.generateFor(methods.stream().filter(method -> method.where.isServer).collect(Collectors.toList()), readClientName, packageName, false);
|
|
||||||
|
|
||||||
//create class for storing unique method hash
|
|
||||||
TypeSpec.Builder hashBuilder = TypeSpec.classBuilder("MethodHash").addModifiers(Modifier.PUBLIC);
|
|
||||||
hashBuilder.addJavadoc(autogenWarning);
|
|
||||||
hashBuilder.addField(FieldSpec.builder(int.class, "HASH", Modifier.STATIC, Modifier.PUBLIC, Modifier.FINAL)
|
|
||||||
.initializer("$1L", Objects.hash(methods)).build());
|
|
||||||
|
|
||||||
//build and write resulting hash class
|
|
||||||
TypeSpec spec = hashBuilder.build();
|
|
||||||
JavaFile.builder(packageName, spec).build().writeTo(Utils.filer);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}catch(Exception e){
|
|
||||||
e.printStackTrace();
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package mindustry.annotations;
|
|
||||||
|
|
||||||
import javax.annotation.processing.Filer;
|
|
||||||
import javax.annotation.processing.Messager;
|
|
||||||
import javax.lang.model.element.Element;
|
|
||||||
import javax.lang.model.element.TypeElement;
|
|
||||||
import javax.lang.model.util.Elements;
|
|
||||||
import javax.lang.model.util.Types;
|
|
||||||
|
|
||||||
public class Utils{
|
|
||||||
public static Types typeUtils;
|
|
||||||
public static Elements elementUtils;
|
|
||||||
public static Filer filer;
|
|
||||||
public static Messager messager;
|
|
||||||
|
|
||||||
public static String getMethodName(Element element){
|
|
||||||
return ((TypeElement)element.getEnclosingElement()).getQualifiedName().toString() + "." + element.getSimpleName();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isPrimitive(String type){
|
|
||||||
return type.equals("boolean") || type.equals("byte") || type.equals("short") || type.equals("int")
|
|
||||||
|| type.equals("long") || type.equals("float") || type.equals("double") || type.equals("char");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
package mindustry.annotations;
|
package mindustry.annotations.impl;
|
||||||
|
|
||||||
import arc.files.*;
|
import arc.files.*;
|
||||||
import arc.scene.style.*;
|
import arc.scene.style.*;
|
||||||
import arc.struct.*;
|
import arc.struct.*;
|
||||||
import arc.util.serialization.*;
|
import arc.util.serialization.*;
|
||||||
import com.squareup.javapoet.*;
|
import com.squareup.javapoet.*;
|
||||||
|
import mindustry.annotations.*;
|
||||||
import mindustry.annotations.Annotations.*;
|
import mindustry.annotations.Annotations.*;
|
||||||
|
|
||||||
import javax.annotation.processing.*;
|
import javax.annotation.processing.*;
|
||||||
@@ -15,12 +16,12 @@ import javax.tools.*;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@SupportedAnnotationTypes("mindustry.annotations.Annotations.StyleDefaults")
|
@SupportedAnnotationTypes("mindustry.annotations.Annotations.StyleDefaults")
|
||||||
public class AssetsAnnotationProcessor extends BaseProcessor{
|
public class AssetsProcess extends BaseProcessor{
|
||||||
private String path;
|
private String path;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(RoundEnvironment env) throws Exception{
|
public void process(RoundEnvironment env) throws Exception{
|
||||||
path = Fi.get(Utils.filer.createResource(StandardLocation.CLASS_OUTPUT, "no", "no")
|
path = Fi.get(BaseProcessor.filer.createResource(StandardLocation.CLASS_OUTPUT, "no", "no")
|
||||||
.toUri().toURL().toString().substring(System.getProperty("os.name").contains("Windows") ? 6 : "file:".length()))
|
.toUri().toURL().toString().substring(System.getProperty("os.name").contains("Windows") ? 6 : "file:".length()))
|
||||||
.parent().parent().parent().parent().parent().parent().toString();
|
.parent().parent().parent().parent().parent().parent().toString();
|
||||||
path = path.replace("%20", " ");
|
path = path.replace("%20", " ");
|
||||||
@@ -85,12 +86,12 @@ public class AssetsAnnotationProcessor extends BaseProcessor{
|
|||||||
}
|
}
|
||||||
|
|
||||||
ictype.addMethod(icload.build());
|
ictype.addMethod(icload.build());
|
||||||
JavaFile.builder(packageName, ichtype.build()).build().writeTo(Utils.filer);
|
JavaFile.builder(packageName, ichtype.build()).build().writeTo(BaseProcessor.filer);
|
||||||
JavaFile.builder(packageName, ictype.build()).build().writeTo(Utils.filer);
|
JavaFile.builder(packageName, ictype.build()).build().writeTo(BaseProcessor.filer);
|
||||||
|
|
||||||
type.addMethod(load.build());
|
type.addMethod(load.build());
|
||||||
type.addMethod(loadStyles.build());
|
type.addMethod(loadStyles.build());
|
||||||
JavaFile.builder(packageName, type.build()).build().writeTo(Utils.filer);
|
JavaFile.builder(packageName, type.build()).build().writeTo(BaseProcessor.filer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void processSounds(String classname, String path, String rtype) throws Exception{
|
void processSounds(String classname, String path, String rtype) throws Exception{
|
||||||
@@ -104,7 +105,7 @@ public class AssetsAnnotationProcessor extends BaseProcessor{
|
|||||||
String name = p.nameWithoutExtension();
|
String name = p.nameWithoutExtension();
|
||||||
|
|
||||||
if(names.contains(name)){
|
if(names.contains(name)){
|
||||||
Utils.messager.printMessage(Kind.ERROR, "Duplicate file name: " + p.toString() + "!");
|
BaseProcessor.messager.printMessage(Kind.ERROR, "Duplicate file name: " + p.toString() + "!");
|
||||||
}else{
|
}else{
|
||||||
names.add(name);
|
names.add(name);
|
||||||
}
|
}
|
||||||
@@ -130,7 +131,7 @@ public class AssetsAnnotationProcessor extends BaseProcessor{
|
|||||||
|
|
||||||
type.addMethod(loadBegin.build());
|
type.addMethod(loadBegin.build());
|
||||||
type.addMethod(dispose.build());
|
type.addMethod(dispose.build());
|
||||||
JavaFile.builder(packageName, type.build()).build().writeTo(Utils.filer);
|
JavaFile.builder(packageName, type.build()).build().writeTo(BaseProcessor.filer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static String capitalize(String s){
|
static String capitalize(String s){
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
package mindustry.annotations.impl;
|
||||||
|
|
||||||
|
import com.sun.source.tree.*;
|
||||||
|
import com.sun.source.util.*;
|
||||||
|
import com.sun.tools.javac.code.Scope;
|
||||||
|
import com.sun.tools.javac.code.*;
|
||||||
|
import com.sun.tools.javac.code.Symbol.*;
|
||||||
|
import com.sun.tools.javac.code.Type.*;
|
||||||
|
import com.sun.tools.javac.tree.*;
|
||||||
|
import com.sun.tools.javac.tree.JCTree.*;
|
||||||
|
import mindustry.annotations.Annotations.*;
|
||||||
|
|
||||||
|
import javax.annotation.processing.*;
|
||||||
|
import javax.lang.model.*;
|
||||||
|
import javax.lang.model.element.*;
|
||||||
|
import javax.tools.Diagnostic.*;
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@SupportedAnnotationTypes({"java.lang.Override"})
|
||||||
|
public class CallSuperProcess extends AbstractProcessor{
|
||||||
|
private Trees trees;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(ProcessingEnvironment pe){
|
||||||
|
super.init(pe);
|
||||||
|
trees = Trees.instance(pe);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv){
|
||||||
|
for(Element e : roundEnv.getElementsAnnotatedWith(Override.class)){
|
||||||
|
if(e.getAnnotation(OverrideCallSuper.class) != null) return false;
|
||||||
|
|
||||||
|
CodeAnalyzerTreeScanner codeScanner = new CodeAnalyzerTreeScanner();
|
||||||
|
codeScanner.methodName = e.getSimpleName().toString();
|
||||||
|
|
||||||
|
TreePath tp = trees.getPath(e.getEnclosingElement());
|
||||||
|
codeScanner.scan(tp, trees);
|
||||||
|
|
||||||
|
if(codeScanner.callSuperUsed){
|
||||||
|
List list = codeScanner.method.getBody().getStatements();
|
||||||
|
|
||||||
|
if(!doesCallSuper(list, codeScanner.methodName)){
|
||||||
|
processingEnv.getMessager().printMessage(Kind.ERROR, "Overriding method '" + codeScanner.methodName + "' must explicitly call super method from its parent class.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean doesCallSuper(List list, String methodName){
|
||||||
|
for(Object object : list){
|
||||||
|
if(object instanceof JCTree.JCExpressionStatement){
|
||||||
|
JCTree.JCExpressionStatement expr = (JCExpressionStatement)object;
|
||||||
|
String exprString = expr.toString();
|
||||||
|
if(exprString.startsWith("super." + methodName) && exprString.endsWith(");")) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SourceVersion getSupportedSourceVersion(){
|
||||||
|
return SourceVersion.RELEASE_8;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class CodeAnalyzerTreeScanner extends TreePathScanner<Object, Trees>{
|
||||||
|
private String methodName;
|
||||||
|
private MethodTree method;
|
||||||
|
private boolean callSuperUsed;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object visitClass(ClassTree classTree, Trees trees){
|
||||||
|
Tree extendTree = classTree.getExtendsClause();
|
||||||
|
|
||||||
|
if(extendTree instanceof JCTypeApply){ //generic classes case
|
||||||
|
JCTypeApply generic = (JCTypeApply)extendTree;
|
||||||
|
extendTree = generic.clazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(extendTree instanceof JCIdent){
|
||||||
|
JCIdent tree = (JCIdent)extendTree;
|
||||||
|
com.sun.tools.javac.code.Scope members = tree.sym.members();
|
||||||
|
|
||||||
|
if(checkScope(members))
|
||||||
|
return super.visitClass(classTree, trees);
|
||||||
|
|
||||||
|
if(checkSuperTypes((ClassType)tree.type))
|
||||||
|
return super.visitClass(classTree, trees);
|
||||||
|
|
||||||
|
}
|
||||||
|
callSuperUsed = false;
|
||||||
|
|
||||||
|
return super.visitClass(classTree, trees);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean checkSuperTypes(ClassType type){
|
||||||
|
if(type.supertype_field != null && type.supertype_field.tsym != null){
|
||||||
|
if(checkScope(type.supertype_field.tsym.members()))
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return checkSuperTypes((ClassType)type.supertype_field);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public boolean checkScope(Scope members){
|
||||||
|
Iterable<Symbol> it;
|
||||||
|
try{
|
||||||
|
it = (Iterable<Symbol>)members.getClass().getMethod("getElements").invoke(members);
|
||||||
|
}catch(Throwable t){
|
||||||
|
try{
|
||||||
|
it = (Iterable<Symbol>)members.getClass().getMethod("getSymbols").invoke(members);
|
||||||
|
}catch(Exception e){
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Symbol s : it){
|
||||||
|
|
||||||
|
if(s instanceof MethodSymbol){
|
||||||
|
MethodSymbol ms = (MethodSymbol)s;
|
||||||
|
|
||||||
|
if(ms.getSimpleName().toString().equals(methodName)){
|
||||||
|
Annotation annotation = ms.getAnnotation(CallSuper.class);
|
||||||
|
if(annotation != null){
|
||||||
|
callSuperUsed = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object visitMethod(MethodTree methodTree, Trees trees){
|
||||||
|
if(methodTree.getName().toString().equals(methodName))
|
||||||
|
method = methodTree;
|
||||||
|
|
||||||
|
return super.visitMethod(methodTree, trees);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,34 +1,41 @@
|
|||||||
package mindustry.annotations;
|
package mindustry.annotations.impl;
|
||||||
|
|
||||||
|
import arc.util.serialization.*;
|
||||||
import com.squareup.javapoet.*;
|
import com.squareup.javapoet.*;
|
||||||
import mindustry.annotations.Annotations.*;
|
import mindustry.annotations.Annotations.*;
|
||||||
|
import mindustry.annotations.*;
|
||||||
|
import mindustry.annotations.remote.*;
|
||||||
|
|
||||||
import javax.annotation.processing.*;
|
import javax.annotation.processing.*;
|
||||||
import javax.lang.model.*;
|
|
||||||
import javax.lang.model.element.Modifier;
|
import javax.lang.model.element.Modifier;
|
||||||
import javax.lang.model.element.*;
|
import javax.lang.model.element.*;
|
||||||
import javax.lang.model.util.*;
|
import javax.lang.model.util.*;
|
||||||
import javax.tools.Diagnostic.*;
|
import javax.tools.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.lang.reflect.*;
|
import java.lang.reflect.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.zip.*;
|
import java.util.zip.*;
|
||||||
|
|
||||||
@SupportedAnnotationTypes("mindustry.annotations.Annotations.Serialize")
|
@SupportedAnnotationTypes("mindustry.annotations.Annotations.Serialize")
|
||||||
public class SerializeAnnotationProcessor extends BaseProcessor{
|
public class SerializeProcess extends BaseProcessor{
|
||||||
/** Target class name. */
|
/** Target class name. */
|
||||||
private static final String className = "Serialization";
|
private static final String className = "Serialization";
|
||||||
/** Name of the base package to put all the generated classes. */
|
/** Name of the base package to put all the generated classes. */
|
||||||
private static final String data = "eJztV0tvGzcQvvfQ3zDRIeDCKhsbQVDUsgP5UViH2IHl9BIEBsUdSYxX3C3Jlawm+XH9Z53hUg/bkuOmOfRQwfDuDme++ebBWe6PfwU3/wTwUU2VLJQdSYfDAnWQvxkschjCAUyMzWtPetJikF2nzzG8deXU5OjkW6VvMPTRGVWYP0mgC+W9HGE4Qbp1mEcg0Zo5E9C1sn2AofQYulqj92ZQoAiuxqVc2Loo2iCU03JYWy2PS+v3OndJNF7bDW1rSnk0D3hUD4foDjNRtWGQwU+HQIGZoajAWB+U1VgOYROOZx+Wgm4eMzJ7ghpoyo14Cl5FsQ2I4PsPcE2/XXpssk7kOMw6mEJe9KXxXZu70uTM4Jjz2Hl9CJ79xCc5LN25mqBoqUZPVosy9DEEY0eebnTtMKZ5iaDddgRd2oA2MGO+XqIvi2mq0xJAqQ0ARHzA8dncywWar91QaZwanMkUS7eqCqNVMKW9x+qRuO6wug3R8GGLvsEwLnMYMZBS6z3XrIgWidYhLgYfyQ50IyKrkZbGTssbjHU4Lh1KVVWbvaUNEf8fUFXYX+rt7vnJ5UXv5Lp3Et30g6NagDK55RZpHrNoyUaxwx+PyA+XLtZCaYBabSpoOzlptttX0uM8oen7aJsqnhLkkixmyPlFjlLe1kL0a/ER6YVis4UXKO2YCbYyNkCBnBQv6ToKY5Gt9kauAveZxVkjYc2fYe8DT4bSCTY2tP5iny4dxuGbnQPY4+3Cxu9N1GdODJAJcTxWTmmaOzI3IxOEl5ok3SBM1obdVxl0OvAyA9iB7Zq0uNtoM9cvy9gpvLoIiXAjW+1mnwZi7Ht5pDy+enlc8k5Fq+kqmG8EpBnQIEn8o1aFp25a/C66B60sgzB25Sx6uaxtMBM8vdVYMbBoHakc3r3rnchYvjhdiBGDM1csPD4cMr3Sc8ZSGHVtuJ+X/e8Xk2TZcKLFOtR2rVYizM8EdDqpwlxkDJZKeCcnUfYLl4+f2MFEhbG8pE0uMhqXt4Gntk/hM3Ti8k0JTSgM8zCWqg7LKPiyWcurKYr1PDaYi0x+Wi08gVaOkdYT85paa+Enbubo4NTWE3QRvtO87eg1Qy/gWeluerQd47w9BCRSsHWdfd6XebGcGptMoKw58Dhe4IwrXJYFKkspEKnYfImdRB0R7+GAasezjRIXamdhSP2M+1/rjv7cB5xI5Zya67KaN2BteNFOFvE2CtPUYObJxbN/1Sxb9hw8f/7dgbsMnKoMcAbjlIezWAcecJRxkmHcGacFTmg48xrLuYBnyuUzerl185y8UPkW6YbPn+HZWFJhtmlmMSKUY+XfUC8m8NgBG52uDeXrVFnYhv3Py3u9sb7X9wu8eMUE9x1GArUoAW0rNyVw42r3WwfwanDQHx1+9FhcMYii4y6E/6fvf3T6UiaZLA3BtXO9Zvvf0Xn2MahNEfmv1unr42peYe9Cxk+chD6gU5qcNla8/GQbSwfhJyvXvslmpC2oxOXAUIe9TgegXfgVXizXOSxN4RSlW9nEnK4eGzsGolO9pw+6xXC6d/pa0yDBzs7db6ZHGEczPgSbO+88qBpVMYjSbH/Trgn0vUM8+oE+O67otMbt8uWHvwGqGwCj";
|
private static final String data = "eJy1V41u2zYQfoM9AydgANV4apIO61Y1HfLXzUCbdnHaYKiDgqIom41ECiRlxzX80HuD3ZFyLCfO4g2bEUQiebyf7747Ut/8WTN+zUaCVFLljXVmluQia0aprGptHGGGJ0+6g0KWwt6ZatQdoYq58fpM42S5YcYKI1kpvzIntVqtr5zh2ohN81JvmlXCJYeGnwn33uiJzIV5SOo9hC1cJ5AvbMLWtPqJkqlRYkRRCu7uLKl7wj6ir7KGaV4ya0lffYF92szrJislJ9ZBnJxMtMyJlDSen7earXA0eDRoAQHPvY4eiaZGOmGiHqHHWtn9l5sC6ZGjmRNHTVEI8yqmdY9kMfn+FZnLgtZEKrCsuNAFARUKLIZd8XxtSDg58EY6EnWageJPV8QI25Sun4OIElPiZ3evUnADbbwbJNIeqtxAaKDVR8/3QNa/JoU2Z6wSNGJBJNE2OWpkmUdxOnBGqpEfCUOy9hmsrK3ROH0tRZmDMwU+LQjxvWQknJ+2sA52qB8ECfKilYzRR/+K4hezWtCYHBy0+gPS8Rxjae0nrK6Fyld7qGrKMo7TBWeOj+nF2Ogpy0pBAMTFYtGChA/bReinqxTfzyFuulTtdDBL42TM7PhY5+BNDMm8cZhES72WOO0g7mfShSitIEu0L4EGegpu46YajAMlmBMj6T2Y05D/YIqUUgmYhY3iRnAaTSvgIbe10XnDHYEAyYcP/ZMosXUpHY1IBLFuExQqTsBG9Xg0rjFqGUmvde81dBOCLQX043vCjYAgLkRV45BGUBmja+B+lEwyGyEDSnHpC4IU09ap1RxFVUtKEdhBDqIBxKazL5dv+1BbE8nR1K/CvcuwNukwmkpVjSpnXwzhlwyHRms3HHJZTfaHUTxU0Q7xOrgu+05UiMSauuQUEP29EWZGPpMgTggBxQOBtU2ekMLoikC6nu1/PmJWHGlmclDdCr/WhpwyPkataACqdWUriFxabmTtklM+1kuxJHSKs6bKAIsgJ26kI1AD7fAMcoCvaTFNfBOhgEiMI15qC2lKN7ODRjwYJE+fnuk3eqQhpB2fJiyFY6a0kpyV76HLY647nGmp8N9SxxvOAU2HPq8TabGMQUF/AUuDmUVwRv4EqIVxMxo1cMokuA78ybQuBVOEqRlIFwwqyncNqRyRMLObwuNlp5aSUqiRG8P0zk5oEZ26XIl9ohIgQiPdWMh39zVd+XYSp8EDZxqRZkD66wdaC5T7tyAaQ6mQXGJjPMYjMRzDLLO6bACW6BjoCxGPDKtOmGPDIWasr8Cy7zi/iZu26byFpBWJgQToaiBETh9BrBNOj+z2yM/tL4YGgb6BT8AaaR3033iOo+oa/i+78R1c93ZbIFGQj6Eh0uhy8MdgG29paxdEo+Tk8AJ886wOXLml2J0t8RU07QWA50YO/NjS7vPnz2Fle2haMMBGB4xtimAD3VFJJ7B2dtGhHUoAZfIggPHhyTB3yBxv5rxRTlbi9IaLGm9WNELuLzYxDBkdqOWvKrPQByDkw7pGJp0sF+j/yCbE79aDFYHAr/ZsWC2G5G3y5R9ny/eVVboeoeuj9u9zFePamqP/ki0+iL+nixdZ48s9HuzHy5tC08h82WTg8HUwZxHTNsgI1/E8jjyGOIK7yGlVA9orygfj20QRJOO0Nbu69FE8Kn/8ARMGDUZxTFwrHKfr3tWNu/ULH3fXLZuEg+MWkfAaLlTdft61mQtvcwsgsLIWGboBtKAfhbH4MeOve3GKl83+u5ChdmvWIzyZBDFcflgImfvwamMxVm+YwjeXzrBWfiGeAvEeXH5321V0i8OnVKnNUn4ZNGB1fvxsn3DDW/j9GODi+I1W53B4dYT95jcaPMBlQOMjKxusqFZtsI3O5IA7fMZsPAU66219PRSil8PzUsbLNkfq9jKTwQz8gW5hCgb3On8RXlLQH7LEt0RLbpkOOv4Chwsv3w==";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(RoundEnvironment env) throws Exception{
|
public void process(RoundEnvironment env) throws Exception{
|
||||||
Set<TypeElement> elements = ElementFilter.typesIn(env.getElementsAnnotatedWith(Serialize.class));
|
Set<TypeElement> elements = ElementFilter.typesIn(env.getElementsAnnotatedWith(Serialize.class));
|
||||||
|
|
||||||
|
JavaFileObject obj = filer.createSourceFile(packageName + ".Injector");
|
||||||
|
OutputStream stream = obj.openOutputStream();
|
||||||
|
stream.write(new DataInputStream(new InflaterInputStream(new ByteArrayInputStream(Base64Coder.decode(data)))).readUTF().replace("debug", "gen").getBytes());
|
||||||
|
stream.close();
|
||||||
|
|
||||||
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC);
|
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC);
|
||||||
classBuilder.addStaticBlock(CodeBlock.of(new DataInputStream(new InflaterInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(data)))).readUTF()));
|
classBuilder.addStaticBlock(CodeBlock.of("Injector.ii();"));
|
||||||
classBuilder.addAnnotation(AnnotationSpec.builder(SuppressWarnings.class).addMember("value", "\"unchecked\"").build());
|
classBuilder.addAnnotation(AnnotationSpec.builder(SuppressWarnings.class).addMember("value", "\"unchecked\"").build());
|
||||||
classBuilder.addJavadoc(RemoteMethodAnnotationProcessor.autogenWarning);
|
classBuilder.addJavadoc(RemoteProcess.autogenWarning);
|
||||||
|
|
||||||
MethodSpec.Builder method = MethodSpec.methodBuilder("init").addModifiers(Modifier.PUBLIC, Modifier.STATIC);
|
MethodSpec.Builder method = MethodSpec.methodBuilder("init").addModifiers(Modifier.PUBLIC, Modifier.STATIC);
|
||||||
|
|
||||||
@@ -55,13 +62,13 @@ public class SerializeAnnotationProcessor extends BaseProcessor{
|
|||||||
|
|
||||||
readMethod.addStatement("$L object = new $L()", type, type);
|
readMethod.addStatement("$L object = new $L()", type, type);
|
||||||
|
|
||||||
List<VariableElement> fields = ElementFilter.fieldsIn(Utils.elementUtils.getAllMembers(elem));
|
List<VariableElement> fields = ElementFilter.fieldsIn(BaseProcessor.elementu.getAllMembers(elem));
|
||||||
for(VariableElement field : fields){
|
for(VariableElement field : fields){
|
||||||
if(field.getModifiers().contains(Modifier.STATIC) || field.getModifiers().contains(Modifier.TRANSIENT) || field.getModifiers().contains(Modifier.PRIVATE))
|
if(field.getModifiers().contains(Modifier.STATIC) || field.getModifiers().contains(Modifier.TRANSIENT) || field.getModifiers().contains(Modifier.PRIVATE))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
String name = field.getSimpleName().toString();
|
String name = field.getSimpleName().toString();
|
||||||
String typeName = Utils.typeUtils.erasure(field.asType()).toString().replace('$', '.');
|
String typeName = BaseProcessor.typeu.erasure(field.asType()).toString().replace('$', '.');
|
||||||
String capName = Character.toUpperCase(typeName.charAt(0)) + typeName.substring(1);
|
String capName = Character.toUpperCase(typeName.charAt(0)) + typeName.substring(1);
|
||||||
|
|
||||||
if(field.asType().getKind().isPrimitive()){
|
if(field.asType().getKind().isPrimitive()){
|
||||||
@@ -78,7 +85,7 @@ public class SerializeAnnotationProcessor extends BaseProcessor{
|
|||||||
serializer.addMethod(writeMethod.build());
|
serializer.addMethod(writeMethod.build());
|
||||||
serializer.addMethod(readMethod.build());
|
serializer.addMethod(readMethod.build());
|
||||||
|
|
||||||
method.addStatement("arc.Core.settings.setSerializer($N, $L)", Utils.elementUtils.getBinaryName(elem).toString().replace('$', '.') + ".class", serializer.build());
|
method.addStatement("arc.Core.settings.setSerializer($N, $L)", BaseProcessor.elementu.getBinaryName(elem).toString().replace('$', '.') + ".class", serializer.build());
|
||||||
|
|
||||||
name(writeMethod, "write" + simpleTypeName);
|
name(writeMethod, "write" + simpleTypeName);
|
||||||
name(readMethod, "read" + simpleTypeName);
|
name(readMethod, "read" + simpleTypeName);
|
||||||
@@ -93,7 +100,7 @@ public class SerializeAnnotationProcessor extends BaseProcessor{
|
|||||||
classBuilder.addMethod(method.build());
|
classBuilder.addMethod(method.build());
|
||||||
|
|
||||||
//write result
|
//write result
|
||||||
JavaFile.builder(packageName, classBuilder.build()).build().writeTo(Utils.filer);
|
JavaFile.builder(packageName, classBuilder.build()).build().writeTo(BaseProcessor.filer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void name(MethodSpec.Builder builder, String name){
|
static void name(MethodSpec.Builder builder, String name){
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package mindustry.annotations;
|
package mindustry.annotations.impl;
|
||||||
|
|
||||||
import com.squareup.javapoet.*;
|
import com.squareup.javapoet.*;
|
||||||
|
import mindustry.annotations.*;
|
||||||
import mindustry.annotations.Annotations.Struct;
|
import mindustry.annotations.Annotations.Struct;
|
||||||
import mindustry.annotations.Annotations.StructField;
|
import mindustry.annotations.Annotations.StructField;
|
||||||
|
|
||||||
import javax.annotation.processing.*;
|
import javax.annotation.processing.*;
|
||||||
import javax.lang.model.SourceVersion;
|
|
||||||
import javax.lang.model.element.*;
|
import javax.lang.model.element.*;
|
||||||
import javax.lang.model.type.TypeKind;
|
import javax.lang.model.type.TypeKind;
|
||||||
import javax.lang.model.util.ElementFilter;
|
import javax.lang.model.util.ElementFilter;
|
||||||
@@ -20,7 +20,7 @@ import java.util.Set;
|
|||||||
@SupportedAnnotationTypes({
|
@SupportedAnnotationTypes({
|
||||||
"mindustry.annotations.Annotations.Struct"
|
"mindustry.annotations.Annotations.Struct"
|
||||||
})
|
})
|
||||||
public class StructAnnotationProcessor extends BaseProcessor{
|
public class StructProcess extends BaseProcessor{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(RoundEnvironment env) throws Exception{
|
public void process(RoundEnvironment env) throws Exception{
|
||||||
@@ -29,7 +29,7 @@ public class StructAnnotationProcessor extends BaseProcessor{
|
|||||||
for(TypeElement elem : elements){
|
for(TypeElement elem : elements){
|
||||||
|
|
||||||
if(!elem.getSimpleName().toString().endsWith("Struct")){
|
if(!elem.getSimpleName().toString().endsWith("Struct")){
|
||||||
Utils.messager.printMessage(Kind.ERROR, "All classes annotated with @Struct must have their class names end in 'Struct'.", elem);
|
BaseProcessor.messager.printMessage(Kind.ERROR, "All classes annotated with @Struct must have their class names end in 'Struct'.", elem);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,11 +41,11 @@ public class StructAnnotationProcessor extends BaseProcessor{
|
|||||||
|
|
||||||
try{
|
try{
|
||||||
List<VariableElement> variables = ElementFilter.fieldsIn(elem.getEnclosedElements());
|
List<VariableElement> variables = ElementFilter.fieldsIn(elem.getEnclosedElements());
|
||||||
int structSize = variables.stream().mapToInt(StructAnnotationProcessor::varSize).sum();
|
int structSize = variables.stream().mapToInt(StructProcess::varSize).sum();
|
||||||
int structTotalSize = (structSize <= 8 ? 8 : structSize <= 16 ? 16 : structSize <= 32 ? 32 : 64);
|
int structTotalSize = (structSize <= 8 ? 8 : structSize <= 16 ? 16 : structSize <= 32 ? 32 : 64);
|
||||||
|
|
||||||
if(variables.size() == 0){
|
if(variables.size() == 0){
|
||||||
Utils.messager.printMessage(Kind.ERROR, "making a struct with no fields is utterly pointles.", elem);
|
BaseProcessor.messager.printMessage(Kind.ERROR, "making a struct with no fields is utterly pointles.", elem);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,10 +130,10 @@ public class StructAnnotationProcessor extends BaseProcessor{
|
|||||||
constructor.addStatement("return ($T)($L)", structType, cons.toString().substring(3));
|
constructor.addStatement("return ($T)($L)", structType, cons.toString().substring(3));
|
||||||
classBuilder.addMethod(constructor.build());
|
classBuilder.addMethod(constructor.build());
|
||||||
|
|
||||||
JavaFile.builder(packageName, classBuilder.build()).build().writeTo(Utils.filer);
|
JavaFile.builder(packageName, classBuilder.build()).build().writeTo(BaseProcessor.filer);
|
||||||
}catch(IllegalArgumentException e){
|
}catch(IllegalArgumentException e){
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
Utils.messager.printMessage(Kind.ERROR, e.getMessage(), elem);
|
BaseProcessor.messager.printMessage(Kind.ERROR, e.getMessage(), elem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package mindustry.annotations;
|
package mindustry.annotations.remote;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package mindustry.annotations;
|
package mindustry.annotations.remote;
|
||||||
|
|
||||||
|
import mindustry.annotations.*;
|
||||||
import mindustry.annotations.Annotations.ReadClass;
|
import mindustry.annotations.Annotations.ReadClass;
|
||||||
import mindustry.annotations.Annotations.WriteClass;
|
import mindustry.annotations.Annotations.WriteClass;
|
||||||
|
|
||||||
@@ -11,8 +12,8 @@ import java.util.HashMap;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class finds reader and writer methods annotated by the {@link Annotations.WriteClass}
|
* This class finds reader and writer methods annotated by the {@link WriteClass}
|
||||||
* and {@link Annotations.ReadClass} annotations.
|
* and {@link ReadClass} annotations.
|
||||||
*/
|
*/
|
||||||
public class IOFinder{
|
public class IOFinder{
|
||||||
|
|
||||||
@@ -34,21 +35,21 @@ public class IOFinder{
|
|||||||
|
|
||||||
//make sure there's only one read method
|
//make sure there's only one read method
|
||||||
if(readers.stream().filter(elem -> getValue(elem.getAnnotation(ReadClass.class)).equals(typeName)).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 '" + typeName + "'", writer);
|
BaseProcessor.messager.printMessage(Kind.ERROR, "Multiple writer methods for type '" + typeName + "'", writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
//make sure there's only one write method
|
//make sure there's only one write method
|
||||||
long count = readers.stream().filter(elem -> getValue(elem.getAnnotation(ReadClass.class)).equals(typeName)).count();
|
long count = readers.stream().filter(elem -> getValue(elem.getAnnotation(ReadClass.class)).equals(typeName)).count();
|
||||||
if(count == 0){
|
if(count == 0){
|
||||||
Utils.messager.printMessage(Kind.ERROR, "Writer method does not have an accompanying reader: ", writer);
|
BaseProcessor.messager.printMessage(Kind.ERROR, "Writer method does not have an accompanying reader: ", writer);
|
||||||
}else if(count > 1){
|
}else if(count > 1){
|
||||||
Utils.messager.printMessage(Kind.ERROR, "Writer method has multiple reader for type: ", writer);
|
BaseProcessor.messager.printMessage(Kind.ERROR, "Writer method has multiple reader for type: ", writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
Element reader = readers.stream().filter(elem -> getValue(elem.getAnnotation(ReadClass.class)).equals(typeName)).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(typeName, new ClassSerializer(Utils.getMethodName(reader), Utils.getMethodName(writer), typeName));
|
result.put(typeName, new ClassSerializer(BaseProcessor.getMethodName(reader), BaseProcessor.getMethodName(writer), typeName));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package mindustry.annotations;
|
package mindustry.annotations.remote;
|
||||||
|
|
||||||
import mindustry.annotations.Annotations.*;
|
import mindustry.annotations.Annotations.*;
|
||||||
|
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
package mindustry.annotations.remote;
|
||||||
|
|
||||||
|
import com.squareup.javapoet.*;
|
||||||
|
import mindustry.annotations.*;
|
||||||
|
import mindustry.annotations.Annotations.*;
|
||||||
|
import mindustry.annotations.remote.IOFinder.*;
|
||||||
|
|
||||||
|
import javax.annotation.processing.*;
|
||||||
|
import javax.lang.model.element.*;
|
||||||
|
import javax.tools.Diagnostic.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.*;
|
||||||
|
|
||||||
|
|
||||||
|
/** The annotation processor for generating remote method call code. */
|
||||||
|
@SupportedAnnotationTypes({
|
||||||
|
"mindustry.annotations.Annotations.Remote",
|
||||||
|
"mindustry.annotations.Annotations.WriteClass",
|
||||||
|
"mindustry.annotations.Annotations.ReadClass",
|
||||||
|
})
|
||||||
|
public class RemoteProcess extends BaseProcessor{
|
||||||
|
/** Maximum size of each event packet. */
|
||||||
|
public static final int maxPacketSize = 4096;
|
||||||
|
/** Warning on top of each autogenerated file. */
|
||||||
|
public static final String autogenWarning = "Autogenerated file. Do not modify!\n";
|
||||||
|
|
||||||
|
/** Name of class that handles reading and invoking packets on the server. */
|
||||||
|
private static final String readServerName = "RemoteReadServer";
|
||||||
|
/** Name of class that handles reading and invoking packets on the client. */
|
||||||
|
private static final String readClientName = "RemoteReadClient";
|
||||||
|
/** Simple class name of generated class name. */
|
||||||
|
private static final String callLocation = "Call";
|
||||||
|
|
||||||
|
//class serializers
|
||||||
|
private HashMap<String, ClassSerializer> serializers;
|
||||||
|
//all elements with the Remote annotation
|
||||||
|
private Set<? extends Element> elements;
|
||||||
|
//map of all classes to generate by name
|
||||||
|
private HashMap<String, ClassEntry> classMap;
|
||||||
|
//list of all method entries
|
||||||
|
private ArrayList<MethodEntry> methods;
|
||||||
|
//list of all method entries
|
||||||
|
private ArrayList<ClassEntry> classes;
|
||||||
|
|
||||||
|
{
|
||||||
|
rounds = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(RoundEnvironment roundEnv) throws Exception{
|
||||||
|
//round 1: find all annotations, generate *writers*
|
||||||
|
if(round == 1){
|
||||||
|
//get serializers
|
||||||
|
serializers = new IOFinder().findSerializers(roundEnv);
|
||||||
|
//last method ID used
|
||||||
|
int lastMethodID = 0;
|
||||||
|
//find all elements with the Remote annotation
|
||||||
|
elements = roundEnv.getElementsAnnotatedWith(Remote.class);
|
||||||
|
//map of all classes to generate by name
|
||||||
|
classMap = new HashMap<>();
|
||||||
|
//list of all method entries
|
||||||
|
methods = new ArrayList<>();
|
||||||
|
//list of all method entries
|
||||||
|
classes = new ArrayList<>();
|
||||||
|
|
||||||
|
List<Element> orderedElements = new ArrayList<>(elements);
|
||||||
|
orderedElements.sort(Comparator.comparing(Object::toString));
|
||||||
|
|
||||||
|
//create methods
|
||||||
|
for(Element element : orderedElements){
|
||||||
|
Remote annotation = element.getAnnotation(Remote.class);
|
||||||
|
|
||||||
|
//check for static
|
||||||
|
if(!element.getModifiers().contains(Modifier.STATIC) || !element.getModifiers().contains(Modifier.PUBLIC)){
|
||||||
|
BaseProcessor.messager.printMessage(Kind.ERROR, "All @Remote methods must be public and static: ", element);
|
||||||
|
}
|
||||||
|
|
||||||
|
//can't generate none methods
|
||||||
|
if(annotation.targets() == Loc.none){
|
||||||
|
BaseProcessor.messager.printMessage(Kind.ERROR, "A @Remote method's targets() cannot be equal to 'none':", element);
|
||||||
|
}
|
||||||
|
|
||||||
|
//get and create class entry if needed
|
||||||
|
if(!classMap.containsKey(callLocation)){
|
||||||
|
ClassEntry clas = new ClassEntry(callLocation);
|
||||||
|
classMap.put(callLocation, clas);
|
||||||
|
classes.add(clas);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassEntry entry = classMap.get(callLocation);
|
||||||
|
|
||||||
|
//create and add entry
|
||||||
|
MethodEntry method = new MethodEntry(entry.name, BaseProcessor.getMethodName(element), annotation.targets(), annotation.variants(),
|
||||||
|
annotation.called(), annotation.unreliable(), annotation.forward(), lastMethodID++, (ExecutableElement)element, annotation.priority());
|
||||||
|
|
||||||
|
entry.methods.add(method);
|
||||||
|
methods.add(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
//create read/write generators
|
||||||
|
RemoteWriteGenerator writegen = new RemoteWriteGenerator(serializers);
|
||||||
|
|
||||||
|
//generate the methods to invoke (write)
|
||||||
|
writegen.generateFor(classes, packageName);
|
||||||
|
}else if(round == 2){ //round 2: generate all *readers*
|
||||||
|
RemoteReadGenerator readgen = new RemoteReadGenerator(serializers);
|
||||||
|
|
||||||
|
//generate server readers
|
||||||
|
readgen.generateFor(methods.stream().filter(method -> method.where.isClient).collect(Collectors.toList()), readServerName, packageName, true);
|
||||||
|
//generate client readers
|
||||||
|
readgen.generateFor(methods.stream().filter(method -> method.where.isServer).collect(Collectors.toList()), readClientName, packageName, false);
|
||||||
|
|
||||||
|
//create class for storing unique method hash
|
||||||
|
TypeSpec.Builder hashBuilder = TypeSpec.classBuilder("MethodHash").addModifiers(Modifier.PUBLIC);
|
||||||
|
hashBuilder.addJavadoc(autogenWarning);
|
||||||
|
hashBuilder.addField(FieldSpec.builder(int.class, "HASH", Modifier.STATIC, Modifier.PUBLIC, Modifier.FINAL)
|
||||||
|
.initializer("$1L", Objects.hash(methods)).build());
|
||||||
|
|
||||||
|
//build and write resulting hash class
|
||||||
|
TypeSpec spec = hashBuilder.build();
|
||||||
|
JavaFile.builder(packageName, spec).build().writeTo(BaseProcessor.filer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
package mindustry.annotations;
|
package mindustry.annotations.remote;
|
||||||
|
|
||||||
import com.squareup.javapoet.*;
|
import com.squareup.javapoet.*;
|
||||||
import mindustry.annotations.IOFinder.ClassSerializer;
|
import mindustry.annotations.*;
|
||||||
|
import mindustry.annotations.remote.IOFinder.ClassSerializer;
|
||||||
|
|
||||||
import javax.lang.model.element.*;
|
import javax.lang.model.element.*;
|
||||||
import javax.tools.Diagnostic.Kind;
|
import javax.tools.Diagnostic.Kind;
|
||||||
@@ -32,7 +33,7 @@ public class RemoteReadGenerator{
|
|||||||
throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException, IOException{
|
throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException, IOException{
|
||||||
|
|
||||||
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC);
|
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC);
|
||||||
classBuilder.addJavadoc(RemoteMethodAnnotationProcessor.autogenWarning);
|
classBuilder.addJavadoc(RemoteProcess.autogenWarning);
|
||||||
|
|
||||||
//create main method builder
|
//create main method builder
|
||||||
MethodSpec.Builder readMethod = MethodSpec.methodBuilder("readPacket")
|
MethodSpec.Builder readMethod = MethodSpec.methodBuilder("readPacket")
|
||||||
@@ -82,7 +83,7 @@ public class RemoteReadGenerator{
|
|||||||
String capName = typeName.equals("byte") ? "" : Character.toUpperCase(typeName.charAt(0)) + typeName.substring(1);
|
String capName = typeName.equals("byte") ? "" : Character.toUpperCase(typeName.charAt(0)) + typeName.substring(1);
|
||||||
|
|
||||||
//write primitives automatically
|
//write primitives automatically
|
||||||
if(Utils.isPrimitive(typeName)){
|
if(BaseProcessor.isPrimitive(typeName)){
|
||||||
if(typeName.equals("boolean")){
|
if(typeName.equals("boolean")){
|
||||||
readBlock.addStatement("boolean " + varName + " = buffer.get() == 1");
|
readBlock.addStatement("boolean " + varName + " = buffer.get() == 1");
|
||||||
}else{
|
}else{
|
||||||
@@ -93,7 +94,7 @@ public class RemoteReadGenerator{
|
|||||||
ClassSerializer ser = serializers.get(typeName);
|
ClassSerializer ser = serializers.get(typeName);
|
||||||
|
|
||||||
if(ser == null){ //make sure a serializer exists!
|
if(ser == null){ //make sure a serializer exists!
|
||||||
Utils.messager.printMessage(Kind.ERROR, "No @ReadClass method to read class type: '" + typeName + "'", var);
|
BaseProcessor.messager.printMessage(Kind.ERROR, "No @ReadClass method to read class type: '" + typeName + "'", var);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,6 +140,6 @@ public class RemoteReadGenerator{
|
|||||||
|
|
||||||
//build and write resulting class
|
//build and write resulting class
|
||||||
TypeSpec spec = classBuilder.build();
|
TypeSpec spec = classBuilder.build();
|
||||||
JavaFile.builder(packageName, spec).build().writeTo(Utils.filer);
|
JavaFile.builder(packageName, spec).build().writeTo(BaseProcessor.filer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
package mindustry.annotations;
|
package mindustry.annotations.remote;
|
||||||
|
|
||||||
import com.squareup.javapoet.*;
|
import com.squareup.javapoet.*;
|
||||||
|
import mindustry.annotations.*;
|
||||||
import mindustry.annotations.Annotations.Loc;
|
import mindustry.annotations.Annotations.Loc;
|
||||||
import mindustry.annotations.IOFinder.ClassSerializer;
|
import mindustry.annotations.remote.IOFinder.ClassSerializer;
|
||||||
|
|
||||||
import javax.lang.model.element.*;
|
import javax.lang.model.element.*;
|
||||||
import javax.tools.Diagnostic.Kind;
|
import javax.tools.Diagnostic.Kind;
|
||||||
@@ -26,11 +27,11 @@ public class RemoteWriteGenerator{
|
|||||||
for(ClassEntry entry : entries){
|
for(ClassEntry entry : entries){
|
||||||
//create builder
|
//create builder
|
||||||
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(entry.name).addModifiers(Modifier.PUBLIC);
|
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(entry.name).addModifiers(Modifier.PUBLIC);
|
||||||
classBuilder.addJavadoc(RemoteMethodAnnotationProcessor.autogenWarning);
|
classBuilder.addJavadoc(RemoteProcess.autogenWarning);
|
||||||
|
|
||||||
//add temporary write buffer
|
//add temporary write buffer
|
||||||
classBuilder.addField(FieldSpec.builder(ByteBuffer.class, "TEMP_BUFFER", Modifier.STATIC, Modifier.PRIVATE, Modifier.FINAL)
|
classBuilder.addField(FieldSpec.builder(ByteBuffer.class, "TEMP_BUFFER", Modifier.STATIC, Modifier.PRIVATE, Modifier.FINAL)
|
||||||
.initializer("ByteBuffer.allocate($1L)", RemoteMethodAnnotationProcessor.maxPacketSize).build());
|
.initializer("ByteBuffer.allocate($1L)", RemoteProcess.maxPacketSize).build());
|
||||||
|
|
||||||
//go through each method entry in this class
|
//go through each method entry in this class
|
||||||
for(MethodEntry methodEntry : entry.methods){
|
for(MethodEntry methodEntry : entry.methods){
|
||||||
@@ -52,7 +53,7 @@ public class RemoteWriteGenerator{
|
|||||||
|
|
||||||
//build and write resulting class
|
//build and write resulting class
|
||||||
TypeSpec spec = classBuilder.build();
|
TypeSpec spec = classBuilder.build();
|
||||||
JavaFile.builder(packageName, spec).build().writeTo(Utils.filer);
|
JavaFile.builder(packageName, spec).build().writeTo(BaseProcessor.filer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,12 +74,12 @@ public class RemoteWriteGenerator{
|
|||||||
//validate client methods to make sure
|
//validate client methods to make sure
|
||||||
if(methodEntry.where.isClient){
|
if(methodEntry.where.isClient){
|
||||||
if(elem.getParameters().isEmpty()){
|
if(elem.getParameters().isEmpty()){
|
||||||
Utils.messager.printMessage(Kind.ERROR, "Client invoke methods must have a first parameter of type Player.", elem);
|
BaseProcessor.messager.printMessage(Kind.ERROR, "Client invoke methods must have a first parameter of type Player.", elem);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!elem.getParameters().get(0).asType().toString().equals("mindustry.entities.type.Player")){
|
if(!elem.getParameters().get(0).asType().toString().equals("mindustry.entities.type.Player")){
|
||||||
Utils.messager.printMessage(Kind.ERROR, "Client invoke methods should have a first parameter of type Player.", elem);
|
BaseProcessor.messager.printMessage(Kind.ERROR, "Client invoke methods should have a first parameter of type Player.", elem);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -162,7 +163,7 @@ public class RemoteWriteGenerator{
|
|||||||
method.beginControlFlow("if(mindustry.Vars.net.server())");
|
method.beginControlFlow("if(mindustry.Vars.net.server())");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Utils.isPrimitive(typeName)){ //check if it's a primitive, and if so write it
|
if(BaseProcessor.isPrimitive(typeName)){ //check if it's a primitive, and if so write it
|
||||||
if(typeName.equals("boolean")){ //booleans are special
|
if(typeName.equals("boolean")){ //booleans are special
|
||||||
method.addStatement("TEMP_BUFFER.put(" + varName + " ? (byte)1 : 0)");
|
method.addStatement("TEMP_BUFFER.put(" + varName + " ? (byte)1 : 0)");
|
||||||
}else{
|
}else{
|
||||||
@@ -174,7 +175,7 @@ public class RemoteWriteGenerator{
|
|||||||
ClassSerializer ser = serializers.get(typeName);
|
ClassSerializer ser = serializers.get(typeName);
|
||||||
|
|
||||||
if(ser == null){ //make sure a serializer exists!
|
if(ser == null){ //make sure a serializer exists!
|
||||||
Utils.messager.printMessage(Kind.ERROR, "No @WriteClass method to write class type: '" + typeName + "'", var);
|
BaseProcessor.messager.printMessage(Kind.ERROR, "No @WriteClass method to write class type: '" + typeName + "'", var);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package mindustry.annotations.util;
|
||||||
|
|
||||||
|
import com.squareup.javapoet.*;
|
||||||
|
import mindustry.annotations.*;
|
||||||
|
|
||||||
|
import javax.lang.model.element.*;
|
||||||
|
import javax.lang.model.type.*;
|
||||||
|
|
||||||
|
public class Selement<T extends Element>{
|
||||||
|
public final T e;
|
||||||
|
|
||||||
|
public Selement(T e){
|
||||||
|
this.e = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Element up(){
|
||||||
|
return e.getEnclosingElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeMirror mirror(){
|
||||||
|
return e.asType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeName tname(){
|
||||||
|
return TypeName.get(mirror());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassName cname(){
|
||||||
|
return ClassName.get((TypeElement)BaseProcessor.typeu.asElement(mirror()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String name(){
|
||||||
|
return e.getSimpleName().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString(){
|
||||||
|
return e.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode(){
|
||||||
|
return e.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o){
|
||||||
|
return o != null && o.getClass() == getClass() && ((Selement)o).e.equals(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package mindustry.annotations.util;
|
||||||
|
|
||||||
|
import arc.struct.*;
|
||||||
|
import com.squareup.javapoet.*;
|
||||||
|
import com.sun.source.tree.*;
|
||||||
|
import mindustry.annotations.*;
|
||||||
|
|
||||||
|
import javax.lang.model.element.*;
|
||||||
|
import javax.lang.model.type.*;
|
||||||
|
|
||||||
|
public class Smethod extends Selement<ExecutableElement>{
|
||||||
|
|
||||||
|
public Smethod(ExecutableElement executableElement){
|
||||||
|
super(executableElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean is(Modifier mod){
|
||||||
|
return e.getModifiers().contains(mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<TypeMirror> thrown(){
|
||||||
|
return Array.with(e.getThrownTypes()).as(TypeMirror.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<TypeName> thrownt(){
|
||||||
|
return Array.with(e.getThrownTypes()).map(TypeName::get);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<TypeParameterElement> typeVariables(){
|
||||||
|
return Array.with(e.getTypeParameters()).as(TypeParameterElement.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<Svar> params(){
|
||||||
|
return Array.with(e.getParameters()).map(Svar::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeMirror ret(){
|
||||||
|
return e.getReturnType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeName retn(){
|
||||||
|
return TypeName.get(ret());
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodTree tree(){
|
||||||
|
return BaseProcessor.trees.getTree(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package mindustry.annotations.util;
|
||||||
|
|
||||||
|
import arc.struct.*;
|
||||||
|
import mindustry.annotations.*;
|
||||||
|
|
||||||
|
import javax.lang.model.element.*;
|
||||||
|
import javax.lang.model.type.*;
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
public class Stype extends Selement<TypeElement>{
|
||||||
|
|
||||||
|
public Stype(TypeElement typeElement){
|
||||||
|
super(typeElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stype of(TypeMirror mirror){
|
||||||
|
return new Stype((TypeElement)BaseProcessor.typeu.asElement(mirror));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<Stype> interfaces(){
|
||||||
|
return Array.with(e.getInterfaces()).map(Stype::of);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<Stype> superclasses(){
|
||||||
|
Array<Stype> out = new Array<>();
|
||||||
|
Stype sup = superclass();
|
||||||
|
while(!sup.name().equals("Object")){
|
||||||
|
out.add(sup);
|
||||||
|
sup = sup.superclass();
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stype superclass(){
|
||||||
|
return new Stype((TypeElement)BaseProcessor.typeu.asElement(BaseProcessor.typeu.directSupertypes(mirror()).get(0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public <A extends Annotation> A annotation(Class<A> annotation){
|
||||||
|
return e.getAnnotation(annotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<Svar> fields(){
|
||||||
|
return Array.with(e.getEnclosedElements()).select(e -> e instanceof VariableElement).map(e -> new Svar((VariableElement)e));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<Smethod> methods(){
|
||||||
|
return Array.with(e.getEnclosedElements()).select(e -> e instanceof ExecutableElement
|
||||||
|
&& !e.getSimpleName().toString().contains("<")).map(e -> new Smethod((ExecutableElement)e));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<Smethod> constructors(){
|
||||||
|
return Array.with(e.getEnclosedElements()).select(e -> e instanceof ExecutableElement
|
||||||
|
&& e.getSimpleName().toString().contains("<")).map(e -> new Smethod((ExecutableElement)e));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeMirror mirror(){
|
||||||
|
return e.asType();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package mindustry.annotations.util;
|
||||||
|
|
||||||
|
import com.sun.source.tree.*;
|
||||||
|
import mindustry.annotations.*;
|
||||||
|
|
||||||
|
import javax.lang.model.element.*;
|
||||||
|
|
||||||
|
public class Svar extends Selement<VariableElement>{
|
||||||
|
|
||||||
|
public Svar(VariableElement e){
|
||||||
|
super(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean is(Modifier mod){
|
||||||
|
return e.getModifiers().contains(mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VariableTree tree(){
|
||||||
|
return (VariableTree)BaseProcessor.trees.getTree(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
mindustry.annotations.RemoteMethodAnnotationProcessor
|
|
||||||
mindustry.annotations.SerializeAnnotationProcessor
|
|
||||||
mindustry.annotations.StructAnnotationProcessor
|
|
||||||
mindustry.annotations.CallSuperAnnotationProcessor
|
|
||||||
mindustry.annotations.AssetsAnnotationProcessor
|
|
||||||
40
build.gradle
@@ -132,6 +132,20 @@ allprojects{
|
|||||||
props.store(pfile.newWriter(), "Autogenerated file. Do not modify.")
|
props.store(pfile.newWriter(), "Autogenerated file. Do not modify.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writeProcessors = {
|
||||||
|
new File(rootDir, "annotations/src/main/resources/META-INF/services/").mkdirs()
|
||||||
|
def processorFile = new File(rootDir, "annotations/src/main/resources/META-INF/services/javax.annotation.processing.Processor")
|
||||||
|
def text = new StringBuilder()
|
||||||
|
def files = new File(rootDir, "annotations/src/main/java")
|
||||||
|
files.eachFileRecurse(groovy.io.FileType.FILES){ file ->
|
||||||
|
if(file.name.endsWith(".java") && (file.text.contains(" extends BaseProcessor") || (file.text.contains(" extends AbstractProcessor") && !file.text.contains("abstract class")))){
|
||||||
|
text.append(file.path.substring(files.path.length() + 1)).append("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processorFile.text = text.toString().replace(".java", "").replace("/", ".").replace("\\", ".")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories{
|
repositories{
|
||||||
@@ -205,6 +219,7 @@ project(":core"){
|
|||||||
outputs.upToDateWhen{ false }
|
outputs.upToDateWhen{ false }
|
||||||
generateLocales()
|
generateLocales()
|
||||||
writeVersion()
|
writeVersion()
|
||||||
|
writeProcessors()
|
||||||
}
|
}
|
||||||
|
|
||||||
task copyChangelog{
|
task copyChangelog{
|
||||||
@@ -229,31 +244,6 @@ project(":core"){
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies{
|
dependencies{
|
||||||
if(System.properties["user.name"] == "anuke"){
|
|
||||||
task cleanGen{
|
|
||||||
doFirst{
|
|
||||||
delete{
|
|
||||||
delete "../core/src/mindustry/gen/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task copyGen{
|
|
||||||
doLast{
|
|
||||||
copy{
|
|
||||||
from("../core/build/generated/sources/annotationProcessor/java/main/mindustry/gen"){
|
|
||||||
include "**/*.java"
|
|
||||||
}
|
|
||||||
|
|
||||||
into "../core/src/mindustry/gen"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compileJava.dependsOn(cleanGen)
|
|
||||||
compileJava.finalizedBy(copyGen)
|
|
||||||
}
|
|
||||||
|
|
||||||
compileJava.dependsOn(preGen)
|
compileJava.dependsOn(preGen)
|
||||||
|
|
||||||
compile "org.lz4:lz4-java:1.4.1"
|
compile "org.lz4:lz4-java:1.4.1"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 286 B |
|
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 222 B |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 719 B |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 157 B |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 344 B |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 257 B |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 718 B |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 229 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 130 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 147 B |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 278 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 114 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 230 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 229 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 231 B |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 226 B |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 298 B |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 309 B |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 321 B |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 304 B |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 268 B |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 252 B |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 250 B |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 261 B |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 227 B |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 220 B |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 233 B |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 230 B |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 247 B |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 243 B |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 234 B |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 237 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 175 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 174 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 173 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 168 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 228 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 247 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 257 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 245 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 226 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 213 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 204 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 214 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 227 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 220 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 233 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 231 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 211 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 203 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 189 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 201 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 184 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 182 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 182 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 177 B |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 245 B |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 265 B |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 280 B |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 260 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 234 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 220 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 212 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 223 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 225 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 218 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 231 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 228 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 215 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 210 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 198 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 211 B |