refactoring code
All checks were successful
studiorailgun/highlevel-netcode-gen/pipeline/head This commit looks good

This commit is contained in:
austin 2024-07-31 10:49:54 -04:00
parent 57a7aa0c61
commit 9239aee487
14 changed files with 172 additions and 684 deletions

View File

@ -11,7 +11,7 @@ import java.util.Map;
import org.jboss.forge.roaster.Roaster; import org.jboss.forge.roaster.Roaster;
import org.jboss.forge.roaster.model.source.JavaClassSource; import org.jboss.forge.roaster.model.source.JavaClassSource;
import electrosphere.main.structure.ProjectStructure; import electrosphere.main.project.ProjectStructure;
import electrosphere.main.targets.TargetFile; import electrosphere.main.targets.TargetFile;
/** /**

View File

@ -1,5 +1,10 @@
package electrosphere.main.structure; package electrosphere.main.client;
import electrosphere.main.core.btree.BehaviorTree;
import electrosphere.main.core.enums.BTreeIdEnum;
import electrosphere.main.core.syncfield.SynchronizedField;
import electrosphere.main.core.syncfield.SynchronizedType;
import electrosphere.main.project.ProjectStructure;
import electrosphere.main.targets.TargetFile; import electrosphere.main.targets.TargetFile;
import electrosphere.main.util.ClassSourceUtils; import electrosphere.main.util.ClassSourceUtils;
import electrosphere.main.util.TemplateInjectionUtils; import electrosphere.main.util.TemplateInjectionUtils;
@ -21,16 +26,16 @@ public class ClientSynchronizationManager {
*/ */
public static void update(ProjectStructure structure, TargetFile clientSynchronizationManager){ public static void update(ProjectStructure structure, TargetFile clientSynchronizationManager){
String updateCases = ""; String updateCases = "";
for(BehaviorTree serverTree : structure.behaviorTrees){ for(BehaviorTree serverTree : structure.getBehaviorTrees()){
//counterintuitively, want to only update client for server behavior tree ids //counterintuitively, want to only update client for server behavior tree ids
if(serverTree.isServer()){ if(serverTree.isServer()){
BehaviorTree clientEquivalent = structure.getTree(serverTree.correspondingTreeName); BehaviorTree clientEquivalent = structure.getTree(serverTree.getCorrespondingTreeName());
updateCases = updateCases + " case BehaviorTreeIdEnums." + BTreeIdEnum.getTreeIdEnum(serverTree) + ": {\n"; updateCases = updateCases + " case BehaviorTreeIdEnums." + BTreeIdEnum.getTreeIdEnum(serverTree) + ": {\n";
updateCases = updateCases + " switch(message.getfieldId()){\n"; updateCases = updateCases + " switch(message.getfieldId()){\n";
for(SynchronizedField field : serverTree.synchronizedFields){ for(SynchronizedField field : serverTree.getSynchronizedFields()){
String treeName = clientEquivalent.getClassName(); String treeName = clientEquivalent.getClassName();
String fieldIdVariable = "TREE_" + serverTree.name.toUpperCase() + "_SYNCEDFIELD_" + field.fieldName.toUpperCase() + "_ID"; String fieldIdVariable = "TREE_" + serverTree.getName().toUpperCase() + "_SYNCEDFIELD_" + field.getFieldName().toUpperCase() + "_ID";
switch(field.typeName){ switch(field.getTypeName()){
case "int": { case "int": {
updateCases = updateCases + " case FieldIdEnums." + fieldIdVariable + ":{\n"; updateCases = updateCases + " case FieldIdEnums." + fieldIdVariable + ":{\n";
updateCases = updateCases + " " + treeName + " tree = " + treeName + ".get" + treeName + "(entity);\n"; updateCases = updateCases + " " + treeName + " tree = " + treeName + ".get" + treeName + "(entity);\n";
@ -62,7 +67,7 @@ public class ClientSynchronizationManager {
updateCases = updateCases + " } break;\n"; updateCases = updateCases + " } break;\n";
} break; } break;
default: { default: {
SynchronizedType type = structure.getType(field.typeName); SynchronizedType type = structure.getType(field.getTypeName());
String typeClass = type.getTargetFile().getSource().getName(); String typeClass = type.getTargetFile().getSource().getName();
updateCases = updateCases + " case FieldIdEnums." + fieldIdVariable + ":{\n"; updateCases = updateCases + " case FieldIdEnums." + fieldIdVariable + ":{\n";
updateCases = updateCases + " " + treeName + " tree = " + treeName + ".get" + treeName + "(entity);\n"; updateCases = updateCases + " " + treeName + " tree = " + treeName + ".get" + treeName + "(entity);\n";
@ -76,7 +81,7 @@ public class ClientSynchronizationManager {
//guarantee import //guarantee import
// ClassSourceUtils.importClass(structure, clientSynchronizationManager, serverTree.getTargetFile().getQualifiedPath()); // ClassSourceUtils.importClass(structure, clientSynchronizationManager, serverTree.getTargetFile().getQualifiedPath());
ClassSourceUtils.importClass(structure, clientSynchronizationManager, structure.getTree(serverTree.correspondingTreeName).getTargetFile().getQualifiedPath()); ClassSourceUtils.importClass(structure, clientSynchronizationManager, structure.getTree(serverTree.getCorrespondingTreeName()).getTargetFile().getQualifiedPath());
} }
} }
ClassSourceUtils.importClass(structure, clientSynchronizationManager, "electrosphere.net.synchronization.FieldIdEnums"); ClassSourceUtils.importClass(structure, clientSynchronizationManager, "electrosphere.net.synchronization.FieldIdEnums");

View File

@ -1,292 +0,0 @@
package electrosphere.main.codegen;
import java.io.File;
import java.util.LinkedList;
import java.util.List;
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.JavaClassSource;
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.Main;
import electrosphere.main.targets.NetcodeGenTarget;
import electrosphere.main.targets.TargetFile;
import electrosphere.main.util.Utilities;
/**
* Generates client-side synchronization code
*/
public class ClientGen {
public static void generateCode(JavaClassSource source, String bTreeName, File file, String content) throws Exception {
TargetFile targetFile = new TargetFile(file.getAbsolutePath(), content, bTreeName, source);
StringBuilder outputContent = new StringBuilder(content);
List<NetcodeGenTarget> targets = parseGenerationTargets(targetFile);
//
//Find if there was already a parse network message function
MethodSource<JavaClassSource> parseNetworkMessageFunction = null;
for(MethodSource<JavaClassSource> method : targetFile.getSource().getMethods()){
if(method.getName().equals("parseBTreeMessages")){
parseNetworkMessageFunction = method;
}
}
//
//Code gen for each synchronized variable
//
for(NetcodeGenTarget target : targets){
//
//Look for existing methods
MethodSource<JavaClassSource> setter = null;
MethodSource<JavaClassSource> enumToIntMapper = null;
MethodSource<JavaClassSource> intToEnumMapper = null;
for(MethodSource<JavaClassSource> method : targetFile.getSource().getMethods()){
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;
}
}
//
//check if need to make enum to int mapper function
if(target.getAnnotation().getStringValue("isEnum") != null){
if(target.getAnnotation().getStringValue("enumId") == null){
throw new Exception("Failed to parse enum because enumId is not set on the synchronized field annotation");
}
// int enumId = Integer.parseInt(target.getAnnotation().getStringValue("enumId"));
//
//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.delete(startChar, endChar);
int lineNumber = Utilities.getLineNumber(outputContent.toString(), startChar);
Utilities.insertIntoSource(outputContent, generateEnumToIntMapperCode(target,enumConstNames), lineNumber, 1);
} else {
//generate
int positionJustBeforeClassEnd = targetFile.getSource().getEndPosition() - 1;
int lineNumber = Utilities.getLineNumber(outputContent.toString(), positionJustBeforeClassEnd);
outputContent = Utilities.insertIntoSource(outputContent, generateEnumToIntMapperCode(target,enumConstNames), lineNumber, 1);
}
//
//mapper int->enum
if(intToEnumMapper != null){
//regenerate
int startChar = intToEnumMapper.getStartPosition();
int endChar = intToEnumMapper.getEndPosition();
outputContent = outputContent.delete(startChar, endChar);
int lineNumber = Utilities.getLineNumber(outputContent.toString(), startChar);
Utilities.insertIntoSource(outputContent, generateIntToEnumMapperCode(target,enumConstNames), lineNumber, 1);
} else {
//generate
int positionJustBeforeClassEnd = targetFile.getSource().getEndPosition() - 1;
int lineNumber = Utilities.getLineNumber(outputContent.toString(), positionJustBeforeClassEnd);
outputContent = Utilities.insertIntoSource(outputContent, generateIntToEnumMapperCode(target,enumConstNames), lineNumber, 1);
}
}
//
//generate setter
if(setter != null){
//regenerate
int startChar = setter.getStartPosition();
int endChar = setter.getEndPosition();
outputContent = outputContent.delete(startChar, endChar);
int lineNumber = Utilities.getLineNumber(outputContent.toString(), startChar);
Utilities.insertIntoSource(outputContent, generateSetterCode(targetFile,target.getName(),target), lineNumber, 1);
} else {
//generate
int positionJustBeforeClassEnd = targetFile.getSource().getEndPosition() - 1;
int lineNumber = Utilities.getLineNumber(outputContent.toString(), positionJustBeforeClassEnd);
outputContent = Utilities.insertIntoSource(outputContent, generateSetterCode(targetFile,target.getName(),target), lineNumber, 1);
}
}
//message parser generation
if(parseNetworkMessageFunction == null){
//generate
int positionJustBeforeClassEnd = targetFile.getSource().getEndPosition() - 1;
int lineNumber = Utilities.getLineNumber(outputContent.toString(), positionJustBeforeClassEnd);
outputContent = Utilities.insertIntoSource(outputContent, generateParseBTreeMessages(targetFile, targets), lineNumber, 1);
} else {
//regenerate
int startChar = parseNetworkMessageFunction.getStartPosition();
int endChar = parseNetworkMessageFunction.getEndPosition();
outputContent = outputContent.delete(startChar, endChar);
int lineNumber = Utilities.getLineNumber(outputContent.toString(), startChar);
Utilities.insertIntoSource(outputContent, generateParseBTreeMessages(targetFile, targets), lineNumber, 1);
}
// System.out.println(outputContent);
}
static List<NetcodeGenTarget> parseGenerationTargets(TargetFile targetFile){
int targetIdIterator = 0;
List<NetcodeGenTarget> targets = new LinkedList<NetcodeGenTarget>();
for(FieldSource<JavaClassSource> field : targetFile.getSource().getFields()){
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;
}
static String getSetterName(String fieldName){
return "set" + Utilities.camelCase(fieldName);
}
static String getEnumToIntMapperName(String fieldName){
return "getEnumIntValue" + Utilities.camelCase(fieldName);
}
static String getIntToEnumMapperName(String fieldName){
return "getIntEnumValue" + Utilities.camelCase(fieldName);
}
static String generateSetterCode(TargetFile targetFile, String variableName, NetcodeGenTarget target){
String messageConstructor = "";
//
//regular types
switch(target.getTypeName()){
case "int": {
messageConstructor = Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/client/SetterInt.java"));
} break;
case "double": {
messageConstructor = Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/client/SetterDouble.java"));
} break;
case "float": {
messageConstructor = Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/client/SetterFloat.java"));
} break;
case "String": {
messageConstructor = Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/client/SetterString.java"));
} break;
}
messageConstructor = messageConstructor
.replace("REPLACEBTREEID",Main.bTreeIdMap.get(targetFile.getName()) + "")
.replace("REPLACEPROPERTYID",target.getId() + "")
.replace("REPLACENAMENOTCAMEL",variableName);
//
//enum type handling
if(target.getAnnotation().getStringValue("isEnum") != null){
messageConstructor = Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/client/SetterEnum.java"))
.replace("REPLACEBTREEID",Main.bTreeIdMap.get(targetFile.getName()) + "")
.replace("REPLACEPROPERTYID",target.getId() + "")
.replace("REPLACENAMECAMEL",Utilities.camelCase(variableName))
.replace("REPLACENAMENOTCAMEL",variableName);
}
//
//returns setter string
String rVal = Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/client/Setter.java"))
.replace("REPLACENAMECAMEL",Utilities.camelCase(variableName))
.replace("REPLACETYPE",target.getTypeName())
.replace("REPLACENAMENOTCAMEL",variableName)
.replace("REPLACEMESSAGECONSTRUCTOR",messageConstructor);
return rVal;
}
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++;
}
String rVal = Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/client/EnumToIntMapper.java"))
.replace("REPLACEENUMTYPE",target.getTypeName())
.replace("REPLACENAMECAMEL",Utilities.camelCase(target.getName()))
.replace("REPLACETYPENAME",target.getTypeName());
rVal = Utilities.replacePhraseWithPhraseAtIndent(rVal, switchCases, "REPLACECASE");
return rVal;
}
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++;
}
String rVal = Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/client/IntToEnumMapper.java"))
.replace("REPLACEENUMTYPE",target.getTypeName())
.replace("REPLACENAMECAMEL",Utilities.camelCase(target.getName()));
rVal = Utilities.replacePhraseWithPhraseAtIndent(rVal, switchCases, "REPLACECASE");
return rVal;
}
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 = "getIntEnumValueREPLACENAMECAMEL(message.getpropertyValueInt())".replace("REPLACENAMECAMEL",Utilities.camelCase(target.getName()));
} break;
}
String replaced = base
.replace("REPLACE_PROPERTY_ID",target.getId() + "")
.replace("REPLACE_GET_PROPERTY_VALUE",propertyValueFetcher)
.replace("REPLACE_VARIABLE_NAME_CAMEL",Utilities.camelCase(target.getName()));
setCases = setCases + replaced;
}
String rVal = Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/client/ParseBTreeMessages.java"));
rVal = Utilities.replacePhraseWithPhraseAtIndent(rVal, setCases, "REPLACE_WITH_CASES");
return rVal;
}
}

View File

@ -1,31 +0,0 @@
package electrosphere.main.codegen;
import java.io.File;
import org.jboss.forge.roaster.model.source.AnnotationSource;
import org.jboss.forge.roaster.model.source.JavaClassSource;
import electrosphere.main.Main;
/**
* Generates synchronization code. Principally figures out if it's a server or a client btree and handles accordingly.
*/
public class CodeGen {
public static void generateCode(JavaClassSource source, File file, String content) throws Exception {
AnnotationSource<JavaClassSource> mainAnnotation = source.getAnnotation("SynchronizedBehaviorTree");
String bTreeName = mainAnnotation.getStringValue("name");
boolean isServer = Boolean.parseBoolean(mainAnnotation.getStringValue("isServer"));
Main.bTreeIdMap.put(bTreeName,Main.bTreeIterator);
Main.bTreeIterator++;
if(isServer){
ServerGen.generateCode(source, bTreeName, file, content);
} else {
ClientGen.generateCode(source, bTreeName, file, content);
}
}
}

View File

@ -1,316 +0,0 @@
package electrosphere.main.codegen;
import java.io.File;
import java.util.LinkedList;
import java.util.List;
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.JavaClassSource;
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 com.google.common.io.Files;
import electrosphere.main.Main;
import electrosphere.main.targets.NetcodeGenTarget;
import electrosphere.main.targets.TargetFile;
import electrosphere.main.util.Utilities;
/**
* Generates server-side synchronization code
*/
public class ServerGen {
/**
* Main method for replacing source file content with synchronization code
* @param source The roaster source file object
* @param bTreeName The name of this btree
* @param file The file handle for this source file
* @param content The content of the source file
* @throws Exception Can throw an exception if an enum isn't properly annotated
*/
public static void generateCode(JavaClassSource source, String bTreeName, File file, String content) throws Exception {
TargetFile targetFile = new TargetFile(file.getAbsolutePath(), content, bTreeName, source);
StringBuilder outputContent = new StringBuilder(content);
List<NetcodeGenTarget> targets = parseGenerationTargets(targetFile);
//
//Find if there was already a parse network message function
MethodSource<JavaClassSource> parseNetworkMessageFunction = null;
for(MethodSource<JavaClassSource> method : targetFile.getSource().getMethods()){
if(method.getName().equals("parseBTreeMessages")){
parseNetworkMessageFunction = method;
}
}
//
//Code gen for each synchronized variable
//
for(NetcodeGenTarget target : targets){
//
//Look for existing methods
MethodSource<JavaClassSource> setter = null;
MethodSource<JavaClassSource> enumToIntMapper = null;
MethodSource<JavaClassSource> intToEnumMapper = null;
for(MethodSource<JavaClassSource> method : targetFile.getSource().getMethods()){
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;
}
}
//
//check if need to make enum to int mapper function
if(target.getAnnotation().getStringValue("isEnum") != null){
if(target.getAnnotation().getStringValue("enumId") == null){
throw new Exception("Failed to parse enum because enumId is not set on the synchronized field annotation");
}
// int enumId = Integer.parseInt(target.getAnnotation().getStringValue("enumId"));
//
//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.delete(startChar, endChar);
int lineNumber = Utilities.getLineNumber(outputContent.toString(), startChar);
Utilities.insertIntoSource(outputContent, generateEnumToIntMapperCode(target,enumConstNames), lineNumber, 1);
} else {
//generate
int positionJustBeforeClassEnd = targetFile.getSource().getEndPosition() - 1;
int lineNumber = Utilities.getLineNumber(outputContent.toString(), positionJustBeforeClassEnd);
outputContent = Utilities.insertIntoSource(outputContent, generateEnumToIntMapperCode(target,enumConstNames), lineNumber, 1);
}
//
//mapper int->enum
if(intToEnumMapper != null){
//regenerate
int startChar = intToEnumMapper.getStartPosition();
int endChar = intToEnumMapper.getEndPosition();
outputContent = outputContent.delete(startChar, endChar);
int lineNumber = Utilities.getLineNumber(outputContent.toString(), startChar);
Utilities.insertIntoSource(outputContent, generateIntToEnumMapperCode(target,enumConstNames), lineNumber, 1);
} else {
//generate
int positionJustBeforeClassEnd = targetFile.getSource().getEndPosition() - 1;
int lineNumber = Utilities.getLineNumber(outputContent.toString(), positionJustBeforeClassEnd);
outputContent = Utilities.insertIntoSource(outputContent, generateIntToEnumMapperCode(target,enumConstNames), lineNumber, 1);
}
}
//
//generate setter
if(setter != null){
//regenerate
int startChar = setter.getStartPosition();
int endChar = setter.getEndPosition();
outputContent = outputContent.delete(startChar, endChar);
int lineNumber = Utilities.getLineNumber(outputContent.toString(), startChar);
Utilities.insertIntoSource(outputContent, generateSetterCode(targetFile,target.getName(),target), lineNumber, 1);
} else {
//generate
int positionJustBeforeClassEnd = targetFile.getSource().getEndPosition() - 1;
int lineNumber = Utilities.getLineNumber(outputContent.toString(), positionJustBeforeClassEnd);
outputContent = Utilities.insertIntoSource(outputContent, generateSetterCode(targetFile,target.getName(),target), lineNumber, 1);
}
}
//create network message parser for incoming requests to change synchronized variables
//...
//message parser generation
if(parseNetworkMessageFunction == null){
//generate
int positionJustBeforeClassEnd = targetFile.getSource().getEndPosition() - 1;
int lineNumber = Utilities.getLineNumber(outputContent.toString(), positionJustBeforeClassEnd);
outputContent = Utilities.insertIntoSource(outputContent, generateParseBTreeMessages(targetFile, targets), lineNumber, 1);
} else {
//regenerate
int startChar = parseNetworkMessageFunction.getStartPosition();
int endChar = parseNetworkMessageFunction.getEndPosition();
outputContent = outputContent.delete(startChar, endChar);
int lineNumber = Utilities.getLineNumber(outputContent.toString(), startChar);
Utilities.insertIntoSource(outputContent, generateParseBTreeMessages(targetFile, targets), lineNumber, 1);
}
//
//Replace file on disk
Files.write(outputContent.toString().getBytes(), file);
}
static List<NetcodeGenTarget> parseGenerationTargets(TargetFile targetFile){
int targetIdIterator = 0;
List<NetcodeGenTarget> targets = new LinkedList<NetcodeGenTarget>();
for(FieldSource<JavaClassSource> field : targetFile.getSource().getFields()){
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;
}
static String getSetterName(String fieldName){
return "set" + Utilities.camelCase(fieldName);
}
static String getEnumToIntMapperName(String fieldName){
return "getEnumIntValue" + Utilities.camelCase(fieldName);
}
static String getIntToEnumMapperName(String fieldName){
return "getIntEnumValue" + Utilities.camelCase(fieldName);
}
/**
* Generates code for a setter method for a synchronized field
* @param targetFile The target file
* @param variableName The name of the variable being set
* @param target The target
* @return The source code string
*/
static String generateSetterCode(TargetFile targetFile, String variableName, NetcodeGenTarget target){
String messageConstructor = "";
//
//regular types
switch(target.getTypeName()){
case "int": {
messageConstructor = Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/server/SetterInt.java"));
} break;
case "double": {
messageConstructor = Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/server/SetterDouble.java"));
} break;
case "float": {
messageConstructor = Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/server/SetterFloat.java"));
} break;
case "String": {
messageConstructor = Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/server/SetterString.java"));
} break;
}
messageConstructor = messageConstructor
.replace("REPLACEBTREEID",Main.bTreeIdMap.get(targetFile.getName()) + "")
.replace("REPLACEPROPERTYID",target.getId() + "")
.replace("REPLACENAMENOTCAMEL",variableName);
//
//enum type handling
if(target.getAnnotation().getStringValue("isEnum") != null){
messageConstructor = Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/server/SetterEnum.java"))
.replace("REPLACEBTREEID",Main.bTreeIdMap.get(targetFile.getName()) + "")
.replace("REPLACEPROPERTYID",target.getId() + "")
.replace("REPLACENAMECAMEL",Utilities.camelCase(variableName))
.replace("REPLACENAMENOTCAMEL",variableName);
}
//
//returns setter string
String rVal = Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/server/Setter.java"))
.replace("REPLACENAMECAMEL",Utilities.camelCase(variableName))
.replace("REPLACETYPE",target.getTypeName())
.replace("REPLACENAMENOTCAMEL",variableName)
.replace("REPLACEMESSAGECONSTRUCTOR",messageConstructor);
return rVal;
}
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++;
}
String rVal = Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/server/EnumToIntMapper.java"))
.replace("REPLACEENUMTYPE",target.getTypeName())
.replace("REPLACENAMECAMEL",Utilities.camelCase(target.getName()))
.replace("REPLACETYPENAME",target.getTypeName());
rVal = Utilities.replacePhraseWithPhraseAtIndent(rVal, switchCases, "REPLACECASE");
return rVal;
}
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++;
}
String rVal = Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/server/IntToEnumMapper.java"))
.replace("REPLACEENUMTYPE",target.getTypeName())
.replace("REPLACENAMECAMEL",Utilities.camelCase(target.getName()));
rVal = Utilities.replacePhraseWithPhraseAtIndent(rVal, switchCases, "REPLACECASE");
return rVal;
}
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 = "getIntEnumValueREPLACENAMECAMEL(message.getpropertyValueInt())".replace("REPLACENAMECAMEL",Utilities.camelCase(target.getName()));
} break;
}
String replaced = base
.replace("REPLACE_PROPERTY_ID",target.getId() + "")
.replace("REPLACE_GET_PROPERTY_VALUE",propertyValueFetcher)
.replace("REPLACE_VARIABLE_NAME_CAMEL",Utilities.camelCase(target.getName()));
// System.out.println(replaced);
setCases = setCases + replaced;
}
String rVal = Utilities.readBakedResourceToString(Main.class.getResourceAsStream("/server/ParseBTreeMessages.java"));
rVal = Utilities.replacePhraseWithPhraseAtIndent(rVal, setCases, "REPLACE_WITH_CASES");
return rVal;
}
}

