state transition packets in synchronization manager
All checks were successful
studiorailgun/highlevel-netcode-gen/pipeline/head This commit looks good

This commit is contained in:
austin 2024-08-02 15:56:58 -04:00
parent e66b36c305
commit 1bb9cb1b35
10 changed files with 323 additions and 20 deletions

View File

@ -1,5 +1,6 @@
package electrosphere.main.client.syncmanager;
import electrosphere.main.client.syncmanager.methods.TransitionBTree;
import electrosphere.main.client.syncmanager.methods.UpdateEntityState;
import electrosphere.main.source.VirtualClass;
import electrosphere.main.targets.TargetFile;
@ -30,6 +31,7 @@ public class ClientSynchronizationManager extends VirtualClass {
//
//
this.addMethod(new UpdateEntityState());
this.addMethod(new TransitionBTree());
}
}

View File

@ -0,0 +1,94 @@
package electrosphere.main.client.syncmanager.methods;
import java.util.LinkedList;
import java.util.List;
import electrosphere.main.core.btree.BehaviorTree;
import electrosphere.main.core.statics.btreeenum.BTreeIdEnum;
import electrosphere.main.core.syncfield.SynchronizedField;
import electrosphere.main.core.syncfield.SynchronizedType;
import electrosphere.main.project.ProjectStructure;
import electrosphere.main.source.VirtualMethod;
import electrosphere.main.util.TemplateInjectionUtils;
import electrosphere.main.util.Utilities;
/**
* Method to apply synchronization packets to behavior trees that require them
*/
public class TransitionBTree implements VirtualMethod {
@Override
public String getName(ProjectStructure projectStructure) {
return "transitionBTree";
}
@Override
public String getContent(ProjectStructure projectStructure) {
String updateCases = "";
for(BehaviorTree clientTree : this.getValidTrees(projectStructure)){
//counterintuitively, want to only update client for server behavior tree ids
if(!clientTree.isServer()){
BehaviorTree serverEquivalent = projectStructure.getTree(clientTree.getCorrespondingTreeName());
updateCases = updateCases + " case BehaviorTreeIdEnums." + BTreeIdEnum.getTreeIdEnum(serverEquivalent) + ": {\n";
updateCases = updateCases + " switch(message.getfieldId()){\n";
for(SynchronizedField field : clientTree.getSynchronizedFields()){
if(field.containsAnnotation("serverSendTransitionPacket")){
String treeName = clientTree.getClassName();
String fieldIdVariable = "TREE_" + serverEquivalent.getName().toUpperCase() + "_SYNCEDFIELD_" + field.getFieldName().toUpperCase() + "_ID";
SynchronizedType type = projectStructure.getType(field.getTypeName());
String typeClass = type.getTargetFile().getSource().getName();
updateCases = updateCases + " case FieldIdEnums." + fieldIdVariable + ":{\n";
updateCases = updateCases + " " + treeName + " tree = " + treeName + ".get" + treeName + "(entity);\n";
updateCases = updateCases + " tree.transition" + Utilities.camelCase(field.getFieldName()) + "(" + typeClass + "." + type.getFromShortConversionMethodName() + "((short)message.getbTreeValue()));\n";
updateCases = updateCases + " } break;\n";
}
}
updateCases = updateCases + " }\n";
updateCases = updateCases + " } break;\n";
}
}
String fullReplacementText = TemplateInjectionUtils.getFragmentWithReplacement("/client/TransitionBTree.java", updateCases);
return fullReplacementText;
}
@Override
public List<String> getImports(ProjectStructure projectStructure) {
List<String> rVal = new LinkedList<String>();
//add server trees
for(BehaviorTree bTree : this.getValidTrees(projectStructure)){
rVal.add(bTree.getTargetFile().getQualifiedPath());
}
return rVal;
}
@Override
public boolean shouldOverwrite() {
return true;
}
/**
* Gets the list of all trees that should be captured in the transition b tree method
* @param projectStructure The project structure
* @return The list
*/
private List<BehaviorTree> getValidTrees(ProjectStructure projectStructure){
List<BehaviorTree> rVal = new LinkedList<BehaviorTree>();
for(BehaviorTree tree : projectStructure.getBehaviorTrees()){
boolean isClient = tree.getName().contains("client");
boolean containsTransitionField = false;
for(SynchronizedField field : tree.getSynchronizedFields()){
if(field.containsAnnotation("serverSendTransitionPacket")){
containsTransitionField = true;
}
}
if(isClient && containsTransitionField){
rVal.add(tree);
}
}
return rVal;
}
}

