From 1bb9cb1b35e2afd7d6b61562a8ca9b69666eaf23 Mon Sep 17 00:00:00 2001 From: austin Date: Fri, 2 Aug 2024 15:56:58 -0400 Subject: [PATCH] state transition packets in synchronization manager --- .../ClientSynchronizationManager.java | 2 + .../syncmanager/methods/TransitionBTree.java | 94 +++++++++++++++++++ .../core/btree/methods/ClientTransition.java | 61 ++++++++++++ .../core/btree/methods/ServerFieldSetter.java | 78 +++++++++++---- .../core/syncfield/SynchronizedField.java | 33 +++++++ .../main/project/ProjectStructure.java | 10 ++ .../main/project/parsers/FieldParser.java | 21 ++++- .../main/project/parsers/MainParser.java | 19 ++++ src/main/resources/client/Transition.java | 11 +++ .../resources/client/TransitionBTree.java | 14 +++ 10 files changed, 323 insertions(+), 20 deletions(-) create mode 100644 src/main/java/electrosphere/main/client/syncmanager/methods/TransitionBTree.java create mode 100644 src/main/java/electrosphere/main/core/btree/methods/ClientTransition.java create mode 100644 src/main/resources/client/Transition.java create mode 100644 src/main/resources/client/TransitionBTree.java diff --git a/src/main/java/electrosphere/main/client/syncmanager/ClientSynchronizationManager.java b/src/main/java/electrosphere/main/client/syncmanager/ClientSynchronizationManager.java index b931757..714be5c 100644 --- a/src/main/java/electrosphere/main/client/syncmanager/ClientSynchronizationManager.java +++ b/src/main/java/electrosphere/main/client/syncmanager/ClientSynchronizationManager.java @@ -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()); } } diff --git a/src/main/java/electrosphere/main/client/syncmanager/methods/TransitionBTree.java b/src/main/java/electrosphere/main/client/syncmanager/methods/TransitionBTree.java new file mode 100644 index 0000000..8e69189 --- /dev/null +++ b/src/main/java/electrosphere/main/client/syncmanager/methods/TransitionBTree.java @@ -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 getImports(ProjectStructure projectStructure) { + List rVal = new LinkedList(); + + //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 getValidTrees(ProjectStructure projectStructure){ + List rVal = new LinkedList(); + + 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; + } + +} diff --git a/src/main/java/electrosphere/main/core/btree/methods/ClientTransition.java b/src/main/java/electrosphere/main/core/btree/methods/ClientTransition.java new file mode 100644 index 0000000..d015580 --- /dev/null +++ b/src/main/java/electrosphere/main/core/btree/methods/ClientTransition.java @@ -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 getImports(ProjectStructure projectStructure) { + List rVal = Arrays.asList(new String[]{ + }); + return rVal; + } + + @Override + public boolean shouldOverwrite() { + return false; + } + +} diff --git a/src/main/java/electrosphere/main/core/btree/methods/ServerFieldSetter.java b/src/main/java/electrosphere/main/core/btree/methods/ServerFieldSetter.java index c7b3993..603dbc7 100644 --- a/src/main/java/electrosphere/main/core/btree/methods/ServerFieldSetter.java +++ b/src/main/java/electrosphere/main/core/btree/methods/ServerFieldSetter.java @@ -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 getImports(ProjectStructure projectStructure) { + List 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 getImports(ProjectStructure projectStructure) { - List 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; - } - } diff --git a/src/main/java/electrosphere/main/core/syncfield/SynchronizedField.java b/src/main/java/electrosphere/main/core/syncfield/SynchronizedField.java index f2bf089..4913543 100644 --- a/src/main/java/electrosphere/main/core/syncfield/SynchronizedField.java +++ b/src/main/java/electrosphere/main/core/syncfield/SynchronizedField.java @@ -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 annotations = new HashMap(); + /** * 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); + } + } diff --git a/src/main/java/electrosphere/main/project/ProjectStructure.java b/src/main/java/electrosphere/main/project/ProjectStructure.java index 7a11b01..0db5558 100644 --- a/src/main/java/electrosphere/main/project/ProjectStructure.java +++ b/src/main/java/electrosphere/main/project/ProjectStructure.java @@ -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 diff --git a/src/main/java/electrosphere/main/project/parsers/FieldParser.java b/src/main/java/electrosphere/main/project/parsers/FieldParser.java index 429f0f3..f98b3d9 100644 --- a/src/main/java/electrosphere/main/project/parsers/FieldParser.java +++ b/src/main/java/electrosphere/main/project/parsers/FieldParser.java @@ -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 getSynchronizedFields(){ - return this.synchronizedFields; + private void scrapeAnnotations(SynchronizedField field, AnnotationSource mainAnnotation){ + for(ValuePair value : mainAnnotation.getValues()){ + field.addAnnotation(value.getName(), value.getStringValue()); + } } /** @@ -111,5 +116,13 @@ public class FieldParser { return fieldIdIterator; } } + + /** + * Gets the list of synchronized fields + * @return The list of synchronized fields + */ + public List getSynchronizedFields(){ + return this.synchronizedFields; + } } diff --git a/src/main/java/electrosphere/main/project/parsers/MainParser.java b/src/main/java/electrosphere/main/project/parsers/MainParser.java index 8ee6768..3b24e68 100644 --- a/src/main/java/electrosphere/main/project/parsers/MainParser.java +++ b/src/main/java/electrosphere/main/project/parsers/MainParser.java @@ -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 diff --git a/src/main/resources/client/Transition.java b/src/main/resources/client/Transition.java new file mode 100644 index 0000000..4e7af64 --- /dev/null +++ b/src/main/resources/client/Transition.java @@ -0,0 +1,11 @@ +/** + *

(Initially) Automatically Generated

+ *

+ * Performs a state transition on a client state variable. + * Will be triggered when a server performs a state change. + *

+ * @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); +} \ No newline at end of file diff --git a/src/main/resources/client/TransitionBTree.java b/src/main/resources/client/TransitionBTree.java new file mode 100644 index 0000000..7c4360d --- /dev/null +++ b/src/main/resources/client/TransitionBTree.java @@ -0,0 +1,14 @@ +/** + *

Automatically generated

+ *

+ * Transitions a behavior tree to a new state + *

+ * @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 + } +} \ No newline at end of file