Generating btree functions

This commit is contained in:
unknown 2023-05-08 08:33:35 -04:00
parent 0241f4d641
commit 2a0225abdf
14 changed files with 438 additions and 14 deletions

View File

@ -3,13 +3,21 @@ package electrosphere.main;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map;
import org.jboss.forge.roaster.Roaster; import org.jboss.forge.roaster.Roaster;
import org.jboss.forge.roaster.model.ValuePair;
import org.jboss.forge.roaster.model.source.AnnotationSource;
import org.jboss.forge.roaster.model.source.EnumConstantSource;
import org.jboss.forge.roaster.model.source.FieldSource; import org.jboss.forge.roaster.model.source.FieldSource;
import org.jboss.forge.roaster.model.source.JavaClassSource; import org.jboss.forge.roaster.model.source.JavaClassSource;
import org.jboss.forge.roaster.model.source.JavaDocSource; import org.jboss.forge.roaster.model.source.JavaDocSource;
import org.jboss.forge.roaster.model.source.JavaEnumSource;
import org.jboss.forge.roaster.model.source.JavaSource;
import org.jboss.forge.roaster.model.source.MethodSource;
import electrosphere.main.targets.NetcodeGenTarget; import electrosphere.main.targets.NetcodeGenTarget;
import electrosphere.main.targets.TargetFile; import electrosphere.main.targets.TargetFile;
@ -20,30 +28,177 @@ import electrosphere.main.targets.TargetFile;
*/ */
public class Main { public class Main {
static String topLevelFolderPath = "C:\\Users\\satellite\\Documents\\Renderer\\src\\main\\java\\electrosphere";
static String[] targetFiles = new String[]{ static String[] targetFiles = new String[]{
"C:\\Users\\satellite\\Documents\\Renderer\\src\\main\\java\\electrosphere\\entity\\state\\IdleTree.java", "C:\\Users\\satellite\\Documents\\Renderer\\src\\main\\java\\electrosphere\\entity\\state\\IdleTree.java",
}; };
static int bTreeIterator = 0;
//maps the btree annotation "name" to an id
static Map<String,Integer> bTreeIdMap = new HashMap<String,Integer>();
public static void main(String args[]){ public static void main(String args[]){
System.out.println("Hello, world!"); File topLevelFolder = new File(topLevelFolderPath);
for(String targetFilePath : targetFiles){ List<File> fileQueue = new LinkedList<File>();
String content = ""; List<File> fileQueueOpenSet = new LinkedList<File>();
try { List<File> fileQueueClosedSet = new LinkedList<File>();
content = Files.readString(new File(targetFilePath).toPath()); fileQueue.add(topLevelFolder);
} catch (IOException e){ while(fileQueue.size() > 0){
e.printStackTrace(); for(File currentFile : fileQueue){
if(currentFile.isDirectory()){
for(File childFile : currentFile.listFiles()){
fileQueueOpenSet.add(childFile);
}
} else {
if(currentFile.getName().contains(".java")){
String content = "";
try {
content = Files.readString(currentFile.toPath());
if(content.contains("@BehaviorTreeAnnotation")){
//parse
JavaClassSource source = parseJavaFile(content);
//generate code
generateCode(source, currentFile, content);
}
} catch (IOException e){
e.printStackTrace();
}
}
}
fileQueueClosedSet.add(currentFile);
} }
TargetFile targetFile = new TargetFile(targetFilePath, content); for(File currentClosedFile : fileQueueOpenSet){
for(NetcodeGenTarget target : parseGenerationTargets(targetFile)){ fileQueue.add(currentClosedFile);
System.out.println(target.getName()); }
fileQueueOpenSet.clear();
for(File currentClosedFile : fileQueueClosedSet){
fileQueue.remove(currentClosedFile);
} }
} }
} }
static JavaClassSource parseJavaFile(String content){
return Roaster.parse(JavaClassSource.class, content);
}
static void generateCode(JavaClassSource source, File file, String content){
String bTreeName = source.getAnnotation("BehaviorTreeAnnotation").getStringValue("name");
bTreeIdMap.put(bTreeName,bTreeIterator);
bTreeIterator++;
TargetFile targetFile = new TargetFile(file.getAbsolutePath(), content, bTreeName, source);
StringBuilder outputContent = new StringBuilder(content);
List<NetcodeGenTarget> targets = parseGenerationTargets(targetFile);
for(NetcodeGenTarget target : targets){
//check if has getter
MethodSource<JavaClassSource> getter = null;
MethodSource<JavaClassSource> setter = null;
MethodSource<JavaClassSource> enumToIntMapper = null;
MethodSource<JavaClassSource> intToEnumMapper = null;
for(MethodSource<JavaClassSource> method : targetFile.getSource().getMethods()){
if(method.getName().equals(getGetterName(target.getName()))){
getter = method;
}
if(method.getName().equals(getSetterName(target.getName()))){
setter = method;
}
if(method.getName().equals(getEnumToIntMapperName(target.getName()))){
enumToIntMapper = method;
}
if(method.getName().equals(getIntToEnumMapperName(target.getName()))){
intToEnumMapper = method;
}
if(getter != null && setter != null && enumToIntMapper != null && intToEnumMapper != null){
break;
}
}
//check if need to make enum to int mapper function
if(target.getAnnotation().getStringValue("isEnum") != null){
//find enum in current file
JavaSource<JavaEnumSource> enumSource = null;
for(JavaSource<?> nestedSource : targetFile.getSource().getNestedTypes()){
if(nestedSource.getName().equals(target.getTypeName())){
enumSource = (JavaSource<JavaEnumSource>)nestedSource;
break;
}
}
List<String> enumConstNames = new LinkedList<String>();
if(enumSource != null){
for(EnumConstantSource enumConstant : enumSource.getOrigin().getEnumConstants()){
enumConstNames.add(enumConstant.getName());
}
}
//mapper enum->int
if(enumToIntMapper != null){
//regenerate
int startChar = enumToIntMapper.getStartPosition();
int endChar = enumToIntMapper.getEndPosition();
outputContent = outputContent.replace(startChar, endChar, generateEnumToIntMapperCode(target,enumConstNames));
} else {
//generate
int positionJustBeforeClassEnd = targetFile.getSource().getEndPosition() - 1;
outputContent.insert(positionJustBeforeClassEnd, generateEnumToIntMapperCode(target,enumConstNames));
}
//mapper int->enum
if(intToEnumMapper != null){
//regenerate
int startChar = intToEnumMapper.getStartPosition();
int endChar = intToEnumMapper.getEndPosition();
outputContent = outputContent.replace(startChar, endChar, generateIntToEnumMapperCode(target,enumConstNames));
} else {
//generate
int positionJustBeforeClassEnd = targetFile.getSource().getEndPosition() - 1;
outputContent.insert(positionJustBeforeClassEnd, generateIntToEnumMapperCode(target,enumConstNames));
}
}
//getter
if(getter != null){
//regenerate
int startChar = getter.getStartPosition();
int endChar = getter.getEndPosition();
outputContent = outputContent.replace(startChar, endChar, generateGetterCode(target.getName(),target));
} else {
//generate
int positionJustBeforeClassEnd = targetFile.getSource().getEndPosition() - 1;
outputContent.insert(positionJustBeforeClassEnd, generateGetterCode(target.getName(),target));
}
//setter
if(setter != null){
//regenerate
int startChar = setter.getStartPosition();
int endChar = setter.getEndPosition();
outputContent = outputContent.replace(startChar, endChar, generateSetterCode(targetFile,target.getName(),target));
} else {
//generate
int positionJustBeforeClassEnd = targetFile.getSource().getEndPosition() - 1;
outputContent.insert(positionJustBeforeClassEnd, generateSetterCode(targetFile,target.getName(),target));
}
//message parsing on behavior tree in general
//...TODO
}
//message parser generation
int positionJustBeforeClassEnd = targetFile.getSource().getEndPosition() - 1;
outputContent.insert(positionJustBeforeClassEnd, generateParseBTreeMessages(targetFile, targets));
System.out.println(outputContent);
}
static List<NetcodeGenTarget> parseGenerationTargets(TargetFile targetFile){ static List<NetcodeGenTarget> parseGenerationTargets(TargetFile targetFile){
int targetIdIterator = 0;
List<NetcodeGenTarget> targets = new LinkedList<NetcodeGenTarget>(); List<NetcodeGenTarget> targets = new LinkedList<NetcodeGenTarget>();
for(FieldSource<JavaClassSource> field : targetFile.getSource().getFields()){ for(FieldSource<JavaClassSource> field : targetFile.getSource().getFields()){
System.out.println(field.getName()); List<AnnotationSource<JavaClassSource>> annotations = field.getAnnotations();
for(AnnotationSource<JavaClassSource> annotation : annotations){
if(annotation.getName().equals("SyncedField")){
targets.add(new NetcodeGenTarget(targetIdIterator, field.getName(), field.getType().getName(), field, annotation));
targetIdIterator++;
}
}
} }
return targets; return targets;
} }
@ -79,4 +234,140 @@ public class Main {
System.out.println(javaClass); System.out.println(javaClass);
} }
static String getGetterName(String fieldName){
return "get" + camelCase(fieldName);
}
static String getSetterName(String fieldName){
return "set" + camelCase(fieldName);
}
static String getEnumToIntMapperName(String fieldName){
return fieldName + "ToInt";
}
static String getIntToEnumMapperName(String fieldName){
return fieldName + "FromInt";
}
static String camelCase(String input){
return Character.toUpperCase(input.charAt(0)) + input.substring(1);
}
static String generateGetterCode(String variableName, NetcodeGenTarget target){
return Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/Getter.java"))
.replace("REPLACENAMECAMEL",camelCase(variableName))
.replace("REPLACETYPE",target.getTypeName())
.replace("REPLACENAMENOTCAMEL",variableName);
}
static String generateSetterCode(TargetFile targetFile, String variableName, NetcodeGenTarget target){
String messageConstructor = "";
switch(target.getTypeName()){
case "int": {
messageConstructor = Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/SetterInt.java"))
.replace("REPLACEBTREEID",bTreeIdMap.get(targetFile.getName()) + "")
.replace("REPLACEPROPERTYID",target.getId() + "")
.replace("REPLACENAMENOTCAMEL",variableName);
} break;
case "double": {
messageConstructor = Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/SetterDouble.java"))
.replace("REPLACEBTREEID",bTreeIdMap.get(targetFile.getName()) + "")
.replace("REPLACEPROPERTYID",target.getId() + "")
.replace("REPLACENAMENOTCAMEL",variableName);
} break;
case "float": {
messageConstructor = Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/SetterFloat.java"))
.replace("REPLACEBTREEID",bTreeIdMap.get(targetFile.getName()) + "")
.replace("REPLACEPROPERTYID",target.getId() + "")
.replace("REPLACENAMENOTCAMEL",variableName);
} break;
case "String": {
messageConstructor = Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/SetterString.java"))
.replace("REPLACEBTREEID",bTreeIdMap.get(targetFile.getName()) + "")
.replace("REPLACEPROPERTYID",target.getId() + "")
.replace("REPLACENAMENOTCAMEL",variableName);
} break;
}
if(target.getAnnotation().getStringValue("isEnum") != null){
messageConstructor = Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/SetterEnum.java"))
.replace("REPLACEBTREEID",bTreeIdMap.get(targetFile.getName()) + "")
.replace("REPLACEPROPERTYID",target.getId() + "")
.replace("REPLACENAMECAMEL",camelCase(variableName))
.replace("REPLACENAMENOTCAMEL",variableName);
}
return Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/Setter.java"))
.replace("REPLACENAMECAMEL",camelCase(variableName))
.replace("REPLACETYPE",target.getTypeName())
.replace("REPLACENAMENOTCAMEL",variableName)
.replace("REPLACEMESSAGECONSTRUCTOR",messageConstructor);
}
static String generateEnumToIntMapperCode(NetcodeGenTarget target, List<String> enumConstNames){
String switchCases = "";
int i = 0;
for(String enumConstName : enumConstNames){
switchCases = switchCases + "case " + enumConstName + ":\n" +
"return " + i + ";\n";
i++;
}
return Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/EnumToIntMapper.java"))
.replace("REPLACEENUMTYPE",target.getTypeName())
.replace("REPLACENAMECAMEL",camelCase(target.getName()))
.replace("REPLACECASE",switchCases)
.replace("REPLACETYPENAME",target.getTypeName());
}
static String generateIntToEnumMapperCode(NetcodeGenTarget target, List<String> enumConstNames){
String switchCases = "";
int i = 0;
for(String enumConstName : enumConstNames){
switchCases = switchCases + "case " + i + ":\n" +
"return " + target.getTypeName() + "." + enumConstName + ";\n";
i++;
}
return Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/IntToEnumMapper.java"))
.replace("REPLACEENUMTYPE",target.getTypeName())
.replace("REPLACENAMECAMEL",camelCase(target.getName()))
.replace("REPLACECASE",switchCases);
}
static String generateParseBTreeMessages(TargetFile targetFile, List<NetcodeGenTarget> targets){
String setCases = "";
for(NetcodeGenTarget target : targets){
String base = "case REPLACE_PROPERTY_ID: {\n" +
"setREPLACE_VARIABLE_NAME_CAMEL(REPLACE_GET_PROPERTY_VALUE);\n" +
"} break;\n";
String propertyValueFetcher = "";
switch(target.getTypeName()){
case "int": {
propertyValueFetcher = "message.getpropertyValueInt()";
} break;
case "float": {
propertyValueFetcher = "message.getpropertyValueFloat()";
} break;
case "double": {
propertyValueFetcher = "message.getpropertyValueDouble()";
} break;
case "String": {
propertyValueFetcher = "message.getpropertyValueString()";
} break;
//enum
default: {
propertyValueFetcher = "getEnumIntValueREPLACENAMECAMEL(message.getpropertyValueInt())".replace("REPLACENAMECAMEL",camelCase(target.getName()));
} break;
}
String replaced = base
.replace("REPLACE_PROPERTY_ID",target.getId() + "")
.replace("REPLACE_GET_PROPERTY_VALUE",propertyValueFetcher)
.replace("REPLACE_VARIABLE_NAME_CAMEL",camelCase(target.getName()));
System.out.println(replaced);
setCases = setCases + replaced;
}
return Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/ParseBTreeMessages.java"))
.replace("REPLACE_WITH_CASES",setCases);
}
} }