View File

@ -1,7 +1,8 @@
package electrosphere.main.structure; package electrosphere.main.core.btree;
import java.util.List; import java.util.List;
import electrosphere.main.core.syncfield.SynchronizedField;
import electrosphere.main.targets.TargetFile; import electrosphere.main.targets.TargetFile;
import electrosphere.main.util.TemplateInjectionUtils; import electrosphere.main.util.TemplateInjectionUtils;
@ -58,26 +59,58 @@ public class BehaviorTree {
this.targetFile = targetFile; this.targetFile = targetFile;
} }
/**
* Gets the name of this behavior tree
* @return The name of this behavior tree
*/
public String getName(){ public String getName(){
return name; return name;
} }
/**
* Gets the id of this behavior tree
* @return The id
*/
public int getId(){
return this.id;
}
/**
* Gets the class name of this behavior tree
* @return The class name
*/
public String getClassName(){ public String getClassName(){
return className; return className;
} }
/**
* Gets the corresponding tree name for this behavior tree
* @return The corresponding tree's name
*/
public String getCorrespondingTreeName(){ public String getCorrespondingTreeName(){
return correspondingTreeName; return correspondingTreeName;
} }
/**
* Gets whether this is a server behavior tree or not
* @return true if this is a server behavior tree, false otherwise
*/
public boolean isServer(){ public boolean isServer(){
return isServer; return isServer;
} }
/**
* Gets the list of synchronized fields within this behavior tree
* @return The list of synchronized fields within this behavior tree
*/
public List<SynchronizedField> getSynchronizedFields(){ public List<SynchronizedField> getSynchronizedFields(){
return synchronizedFields; return synchronizedFields;
} }
/**
* Gets the target file associated with this behavior tree
* @return The target file
*/
public TargetFile getTargetFile(){ public TargetFile getTargetFile(){
return targetFile; return targetFile;
} }
@ -91,7 +124,12 @@ public class BehaviorTree {
return rVal; return rVal;
} }
public String getAttachMethodContent(boolean isServer){ /**
* Gets the content for the attach method of this behavior tree
* @param isServer true if this is a server behavior tree, false otherwise
* @return The attach method content
*/
public String getAttachMethodContent(){
String templateSource = "/server/AttachBTree.java"; String templateSource = "/server/AttachBTree.java";
if(!isServer){ if(!isServer){
templateSource = "/client/AttachBTree.java"; templateSource = "/client/AttachBTree.java";
@ -100,13 +138,21 @@ public class BehaviorTree {
return rVal; return rVal;
} }
/**
* Gets the detatch method's name
* @return The detatch method's name
*/
public String getDetachMethodName(){ public String getDetachMethodName(){
String rVal = ""; String rVal = "";
rVal = "detachTree"; rVal = "detachTree";
return rVal; return rVal;
} }
public String getDetachMethodContent(boolean isServer){ /**
* Gets the content for the detatch method
* @return The content
*/
public String getDetachMethodContent(){
String templateSource = "/server/DetachBTree.java"; String templateSource = "/server/DetachBTree.java";
if(!isServer){ if(!isServer){
templateSource = "/client/DetachBTree.java"; templateSource = "/client/DetachBTree.java";
@ -115,21 +161,37 @@ public class BehaviorTree {
return rVal; return rVal;
} }
/**
* Gets the fetch method's name
* @return The name
*/
public String getEntityFetchMethodName(){ public String getEntityFetchMethodName(){
String rVal = "get" + className; String rVal = "get" + className;
return rVal; return rVal;
} }
/**
* Gets the content for the fetch method
* @return The content
*/
public String getEntityFetchMethodContent(){ public String getEntityFetchMethodContent(){
String rVal = TemplateInjectionUtils.getFragmentWithReplacement("/btree/EntityFetchMethod.java", this.className, "TREE_" + this.name.toUpperCase()); String rVal = TemplateInjectionUtils.getFragmentWithReplacement("/btree/EntityFetchMethod.java", this.className, "TREE_" + this.name.toUpperCase());
return rVal; return rVal;
} }
/**
* Gets the constructor method's name
* @return The constructor method's name
*/
public String getConstructorMethodName(){ public String getConstructorMethodName(){
String rVal = className; String rVal = className;
return rVal; return rVal;
} }
/**
* Gets the constructor method's content
* @return The content
*/
public String getConstructorMethodContent(){ public String getConstructorMethodContent(){
String rVal = TemplateInjectionUtils.getFragmentWithReplacement("/btree/Constructor.java", this.className); String rVal = TemplateInjectionUtils.getFragmentWithReplacement("/btree/Constructor.java", this.className);
return rVal; return rVal;

View File

@ -1,10 +1,12 @@
package electrosphere.main.structure; package electrosphere.main.core.enums;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import com.google.common.io.Files; import com.google.common.io.Files;
import electrosphere.main.core.btree.BehaviorTree;
import electrosphere.main.project.ProjectStructure;
import electrosphere.main.util.ClassSourceUtils; import electrosphere.main.util.ClassSourceUtils;
/** /**
@ -49,8 +51,8 @@ public class BTreeIdEnum {
source = source + "\n"; source = source + "\n";
source = source + ClassSourceUtils.generateClassHeader("BehaviorTreeIdEnums", "List of enums for each automatically synchronized behavior tree.", true); source = source + ClassSourceUtils.generateClassHeader("BehaviorTreeIdEnums", "List of enums for each automatically synchronized behavior tree.", true);
source = source + "\n"; source = source + "\n";
for(BehaviorTree tree : structure.behaviorTrees){ for(BehaviorTree tree : structure.getBehaviorTrees()){
source = source + " public static final int " + getTreeIdEnum(tree) + " = " + tree.id + ";\n"; source = source + " public static final int " + getTreeIdEnum(tree) + " = " + tree.getId() + ";\n";
} }
source = source + "\n"; source = source + "\n";
source = source + ClassSourceUtils.generateClassEnd(); source = source + ClassSourceUtils.generateClassEnd();
@ -68,7 +70,7 @@ public class BTreeIdEnum {
* @return the name * @return the name
*/ */
public static String getTreeIdEnum(BehaviorTree tree){ public static String getTreeIdEnum(BehaviorTree tree){
return "BTREE_" + tree.name.toUpperCase() + "_ID"; return "BTREE_" + tree.getName().toUpperCase() + "_ID";
} }
} }

View File

@ -1,10 +1,12 @@
package electrosphere.main.structure; package electrosphere.main.core.enums;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import com.google.common.io.Files; import com.google.common.io.Files;
import electrosphere.main.core.syncfield.SynchronizedField;
import electrosphere.main.project.ProjectStructure;
import electrosphere.main.util.ClassSourceUtils; import electrosphere.main.util.ClassSourceUtils;
/** /**
@ -50,8 +52,8 @@ public class FieldIdEnum {
source = source + "\n"; source = source + "\n";
source = source + ClassSourceUtils.generateClassHeader("FieldIdEnums", "List of enums of all fields and their associated ids.", true); source = source + ClassSourceUtils.generateClassHeader("FieldIdEnums", "List of enums of all fields and their associated ids.", true);
source = source + "\n"; source = source + "\n";
for(SynchronizedField field : structure.synchronizedFields){ for(SynchronizedField field : structure.getSynchronizedFields()){
source = source + " public static final int " + getFieldIdEnum(field) + " = " + field.id + ";\n"; source = source + " public static final int " + getFieldIdEnum(field) + " = " + field.getId() + ";\n";
} }
source = source + "\n"; source = source + "\n";
source = source + ClassSourceUtils.generateClassEnd(); source = source + ClassSourceUtils.generateClassEnd();
@ -69,7 +71,7 @@ public class FieldIdEnum {
* @return the name * @return the name
*/ */
public static String getFieldIdEnum(SynchronizedField field){ public static String getFieldIdEnum(SynchronizedField field){
return "TREE_" + field.parent.name.toUpperCase() + "_SYNCEDFIELD_" + field.fieldName.toUpperCase() + "_ID"; return "TREE_" + field.getParent().getName().toUpperCase() + "_SYNCEDFIELD_" + field.getFieldName().toUpperCase() + "_ID";
} }
} }

View File

@ -1,5 +1,7 @@
package electrosphere.main.structure; package electrosphere.main.core.syncfield;
import electrosphere.main.core.btree.BehaviorTree;
import electrosphere.main.project.ProjectStructure;
import electrosphere.main.targets.TargetFile; import electrosphere.main.targets.TargetFile;
import electrosphere.main.util.TemplateInjectionUtils; import electrosphere.main.util.TemplateInjectionUtils;
import electrosphere.main.util.Utilities; import electrosphere.main.util.Utilities;
@ -71,8 +73,8 @@ public class SynchronizedField {
public String getServerSetterContent(ProjectStructure structure){ public String getServerSetterContent(ProjectStructure structure){
String rVal = null; String rVal = null;
String bTreeIdVariable = "BehaviorTreeIdEnums.BTREE_" + this.parent.name.toUpperCase() + "_ID"; String bTreeIdVariable = "BehaviorTreeIdEnums.BTREE_" + this.parent.getName().toUpperCase() + "_ID";
String fieldIdVariable = "FieldIdEnums.TREE_" + this.parent.name.toUpperCase() + "_SYNCEDFIELD_" + this.fieldName.toUpperCase() + "_ID"; String fieldIdVariable = "FieldIdEnums.TREE_" + this.parent.getName().toUpperCase() + "_SYNCEDFIELD_" + this.fieldName.toUpperCase() + "_ID";
switch(typeName){ switch(typeName){
case "long": { case "long": {
String packetContentFiller = " DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage(SynchronizationMessage.constructUpdateClientLongStateMessage(parent.getId(), " + bTreeIdVariable + ", " + fieldIdVariable + ", " + fieldName + "));"; String packetContentFiller = " DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage(SynchronizationMessage.constructUpdateClientLongStateMessage(parent.getId(), " + bTreeIdVariable + ", " + fieldIdVariable + ", " + fieldName + "));";
@ -110,4 +112,36 @@ public class SynchronizedField {
return rVal; return rVal;
} }
/**
* Gets the id of this field
* @return The id
*/
public int getId(){
return this.id;
}
/**
* Gets the name of this field
* @return The name of the field
*/
public String getFieldName(){
return this.fieldName;
}
/**
* Gets the parent behavior tree of this field
* @return The parent behavior tree
*/
public BehaviorTree getParent(){
return this.parent;
}
/**
* Gets the name of the type for this synchronized field
* @return The name of the type
*/
public String getTypeName(){
return this.typeName;
}
} }

View File

@ -1,4 +1,4 @@
package electrosphere.main.structure; package electrosphere.main.core.syncfield;
import java.util.List; import java.util.List;
@ -115,4 +115,12 @@ public class SynchronizedType {
return getTargetFile().getName().substring(0, getTargetFile().getName().length() - 5); return getTargetFile().getName().substring(0, getTargetFile().getName().length() - 5);
} }
/**
* The name of the type
* @return The name
*/
public String getName(){
return this.name;
}
} }

View File

@ -1,4 +1,4 @@
package electrosphere.main.structure; package electrosphere.main.project;
import java.io.File; import java.io.File;
import java.util.Collection; import java.util.Collection;
@ -15,6 +15,12 @@ import org.jboss.forge.roaster.model.source.JavaEnumSource;
import org.jboss.forge.roaster.model.source.JavaSource; import org.jboss.forge.roaster.model.source.JavaSource;
import electrosphere.main.Main; import electrosphere.main.Main;
import electrosphere.main.client.ClientSynchronizationManager;
import electrosphere.main.core.btree.BehaviorTree;
import electrosphere.main.core.enums.BTreeIdEnum;
import electrosphere.main.core.enums.FieldIdEnum;
import electrosphere.main.core.syncfield.SynchronizedField;
import electrosphere.main.core.syncfield.SynchronizedType;
import electrosphere.main.targets.TargetFile; import electrosphere.main.targets.TargetFile;
import electrosphere.main.util.ClassSourceUtils; import electrosphere.main.util.ClassSourceUtils;
@ -158,20 +164,20 @@ public class ProjectStructure {
//generate in-class functions for btrees //generate in-class functions for btrees
for(BehaviorTree tree : behaviorTrees){ for(BehaviorTree tree : behaviorTrees){
if(Main.LOG){ if(Main.LOG){
System.out.println("Generating for " + tree.className); System.out.println("Generating for " + tree.getClassName());
} }
//server side getter + setter //server side getter + setter
if(tree.isServer){ if(tree.isServer()){
for(SynchronizedField field : tree.synchronizedFields){ for(SynchronizedField field : tree.getSynchronizedFields()){
ClassSourceUtils.addOrReplaceMethod(this, tree.getTargetFile(), field.getGetterName(), field.getServerGetterContent()); ClassSourceUtils.addOrReplaceMethod(this, tree.getTargetFile(), field.getGetterName(), field.getServerGetterContent());
ClassSourceUtils.addOrReplaceMethod(this, tree.getTargetFile(), field.getSetterName(), field.getServerSetterContent(this)); ClassSourceUtils.addOrReplaceMethod(this, tree.getTargetFile(), field.getSetterName(), field.getServerSetterContent(this));
} }
//attach + detatch methods //attach + detatch methods
ClassSourceUtils.addMethodIfAbsent(this, tree.getTargetFile(), tree.getAttachMethodName(), tree.getAttachMethodContent(true)); ClassSourceUtils.addMethodIfAbsent(this, tree.getTargetFile(), tree.getAttachMethodName(), tree.getAttachMethodContent());
ClassSourceUtils.addOrReplaceMethod(this, tree.getTargetFile(), tree.getDetachMethodName(), tree.getDetachMethodContent(true)); ClassSourceUtils.addOrReplaceMethod(this, tree.getTargetFile(), tree.getDetachMethodName(), tree.getDetachMethodContent());
//imports //imports
ClassSourceUtils.importClass(this, tree.getTargetFile(), "electrosphere.engine.Globals"); ClassSourceUtils.importClass(this, tree.getTargetFile(), "electrosphere.engine.Globals");
ClassSourceUtils.importClass(this, tree.getTargetFile(), "electrosphere.server.datacell.utils.DataCellSearchUtils"); ClassSourceUtils.importClass(this, tree.getTargetFile(), "electrosphere.server.datacell.utils.DataCellSearchUtils");
@ -186,13 +192,13 @@ public class ProjectStructure {
for(SynchronizedField field : tree.synchronizedFields){ for(SynchronizedField field : tree.getSynchronizedFields()){
ClassSourceUtils.addOrReplaceMethod(this, tree.getTargetFile(), field.getGetterName(), field.getClientGetterContent()); ClassSourceUtils.addOrReplaceMethod(this, tree.getTargetFile(), field.getGetterName(), field.getClientGetterContent());
ClassSourceUtils.addOrReplaceMethod(this, tree.getTargetFile(), field.getSetterName(), field.getClientSetterContent(this)); ClassSourceUtils.addOrReplaceMethod(this, tree.getTargetFile(), field.getSetterName(), field.getClientSetterContent(this));
} }
//attach + detatch methods //attach + detatch methods
ClassSourceUtils.addMethodIfAbsent(this, tree.getTargetFile(), tree.getAttachMethodName(), tree.getAttachMethodContent(false)); ClassSourceUtils.addMethodIfAbsent(this, tree.getTargetFile(), tree.getAttachMethodName(), tree.getAttachMethodContent());
ClassSourceUtils.addOrReplaceMethod(this, tree.getTargetFile(), tree.getDetachMethodName(), tree.getDetachMethodContent(false)); ClassSourceUtils.addOrReplaceMethod(this, tree.getTargetFile(), tree.getDetachMethodName(), tree.getDetachMethodContent());
//imports //imports
ClassSourceUtils.importClass(this, tree.getTargetFile(), "electrosphere.engine.Globals"); // for client scene wrapper ClassSourceUtils.importClass(this, tree.getTargetFile(), "electrosphere.engine.Globals"); // for client scene wrapper
ClassSourceUtils.importClass(this, tree.getTargetFile(), "electrosphere.entity.Entity"); ClassSourceUtils.importClass(this, tree.getTargetFile(), "electrosphere.entity.Entity");
@ -249,7 +255,7 @@ public class ProjectStructure {
*/ */
public SynchronizedType getType(String typeName){ public SynchronizedType getType(String typeName){
for(SynchronizedType type : this.synchronizedTypes){ for(SynchronizedType type : this.synchronizedTypes){
if(type.name.equals(typeName)){ if(type.getName().equals(typeName)){
return type; return type;
} }
} }
@ -263,7 +269,7 @@ public class ProjectStructure {
*/ */
public BehaviorTree getTree(String typeName){ public BehaviorTree getTree(String typeName){
for(BehaviorTree tree : this.behaviorTrees){ for(BehaviorTree tree : this.behaviorTrees){
if(tree.name.equals(typeName)){ if(tree.getName().equals(typeName)){
return tree; return tree;
} }
} }
@ -344,4 +350,20 @@ public class ProjectStructure {
} }
} }
/**
* Gets the list of synchronized fields
* @return The list of synchronized fields
*/
public List<SynchronizedField> getSynchronizedFields(){
return this.synchronizedFields;
}
/**
* Gets the list of all behavior trees
* @return The list of all behavior trees
*/
public List<BehaviorTree> getBehaviorTrees(){
return this.behaviorTrees;
}
} }

View File

@ -1,4 +1,4 @@
package electrosphere.main.structure; package electrosphere.main.server;
/** /**
* This should represent a service placed in project source folder that tracks which trees are attached to which entities and which values they have * This should represent a service placed in project source folder that tracks which trees are attached to which entities and which values they have

View File

@ -1,8 +0,0 @@
package electrosphere.main.structure;
/**
* This should represent a file placed in project source that translates enums to ints and vice-versa
*/
public class TranslatorService {
}

View File

@ -7,7 +7,7 @@ import org.jboss.forge.roaster.model.source.Import;
import org.jboss.forge.roaster.model.source.JavaClassSource; import org.jboss.forge.roaster.model.source.JavaClassSource;
import org.jboss.forge.roaster.model.source.MethodSource; import org.jboss.forge.roaster.model.source.MethodSource;
import electrosphere.main.structure.ProjectStructure; import electrosphere.main.project.ProjectStructure;
import electrosphere.main.targets.TargetFile; import electrosphere.main.targets.TargetFile;
/** /**