-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Took 38 hours 33 minutes
- Loading branch information
Showing
142 changed files
with
5,404 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
plugins { | ||
id 'java' | ||
id 'com.github.johnrengelman.shadow' version '8.1.1' | ||
} | ||
|
||
tasks.register('generateAnnotationProcessorServicesFile'){ | ||
|
||
var target = file("src/main/resources/META-INF/services/javax.annotation.processing.Processor") | ||
target.parentFile.mkdirs() | ||
target.createNewFile() | ||
target.text = "" | ||
|
||
var classesDir = fileTree("src/main/java/com/xkball/tin_tea_tech/annotation_processor") | ||
var classFiles = classesDir.getFiles().findAll { it.name.endsWith('.java') } | ||
classFiles.each { | ||
var path = it.path | ||
var offset = path.indexOf("com\\xkball\\") | ||
if(offset >= 0) target.text += path.substring(offset,path.length()-5).replace('\\','.') + '\n' | ||
} | ||
|
||
inputs.dir file("src/main/java") | ||
outputs.file target | ||
} | ||
|
||
|
||
|
||
tasks.named("processResources") { | ||
dependsOn generateAnnotationProcessorServicesFile | ||
duplicatesStrategy = DuplicatesStrategy.INCLUDE | ||
} | ||
|
||
tasks.named("build"){ | ||
jar { | ||
archiveBaseName = "TinTeaTech-LocalAnnotationProcessor" | ||
archiveVersion.set(localAnnotationProcessorVersion) | ||
// destinationDirectory = file("../build/local_annotation_processor/lib") | ||
} | ||
|
||
} | ||
|
||
tasks.named("shadowJar"){ | ||
archiveBaseName = "TinTeaTech-LocalAnnotationProcessor" | ||
archiveVersion.set(localAnnotationProcessorVersion) | ||
} | ||
|
||
tasks.withType(JavaCompile).configureEach { | ||
getSource().files | ||
// outputs.upToDateWhen { false } | ||
options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation | ||
// options.fork = true | ||
// options.forkOptions.jvmArgs.add('--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED') | ||
// options.forkOptions.jvmArgs.add('--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED') | ||
// options.forkOptions.jvmArgs.add('--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED') | ||
// options.forkOptions.jvmArgs.add('--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED') | ||
// options.forkOptions.jvmArgs.add('--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED') | ||
// options.forkOptions.jvmArgs.add('--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED') | ||
// options.forkOptions.jvmArgs.add('-ea') | ||
|
||
|
||
options.compilerArgs.add('--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED') | ||
options.compilerArgs.add('--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED') | ||
options.compilerArgs.add('--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED') | ||
options.compilerArgs.add('--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED') | ||
options.compilerArgs.add('--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED') | ||
options.compilerArgs.add('--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED') | ||
} | ||
|
||
repositories { | ||
mavenCentral() | ||
} | ||
|
||
dependencies { | ||
implementation 'org.ow2.asm:asm:9.6' | ||
implementation 'org.ow2.asm:asm-tree:9.6' | ||
implementation 'org.ow2.asm:asm-util:9.6' | ||
implementation 'com.github.javaparser:javaparser-core:3.26.2' | ||
implementation 'com.github.javaparser:javaparser-symbol-solver-core:3.26.2' | ||
} | ||
|
||
tasks.register("runTest", JavaExec) { | ||
mainClass = "dev.vfyjxf.cumulonimbus.test.SampleJavacPluginTest" | ||
classpath = sourceSets.main.runtimeClasspath | ||
} |
98 changes: 98 additions & 0 deletions
98
...or/src/main/java/com/xkball/tin_tea_tech/annotation_processor/CodecProviderProcessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package com.xkball.tin_tea_tech.annotation_processor; | ||
|
||
import com.sun.tools.javac.api.JavacTrees; | ||
import com.sun.tools.javac.code.Symbol; | ||
import com.sun.tools.javac.tree.JCTree; | ||
import com.xkball.tin_tea_tech.util.CodecManager; | ||
import com.xkball.tin_tea_tech.util.jctree.JCTreeUtils; | ||
import com.xkball.tin_tea_tech.util.StringUtils; | ||
|
||
import javax.annotation.processing.AbstractProcessor; | ||
import javax.annotation.processing.Filer; | ||
import javax.annotation.processing.ProcessingEnvironment; | ||
import javax.annotation.processing.RoundEnvironment; | ||
import javax.annotation.processing.SupportedAnnotationTypes; | ||
import javax.annotation.processing.SupportedSourceVersion; | ||
import javax.lang.model.SourceVersion; | ||
import javax.lang.model.element.TypeElement; | ||
import javax.lang.model.util.Elements; | ||
import java.util.HashSet; | ||
import java.util.Objects; | ||
import java.util.Set; | ||
|
||
@SupportedSourceVersion(SourceVersion.RELEASE_21) | ||
@SupportedAnnotationTypes({ | ||
CodecProviderProcessor.CODEC_PROVIDER | ||
}) | ||
public class CodecProviderProcessor extends AbstractProcessor { | ||
|
||
public static final String CODEC_PROVIDER = "com.xkball.tin_tea_tech.api.annotation.CodecProvider"; | ||
|
||
private ProcessingEnvironment processingEnv; | ||
private Elements elementUtils; | ||
private Filer filer; | ||
private JavacTrees trees; | ||
|
||
@Override | ||
public synchronized void init(ProcessingEnvironment processingEnv) { | ||
super.init(processingEnv); | ||
CodecManager.init(processingEnv); | ||
this.processingEnv = processingEnv; | ||
this.elementUtils = processingEnv.getElementUtils(); | ||
this.filer = processingEnv.getFiler(); | ||
this.trees = JavacTrees.instance(processingEnv); | ||
} | ||
|
||
@Override | ||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { | ||
JCTreeUtils.setup(processingEnv); | ||
roundEnv.getElementsAnnotatedWith(elementUtils.getTypeElement(CODEC_PROVIDER)).forEach( | ||
anno -> { | ||
var classSymbol = JCTreeUtils.findClassSymbolRecursive((Symbol) anno); | ||
if (classSymbol == null) return; | ||
var fullName = classSymbol.getQualifiedName().toString(); | ||
var tree = trees.getTree(elementUtils.getTypeElement(fullName)); | ||
handleJCTree(fullName,tree,true); | ||
} | ||
); | ||
return false; | ||
} | ||
|
||
private static final Set<String> sourceHandledClasses = new HashSet<>(); | ||
private static final Set<String> processorHandledClasses = new HashSet<>(); | ||
|
||
public static void handleJCTree(String className, JCTree.JCClassDecl tree,boolean inAnnoProcessor){ | ||
if(!inAnnoProcessor){ | ||
if(sourceHandledClasses.contains(className)) return; | ||
sourceHandledClasses.add(className); | ||
} | ||
else { | ||
if(processorHandledClasses.contains(className)) return; | ||
processorHandledClasses.add(className); | ||
} | ||
JCTreeUtils.findFieldWithAnno(tree,CODEC_PROVIDER) | ||
.forEach(def -> { | ||
if(!JCTreeUtils.isPublicStatic(def)) return; | ||
var codecType = StringUtils.splitTypeNameWithArg(def.vartype.toString()); | ||
var typeName = StringUtils.fixTypeNameWithArgRecursive(className,codecType.snd); | ||
var codecRef = className+"."+def.name.toString(); | ||
var anno = Objects.requireNonNull(JCTreeUtils.findAnnotation(def,CODEC_PROVIDER)); | ||
var codecInsOrder = 0; | ||
var codecInsName = ""; | ||
for(var arg : anno.args){ | ||
if(arg instanceof JCTree.JCAssign assign){ | ||
if(assign.lhs.toString().equals("name")) codecInsName = StringUtils.removeDoubleQuotes(assign.rhs.toString()); | ||
if(assign.lhs.toString().equals("order")) codecInsOrder = Integer.parseInt(assign.rhs.toString()); | ||
} | ||
} | ||
var data = new CodecManager.CodecProviderData(codecType.fst,typeName,codecRef,codecInsName,codecInsOrder); | ||
if(!CodecManager.NEW_CODEC_PROVIDERS.contains(data)){ | ||
if(inAnnoProcessor) | ||
throw new IllegalArgumentException("Can not support codec provider from code generation!!! " + data); | ||
CodecManager.NEW_CODEC_PROVIDERS.add(data); | ||
CodecManager.addCodec(codecType.fst,typeName,codecRef,codecInsName,codecInsOrder); | ||
} | ||
}); | ||
} | ||
|
||
} |
122 changes: 122 additions & 0 deletions
122
...cessor/src/main/java/com/xkball/tin_tea_tech/annotation_processor/DataFieldProcessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
package com.xkball.tin_tea_tech.annotation_processor; | ||
|
||
import com.sun.tools.javac.api.JavacTrees; | ||
import com.sun.tools.javac.code.BoundKind; | ||
import com.sun.tools.javac.code.Flags; | ||
import com.sun.tools.javac.code.Symbol; | ||
import com.sun.tools.javac.tree.JCTree; | ||
import com.sun.tools.javac.util.List; | ||
import com.xkball.tin_tea_tech.api.annotation.DataField; | ||
import com.xkball.tin_tea_tech.api.annotation.DataSyncAdapter; | ||
import com.xkball.tin_tea_tech.util.CodecManager; | ||
import com.xkball.tin_tea_tech.util.jctree.DataJCTreeUtils; | ||
import com.xkball.tin_tea_tech.util.jctree.JCTreeUtils; | ||
|
||
import javax.annotation.processing.AbstractProcessor; | ||
import javax.annotation.processing.Filer; | ||
import javax.annotation.processing.ProcessingEnvironment; | ||
import javax.annotation.processing.RoundEnvironment; | ||
import javax.annotation.processing.SupportedAnnotationTypes; | ||
import javax.annotation.processing.SupportedSourceVersion; | ||
import javax.lang.model.SourceVersion; | ||
import javax.lang.model.element.TypeElement; | ||
import javax.lang.model.util.Elements; | ||
import java.util.ArrayList; | ||
|
||
|
||
import java.util.Objects; | ||
import java.util.Set; | ||
|
||
import static com.xkball.tin_tea_tech.util.jctree.JCTreeUtils.*; | ||
|
||
@SupportedSourceVersion(SourceVersion.RELEASE_21) | ||
@SupportedAnnotationTypes({ | ||
DataFieldProcessor.DATA_FIELD | ||
}) | ||
public class DataFieldProcessor extends AbstractProcessor { | ||
|
||
public static final String DATA_FIELD = "com.xkball.tin_tea_tech.api.annotation.DataField"; | ||
public static final java.util.List<String> handledClasses = new ArrayList<>(); | ||
|
||
private ProcessingEnvironment processingEnv; | ||
private Elements elementUtils; | ||
private Filer filer; | ||
private JavacTrees trees; | ||
|
||
@Override | ||
public synchronized void init(ProcessingEnvironment processingEnv) { | ||
super.init(processingEnv); | ||
CodecManager.init(processingEnv); | ||
this.processingEnv = processingEnv; | ||
this.elementUtils = processingEnv.getElementUtils(); | ||
this.filer = processingEnv.getFiler(); | ||
this.trees = JavacTrees.instance(processingEnv); | ||
} | ||
|
||
@Override | ||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { | ||
JCTreeUtils.setup(processingEnv); | ||
roundEnv.getElementsAnnotatedWith(elementUtils.getTypeElement(DATA_FIELD)).forEach( | ||
anno -> { | ||
var classSymbol = JCTreeUtils.findClassSymbolRecursive((Symbol) anno); | ||
if (classSymbol == null) return; | ||
var fullName = classSymbol.getQualifiedName().toString(); | ||
var tree = trees.getTree(elementUtils.getTypeElement(fullName)); | ||
handleClass(fullName, tree); | ||
} | ||
); | ||
return false; | ||
} | ||
|
||
public static void handleClass(String className, JCTree.JCClassDecl tree) { | ||
if (handledClasses.contains(className)) return; | ||
handledClasses.add(className); | ||
JCTreeUtils.setPos(tree); | ||
var fields = JCTreeUtils.findFieldWithAnno(tree,DATA_FIELD); | ||
var fieldsData = fields.stream().map(f -> DataJCTreeUtils.DataFieldData.fromAnno(className,f)).toList(); | ||
var saveList = List.from(fieldsData.toArray(DataJCTreeUtils.DataFieldData[]::new)); | ||
var s2cList = List.from(fieldsData.stream().filter(d -> d.syncPolicy() != DataField.SyncPolicy.SyncBoth).toArray(DataJCTreeUtils.DataFieldData[]::new)); | ||
var c2sList = List.from(fieldsData.stream().filter(d -> d.syncPolicy() == DataField.SyncPolicy.SyncBoth).toArray(DataJCTreeUtils.DataFieldData[]::new)); | ||
tree.defs = tree.defs.append(DataJCTreeUtils.createDataClass(className,"SaveData",saveList)); | ||
tree.defs = tree.defs.append(DataJCTreeUtils.createDataClass(className,"Sync2ClientData",s2cList)); | ||
tree.defs = tree.defs.append(DataJCTreeUtils.createDataClass(className,"SyncBothData",c2sList)); | ||
handleISyncDataOfNBTTag(className,tree,saveList,s2cList,c2sList); | ||
} | ||
|
||
public static void handleISyncDataOfNBTTag(String className, JCTree.JCClassDecl tree, List<DataJCTreeUtils.DataFieldData> saveList, List<DataJCTreeUtils.DataFieldData> s2cList, List<DataJCTreeUtils.DataFieldData> c2sList) { | ||
if(tree.implementing.stream().noneMatch(impl -> "ISyncDataOfNBTTag".equals(impl.toString()))) return; | ||
var saveCodecRef = className + ".SaveData.CODEC"; | ||
var s2cCodecRef = className + ".Sync2ClientData.CODEC"; | ||
var c2sCodecRef = className + ".SyncBothData.CODEC"; | ||
|
||
var returnCodecType = treeMaker.TypeApply(makeIdent("com.mojang.serialization.Codec"),List.of(treeMaker.Wildcard(treeMaker.TypeBoundKind(BoundKind.UNBOUND),null))); | ||
var saveCodecMethod = treeMaker.MethodDef(mods(Flags.PUBLIC),name("saveCodec"),returnCodecType,List.nil(),List.nil(),List.nil(),treeMaker.Block(0,List.of(treeMaker.Return(makeIdent(saveCodecRef)))),null); | ||
var s2cCodecMethod = treeMaker.MethodDef(mods(Flags.PUBLIC),name("server2clientCodec"),returnCodecType,List.nil(),List.nil(),List.nil(),treeMaker.Block(0,List.of(treeMaker.Return(makeIdent(s2cCodecRef)))),null); | ||
var c2sCodecMethod = treeMaker.MethodDef(mods(Flags.PUBLIC),name("client2serverCodec"),returnCodecType,List.nil(),List.nil(),List.nil(),treeMaker.Block(0,List.of(treeMaker.Return(makeIdent(c2sCodecRef)))),null); | ||
//addAnnotation2Methods("java.lang.Override",List.nil(),saveCodecMethod,s2cCodecMethod,c2sCodecMethod); | ||
tree.defs = tree.defs.appendList(List.of(saveCodecMethod,s2cCodecMethod,c2sCodecMethod)); | ||
|
||
if(!saveList.isEmpty()){ | ||
tree.defs = tree.defs.append(DataJCTreeUtils.createReadMethod(className,"SaveData","load",saveCodecRef,saveList)); | ||
tree.defs = tree.defs.append(DataJCTreeUtils.createWriteMethod(className,"SaveData","save",saveCodecRef,saveList)); | ||
} | ||
if(!s2cList.isEmpty()){ | ||
tree.defs = tree.defs.append(DataJCTreeUtils.createReadMethod(className,"Sync2ClientData","readS2C",s2cCodecRef,s2cList)); | ||
tree.defs = tree.defs.append(DataJCTreeUtils.createWriteMethod(className,"Sync2ClientData","writeS2C",s2cCodecRef,s2cList)); | ||
} | ||
if(!c2sList.isEmpty()){ | ||
tree.defs = tree.defs.append(DataJCTreeUtils.createReadMethod(className,"SyncBothData","readC2S",c2sCodecRef,c2sList)); | ||
tree.defs = tree.defs.append(DataJCTreeUtils.createWriteMethod(className,"SyncBothData","writeC2S",c2sCodecRef,c2sList)); | ||
} | ||
handleSyncAdapter(className,tree); | ||
} | ||
|
||
public static void handleSyncAdapter(String className, JCTree.JCClassDecl tree){ | ||
if(JCTreeUtils.findAnnotation(tree,"com.xkball.tin_tea_tech.api.annotation.DataSyncAdapter") == null) return; | ||
var annoArg = Objects.requireNonNull(findAnnotation(tree, "com.xkball.tin_tea_tech.api.annotation.DataSyncAdapter")).args; | ||
var type = DataSyncAdapter.Type.fromString(annoArg.stream().filter(arg -> arg instanceof JCTree.JCAssign assign && "value".equals(assign.lhs.toString())).map(arg -> ((JCTree.JCAssign)arg).rhs.toString()).findFirst().orElseThrow()); | ||
if(type == DataSyncAdapter.Type.BlockEntity){ | ||
tree.defs = tree.defs.appendList(DataJCTreeUtils.createBlockEntityOverrides()); | ||
} | ||
} | ||
} |
Oops, something went wrong.