View File

@ -0,0 +1,53 @@
package electrosphere.main;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.concurrent.TimeUnit;
public class Utilities {
static final int maxReadFails = 3;
static final int READ_TIMEOUT_DURATION = 5;
public static String readBakedResourceToString(InputStream resourceInputStream){
String rVal = "";
BufferedReader reader;
try {
reader = new BufferedReader(new InputStreamReader(resourceInputStream));
int failCounter = 0;
boolean reading = true;
StringBuilder builder = new StringBuilder("");
while(reading){
if(reader.ready()){
failCounter = 0;
int nextValue = reader.read();
if(nextValue == -1){
reading = false;
} else {
builder.append((char)nextValue);
}
} else {
failCounter++;
if(failCounter > maxReadFails){
reading = false;
} else {
try {
TimeUnit.MILLISECONDS.sleep(READ_TIMEOUT_DURATION);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
rVal = builder.toString();
} catch (IOException ex) {
ex.printStackTrace();
}
return rVal;
}
}

View File

@ -1,15 +1,43 @@
package electrosphere.main.targets; package electrosphere.main.targets;
import org.jboss.forge.roaster.model.source.AnnotationSource;
import org.jboss.forge.roaster.model.source.FieldSource;
import org.jboss.forge.roaster.model.source.JavaClassSource;
public class NetcodeGenTarget { public class NetcodeGenTarget {
int id;
String name; String name;
String typeName;
FieldSource<JavaClassSource> field;
AnnotationSource<JavaClassSource> annotation;
public NetcodeGenTarget(String name){ public NetcodeGenTarget(int id, String name, String typeName, FieldSource<JavaClassSource> field, AnnotationSource<JavaClassSource> annotation){
this.id = id;
this.name = name; this.name = name;
this.typeName = typeName;
this.field = field;
this.annotation = annotation;
}
public int getId(){
return id;
} }
public String getName(){ public String getName(){
return name; return name;
} }
public String getTypeName(){
return typeName;
}
public FieldSource<JavaClassSource> getField(){
return field;
}
public AnnotationSource<JavaClassSource> getAnnotation(){
return annotation;
}
} }

View File

@ -8,15 +8,21 @@ public class TargetFile {
String path; String path;
String content; String content;
JavaClassSource source; JavaClassSource source;
String name;
public TargetFile(String path, String content){ public TargetFile(String path, String content, String name, JavaClassSource source){
this.path = path; this.path = path;
this.content = content; this.content = content;
this.source = Roaster.parse(JavaClassSource.class, content); this.name = name;
this.source = source;
} }
public JavaClassSource getSource(){ public JavaClassSource getSource(){
return source; return source;
} }
public String getName(){
return name;
}
} }

View File

@ -0,0 +1,7 @@
private int getEnumIntValueREPLACENAMECAMEL(REPLACEENUMTYPE value){
int rVal = -1;
switch(value){
REPLACECASE
}
return rVal;
}

View File

@ -0,0 +1,3 @@
public REPLACETYPE getREPLACENAMECAMEL(){
return REPLACENAMENOTCAMEL;
}

View File

@ -0,0 +1,7 @@
private REPLACEENUMTYPE getEnumIntValueREPLACENAMECAMEL(int value){
REPLACEENUMTYPE rVal = null;
switch(value){
REPLACECASE
}
return rVal;
}

View File

@ -0,0 +1,7 @@
private void parseBTreeMessages(List<EntityMessage> messages){
for(EntityMessage message : messages){
switch(message.getpropertyID()){
REPLACE_WITH_CASES
}
}
}

View File

@ -0,0 +1,17 @@
public void setREPLACENAMECAMEL(REPLACETYPE REPLACENAMENOTCAMEL){
this.REPLACENAMENOTCAMEL = REPLACENAMENOTCAMEL;
if(Globals.RUN_SERVER){
//only server
Globals.dataCellManager.sendNetworkMessageToChunk(
REPLACEMESSAGECONSTRUCTOR,
Globals.serverWorldData.convertRealToChunkSpace(position.x),
Globals.serverWorldData.convertRealToChunkSpace(position.z)
);
if(Globals.RUN_CLIENT){
//server and client so alert client entity that this value has been updated
}
} else if(Globals.RUN_CLIENT){
//only client
this.REPLACENAMENOTCAMEL = REPLACENAMENOTCAMEL;
}
}

View File

@ -0,0 +1 @@
EntityMessage.constructsetBTreePropertyDoubleMessage(parent.getId(), Main.getCurrentFrame(), REPLACEBTREEID, REPLACEPROPERTYID, REPLACENAMENOTCAMEL)

View File

@ -0,0 +1 @@
EntityMessage.constructsetBTreePropertyEnumMessage(parent.getId(), Main.getCurrentFrame(), REPLACEBTREEID, REPLACEPROPERTYID, getEnumIntValueREPLACENAMECAMEL(REPLACENAMENOTCAMEL))

View File

@ -0,0 +1 @@
EntityMessage.constructsetBTreePropertyFloatMessage(parent.getId(), Main.getCurrentFrame(), REPLACEBTREEID, REPLACEPROPERTYID, REPLACENAMENOTCAMEL)

View File

@ -0,0 +1 @@
EntityMessage.constructsetBTreePropertyIntMessage(parent.getId(), Main.getCurrentFrame(), REPLACEBTREEID, REPLACEPROPERTYID, REPLACENAMENOTCAMEL)

View File

@ -0,0 +1 @@
EntityMessage.constructsetBTreePropertyStringMessage(parent.getId(), Main.getCurrentFrame(), REPLACEBTREEID, REPLACEPROPERTYID, REPLACENAMENOTCAMEL)