View File

@ -0,0 +1,61 @@
package electrosphere.main.core.btree.methods;
import java.util.Arrays;
import java.util.List;
import electrosphere.main.core.btree.BehaviorTree;
import electrosphere.main.project.ProjectStructure;
import electrosphere.main.source.VirtualMethod;
import electrosphere.main.util.TemplateInjectionUtils;
import electrosphere.main.util.Utilities;
/**
* Transitions a state variable on the client
*/
public class ClientTransition implements VirtualMethod {
//the name of the field
String fieldName;
//the name of the type of the field
String typeName;
//The parent behavior tree
BehaviorTree parent;
/**
* Constructor
* @param tree The parent behavior tree
* @param typeName The name of the type of the field
* @param fieldName The name of the field
*/
public ClientTransition(BehaviorTree tree, String typeName, String fieldName){
this.parent = tree;
this.typeName = typeName;
this.fieldName = fieldName;
}
@Override
public String getName(ProjectStructure projectStructure) {
return "transition" + Utilities.camelCase(fieldName);
}
@Override
public String getContent(ProjectStructure projectStructure) {
String rVal = TemplateInjectionUtils.getFragmentWithReplacement("/client/Transition.java", fieldName, Utilities.camelCase(fieldName), typeName);
return rVal;
}
@Override
public List<String> getImports(ProjectStructure projectStructure) {
List<String> rVal = Arrays.asList(new String[]{
});
return rVal;
}
@Override
public boolean shouldOverwrite() {
return false;
}
}

View File

@ -4,6 +4,7 @@ import java.util.Arrays;
import java.util.List;
import electrosphere.main.core.btree.BehaviorTree;
import electrosphere.main.core.syncfield.SynchronizedField;
import electrosphere.main.core.syncfield.SynchronizedType;
import electrosphere.main.project.ProjectStructure;
import electrosphere.main.source.VirtualMethod;
@ -43,7 +44,67 @@ public class ServerFieldSetter implements VirtualMethod {
@Override
public String getContent(ProjectStructure projectStructure){
String rVal = null;
String rVal = null;
if(shouldUseStateTransitionFlow(projectStructure)){
rVal = getStateTransitionContent(projectStructure);
} else {
rVal = getImmediatePacketContent(projectStructure);
}
return rVal;
}
@Override
public List<String> getImports(ProjectStructure projectStructure) {
List<String> rVal = Arrays.asList(new String[]{
"electrosphere.net.parser.net.message.SynchronizationMessage",
"electrosphere.server.datacell.utils.DataCellSearchUtils",
"electrosphere.net.synchronization.FieldIdEnums",
});
return rVal;
}
@Override
public boolean shouldOverwrite(){
return true;
}
/**
* Checks if the setter should use the state transition flow or the immediate update flow
* @param projectStructure The project structure
* @return true if should use state transition flow, false for immediate update flow
*/
private boolean shouldUseStateTransitionFlow(ProjectStructure projectStructure){
SynchronizedField field = projectStructure.getField(parent.getName(),fieldName);
if(field.containsAnnotation("serverSendTransitionPacket")){
return true;
} else {
return false;
}
}
/**
* Gets the method content for a setter that uses the state transition flow
* @param projectStructure The project structure
* @return The method content
*/
private String getStateTransitionContent(ProjectStructure projectStructure){
String rVal = null;
String bTreeIdVariable = "BehaviorTreeIdEnums.BTREE_" + this.parent.getName().toUpperCase() + "_ID";
String fieldIdVariable = "FieldIdEnums.TREE_" + this.parent.getName().toUpperCase() + "_SYNCEDFIELD_" + this.fieldName.toUpperCase() + "_ID";
SynchronizedType type = projectStructure.getType(typeName);
String packetContentFiller = " int value = " + type.getContainingClassName() + "." + type.getToShortConversionMethodName() + "(" + fieldName + ");\n";
packetContentFiller = packetContentFiller + " DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage(SynchronizationMessage.constructServerNotifyBTreeTransitionMessage(parent.getId(), " + bTreeIdVariable + ", " + fieldIdVariable + ", value));";
rVal = TemplateInjectionUtils.getFragmentWithReplacement("/server/Setter.java", fieldName, Utilities.camelCase(fieldName), typeName, packetContentFiller);
return rVal;
}
/**
* Gets the content for an immediate-update packet based setter
* @param projectStructure The project structure
* @return The method content for an immediate-update packet based setter
*/
private String getImmediatePacketContent(ProjectStructure projectStructure){
String rVal = null;
String bTreeIdVariable = "BehaviorTreeIdEnums.BTREE_" + this.parent.getName().toUpperCase() + "_ID";
String fieldIdVariable = "FieldIdEnums.TREE_" + this.parent.getName().toUpperCase() + "_SYNCEDFIELD_" + this.fieldName.toUpperCase() + "_ID";
switch(typeName){
@ -78,19 +139,4 @@ public class ServerFieldSetter implements VirtualMethod {
return rVal;
}
@Override
public List<String> getImports(ProjectStructure projectStructure) {
List<String> rVal = Arrays.asList(new String[]{
"electrosphere.net.parser.net.message.SynchronizationMessage",
"electrosphere.server.datacell.utils.DataCellSearchUtils",
"electrosphere.net.synchronization.FieldIdEnums",
});
return rVal;
}
@Override
public boolean shouldOverwrite(){
return true;
}
}

View File

@ -1,5 +1,8 @@
package electrosphere.main.core.syncfield;
import java.util.HashMap;
import java.util.Map;
import electrosphere.main.core.btree.BehaviorTree;
import electrosphere.main.targets.TargetFile;
import electrosphere.main.util.Utilities;
@ -24,6 +27,9 @@ public class SynchronizedField {
//The parent behavior tree
BehaviorTree parent;
//The map of annotations applied to this field
Map<String,Object> annotations = new HashMap<String,Object>();
/**
* Constructor
* @param id
@ -99,4 +105,31 @@ public class SynchronizedField {
return this.typeName;
}
/**
* Adds an annoration to this field
* @param annotationName The name of the annotation
* @param annotationValue The value of the annotation
*/
public void addAnnotation(String annotationName, Object annotationValue){
this.annotations.put(annotationName, annotationValue);
}
/**
* Gets the value of an annotation applied to this field
* @param annotationName The name of the annotation
* @return The value of the annotation
*/
public Object getAnnotation(String annotationName){
return this.annotations.get(annotationName);
}
/**
* Gets whether this field has an annotation or not
* @param annotationName The name of the annotation
* @return true if the field has the annotation, false otherwise
*/
public boolean containsAnnotation(String annotationName){
return this.annotations.containsKey(annotationName);
}
}

View File

@ -161,6 +161,16 @@ public class ProjectStructure {
return mainParser.getTree(typeName);
}
/**
* Gets a synchronized field from its name
* @param treeName The name of the tree that contains the field
* @param fieldName The name of the field
* @return The field if it exists, null otherwise
*/
public SynchronizedField getField(String treeName, String fieldName){
return mainParser.getField(treeName, fieldName);
}
/**
* Gets the list of synchronized fields
* @return The list of synchronized fields

View File

@ -6,6 +6,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.jboss.forge.roaster.model.ValuePair;
import org.jboss.forge.roaster.model.source.AnnotationSource;
import org.jboss.forge.roaster.model.source.FieldSource;
import org.jboss.forge.roaster.model.source.JavaClassSource;
@ -48,6 +49,7 @@ public class FieldParser {
String typeName = fieldSource.getType().getName();
int fieldId = getFieldId(bTreeName,fieldName);
SynchronizedField field = new SynchronizedField(fieldId,fieldName,typeName,target);
scrapeAnnotations(field,syncAnnotation);
this.synchronizedFields.add(field);
rVal.add(field);
}
@ -64,11 +66,14 @@ public class FieldParser {
}
/**
* Gets the list of synchronized fields
* @return The list of synchronized fields
* Scrapes all values from the main annotation and puts them inside the field
* @param field The field
* @param mainAnnotation The main annotation
*/
public List<SynchronizedField> getSynchronizedFields(){
return this.synchronizedFields;
private void scrapeAnnotations(SynchronizedField field, AnnotationSource<JavaClassSource> mainAnnotation){
for(ValuePair value : mainAnnotation.getValues()){
field.addAnnotation(value.getName(), value.getStringValue());
}
}
/**
@ -112,4 +117,12 @@ public class FieldParser {
}
}
/**
* Gets the list of synchronized fields
* @return The list of synchronized fields
*/
public List<SynchronizedField> getSynchronizedFields(){
return this.synchronizedFields;
}
}

View File

@ -5,6 +5,7 @@ import java.util.List;
import electrosphere.main.core.VirtualProject;
import electrosphere.main.core.btree.BehaviorTree;
import electrosphere.main.core.btree.methods.ClientFieldSetter;
import electrosphere.main.core.btree.methods.ClientTransition;
import electrosphere.main.core.btree.methods.FromTypeConversion;
import electrosphere.main.core.btree.methods.ServerFieldSetter;
import electrosphere.main.core.btree.methods.ToTypeConversion;
@ -88,6 +89,9 @@ public class MainParser {
tree.addMethod(new ServerFieldSetter(tree, field.getTypeName(), field.getFieldName()));
} else {
tree.addMethod(new ClientFieldSetter(tree, field.getTypeName(), field.getFieldName()));
if(field.containsAnnotation("serverSendTransitionPacket")){
tree.addMethod(new ClientTransition(tree, field.getTypeName(), field.getFieldName()));
}
}
}
for(SynchronizedType type : types){
@ -126,6 +130,21 @@ public class MainParser {
return null;
}
/**
* Gets a synchronized field from its name
* @param treeName The name of the tree that contains the field
* @param fieldName The name of the field
* @return The field if it exists, null otherwise
*/
public SynchronizedField getField(String treeName, String fieldName){
for(SynchronizedField field : this.fieldParser.getSynchronizedFields()){
if(field.getFieldName().equals(fieldName) && field.getParent().getName() == treeName){
return field;
}
}
return null;
}
/**
* Gets the list of synchronized fields
* @return The list of synchronized fields

View File

@ -0,0 +1,11 @@
/**
* <p> (Initially) Automatically Generated </p>
* <p>
* Performs a state transition on a client state variable.
* Will be triggered when a server performs a state change.
* </p>
* @param newREPLACE_1_ME The new value of the state
*/
public void transitionREPLACE_1_ME(REPLACE_2_ME newREPLACE_1_ME){
this.setREPLACE_1_ME(newREPLACE_1_ME);
}

View File

@ -0,0 +1,14 @@
/**
* <p> Automatically generated </p>
* <p>
* Transitions a behavior tree to a new state
* </p>
* @param entity The entity
* @param bTreeId The id of the behavior tree
* @param message The raw synchronization message holding the update data
*/
private void transitionBTree(Entity entity, int bTreeId, SynchronizationMessage message){
switch(bTreeId){
REPLACE_0_ME
}
}