Ver Fonte

行为树可以自动布局,还有个小bug

tanghai há 14 anos atrás
pai
commit
44228bf506

+ 2 - 2
CSharp/Infrastructure/AutoPopulateExportedViewsBehavior.cs

@@ -21,8 +21,8 @@ using Microsoft.Practices.Prism.Regions;
 
 namespace Infrastructure
 {
-	[Export(typeof (AutoPopulateExportedViewsBehavior))]
-	[PartCreationPolicy(CreationPolicy.NonShared)]
+	[Export(typeof (AutoPopulateExportedViewsBehavior)), PartCreationPolicy(CreationPolicy.NonShared)]
+	
 	public class AutoPopulateExportedViewsBehavior : RegionBehavior, IPartImportsSatisfiedNotification
 	{
 		[ImportMany(AllowRecomposition = true)]

+ 2 - 2
CSharp/Infrastructure/ViewExportAttribute.cs

@@ -20,8 +20,8 @@ using System.ComponentModel.Composition;
 
 namespace Infrastructure
 {
-	[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
-	[MetadataAttribute]
+	[AttributeUsage(AttributeTargets.Class, AllowMultiple = false), MetadataAttribute]
+	
 	public class ViewExportAttribute : ExportAttribute, IViewRegionRegistration
 	{
 		public ViewExportAttribute() : base(typeof (object))

+ 55 - 50
CSharp/Modules/BehaviorTree/BehaviorTreeLayout.cs

@@ -1,88 +1,83 @@
-namespace BehaviorTree
+using NLog;
+
+namespace BehaviorTree
 {
 	public class BehaviorTreeLayout
 	{
 		private const double XGap = 20;
 		private const double YGap = 10;
+		private static readonly Logger logger = LogManager.GetCurrentClassLogger();
 
-		private static void CountPrelim(TreeNodeViewModel treeNode)
+		private static void CountPrelimAndModify(TreeNodeViewModel treeNode)
 		{
-			if (treeNode.Index == 0)
+			foreach (TreeNodeViewModel node in treeNode.Children)
 			{
-				treeNode.Prelim = treeNode.Index * (TreeNodeViewModel.Width + XGap);
-				return;
+				CountPrelimAndModify(node);
 			}
 
-			double childrenCenter;
-			if (treeNode.Children.Count > 0)
-			{
-				int maxIndex = treeNode.Children.Count - 1;
-				childrenCenter = (treeNode.Children[0].Prelim + treeNode.Children[maxIndex].Prelim) / 2;
-			}
-			else
-			{
-				childrenCenter = 0;
-			}
-			treeNode.Prelim = childrenCenter;
-		}
+			double prelim = 0;
+			double modify = 0;
 
-		private static void CountModify(TreeNodeViewModel treeNode, double prelim)
-		{
 			double childrenCenter = 0;
-			if (treeNode.Children.Count > 0)
+			if (!treeNode.IsLeaf)
 			{
-				int maxIndex = treeNode.Children.Count - 1;
-				childrenCenter = (treeNode.Children[0].Prelim + treeNode.Children[maxIndex].Prelim) / 2;
+				childrenCenter = (treeNode.LeftMostChild.Prelim + treeNode.RightMostChild.Prelim) / 2;
 			}
-			treeNode.Modify = prelim - childrenCenter;
-		}
-
-		private static void CountPrelimAndModify(TreeNodeViewModel treeNode)
-		{
-			CountPrelim(treeNode);
-			CountModify(treeNode, treeNode.Prelim);
 
-			foreach (TreeNodeViewModel node in treeNode.Children)
+			if (treeNode.Index == 0)
 			{
-				CountPrelimAndModify(node);
+				// 如果没有左邻居,不需要设置modify
+				prelim = childrenCenter;
 			}
+			else
+			{
+				prelim = treeNode.Index * (TreeNodeViewModel.Width + XGap) + treeNode.Parent.LeftMostChild.Prelim;
+				modify = prelim - childrenCenter;
+			}
+			treeNode.Prelim = prelim;
+			treeNode.Modify = modify;
+
+			logger.Debug("Num: " + treeNode.Num + " Prelim: " + treeNode.Prelim + " Modify: " + treeNode.Modify);
 		}
 
 		private static void AjustTwoSubTreeGap(TreeNodeViewModel left, TreeNodeViewModel right)
 		{
-			if (left.IsLeaf || right.IsLeaf)
-			{
-				return;
-			}
 			double offset = 0;
 			TreeNodeViewModel tLeft = left;
 			TreeNodeViewModel tRight = right;
 			double leftTreeModify = 0;
 			double rightTreeModify = 0;
-			for (int i = 0;; ++i)
+			for (int i = 0; ; ++i)
 			{
-				leftTreeModify += tLeft.Modify;
-				rightTreeModify += tRight.Modify;
-
-				tLeft = tLeft.RightMostChild;
-				tRight = tRight.LeftMostChild;
-
 				double tGap = (tRight.Prelim + rightTreeModify) - (tLeft.Prelim + leftTreeModify);
-				if (tGap - XGap - TreeNodeViewModel.Width > offset)
+				if (XGap + TreeNodeViewModel.Width - tGap > offset)
 				{
-					offset = tGap - XGap - TreeNodeViewModel.Width;
+					offset = XGap + TreeNodeViewModel.Width - tGap;
 				}
 
 				if (tLeft.IsLeaf || tRight.IsLeaf)
 				{
 					break;
 				}
+				leftTreeModify += tLeft.Modify;
+				rightTreeModify += tRight.Modify;
+				tLeft = tLeft.RightMostChild;
+				tRight = tRight.LeftMostChild;
 			}
 			right.Modify += offset;
+			right.Prelim += offset;
 		}
 
 		private static void AjustTreeGap(TreeNodeViewModel treeNode)
 		{
+			if (treeNode.IsLeaf)
+			{
+				return;
+			}
+			foreach (var child in treeNode.Children)
+			{
+				AjustTreeGap(child);
+			}
 			for (int i = 0; i < treeNode.Children.Count - 1; ++i)
 			{
 				var left = treeNode.Children[i];
@@ -91,22 +86,32 @@
 			}
 		}
 
-		private static void ApplyXY(int level, TreeNodeViewModel treeNode)
+		private static void ApplyXY(TreeNodeViewModel treeNode, int level, double totalModify)
 		{
-			treeNode.X = treeNode.Prelim + treeNode.Modify;
-			treeNode.Y = level * (TreeNodeViewModel.Height + YGap);
-			++level;
 			foreach (TreeNodeViewModel node in treeNode.Children)
 			{
-				ApplyXY(level, node);
+				ApplyXY(node, level + 1, treeNode.Modify + totalModify);
 			}
+			if (treeNode.IsLeaf)
+			{
+				treeNode.X = treeNode.Prelim + totalModify;
+			}
+			else
+			{
+				treeNode.X = (treeNode.LeftMostChild.X + treeNode.RightMostChild.X) / 2;
+			}
+			treeNode.Y = level * (TreeNodeViewModel.Height + YGap);
 		}
 
 		public static void ExcuteLayout(TreeNodeViewModel root)
 		{
+			if (root == null)
+			{
+				return;
+			}
 			CountPrelimAndModify(root);
 			AjustTreeGap(root);
-			ApplyXY(0, root);
+			ApplyXY(root, 0, 0);
 		}
 	}
 }

+ 20 - 9
CSharp/Modules/BehaviorTree/BehaviorTreeView.xaml

@@ -1,9 +1,9 @@
 <UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-			 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-			 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
-			 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
-			 x:Class="BehaviorTree.BehaviorTreeView"
-			 mc:Ignorable="d" d:DesignHeight="600" d:DesignWidth="800">
+		xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+		xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+		xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
+		x:Class="BehaviorTree.BehaviorTreeView"
+		mc:Ignorable="d" d:DesignHeight="600" d:DesignWidth="800">
 	<UserControl.Resources>
 		<LinearGradientBrush x:Key="treeNodeFillBrush" StartPoint="0,0" EndPoint="0,1">
 			<GradientStop Color="White" Offset="0" />
@@ -20,9 +20,9 @@
 	<UserControl.ContextMenu>
 		<ContextMenu>
 			<MenuItem Header="New" Command="ApplicationCommands.New"
-					  CommandTarget="{Binding Path=PlacementTarget, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
+					CommandTarget="{Binding Path=PlacementTarget, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
 			<MenuItem Header="Delete" Command="ApplicationCommands.Delete"
-					  CommandTarget="{Binding Path=PlacementTarget, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
+					CommandTarget="{Binding Path=PlacementTarget, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
 		</ContextMenu>
 	</UserControl.ContextMenu>
 	<Grid>
@@ -42,9 +42,20 @@
 				<DataTemplate>
 					<Canvas MouseDown="ListBoxItem_MouseDown" MouseUp="ListBoxItem_MouseUp" MouseMove="ListBoxItem_MouseMove">
 						<Rectangle Name="rectNode" Width="{Binding Width}" Height="{Binding Height}" Cursor="Hand" StrokeThickness="4"
-								   RadiusX="4" RadiusY="4" Stroke="{StaticResource treeNodeBorderBrush}" Fill="{StaticResource treeNodeFillBrush}" />
+								RadiusX="4" RadiusY="4" Stroke="{StaticResource treeNodeBorderBrush}" Fill="{StaticResource treeNodeFillBrush}"/>
 						<Line X1="{Binding ConnectorX1}" Y1="{Binding ConnectorY1}" X2="{Binding ConnectorX2}" Y2="{Binding ConnectorY2}"
-							  Stroke="Black" StrokeThickness="2" />
+								Stroke="Black" StrokeThickness="2" />
+						<StackPanel>
+							<StackPanel Orientation="Horizontal">
+								<Label Content="{Binding Num}"></Label>
+								<Label Content="{Binding X}"></Label>
+								<Label Content="{Binding Y}"></Label>
+							</StackPanel>
+							<StackPanel Orientation="Horizontal">
+								<Label Content="{Binding Prelim}"></Label>
+								<Label Content="{Binding Modify}"></Label>
+							</StackPanel>
+						</StackPanel>
 					</Canvas>
 					<DataTemplate.Triggers>
 						<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}, Path=IsSelected}" Value="True">

+ 2 - 2
CSharp/Modules/BehaviorTree/BehaviorTreeView.xaml.cs

@@ -9,8 +9,8 @@ namespace BehaviorTree
 	/// <summary>
 	/// BehaviorTreeView.xaml 的交互逻辑
 	/// </summary>
-	[ViewExport(RegionName = "TreeCanvasRegion")]
-	[PartCreationPolicy(CreationPolicy.NonShared)]
+	[ViewExport(RegionName = "TreeCanvasRegion"), PartCreationPolicy(CreationPolicy.NonShared)]
+	
 	public partial class BehaviorTreeView
 	{
 		private const double DragThreshold = 5;

+ 3 - 3
CSharp/Modules/BehaviorTree/BehaviorTreeViewModel.cs

@@ -3,8 +3,8 @@ using System.ComponentModel.Composition;
 
 namespace BehaviorTree
 {
-	[Export(typeof (BehaviorTreeViewModel))]
-	[PartCreationPolicy(CreationPolicy.NonShared)]
+	[Export(typeof (BehaviorTreeViewModel)), PartCreationPolicy(CreationPolicy.NonShared)]
+	
 	internal class BehaviorTreeViewModel
 	{
 		private readonly ObservableCollection<TreeNodeViewModel> treeNodes = new ObservableCollection<TreeNodeViewModel>();
@@ -21,7 +21,7 @@ namespace BehaviorTree
 		{
 			get
 			{
-				return treeNodes.Count == 0? null : treeNodes[0];
+				return treeNodes.Count == 0 ? null : treeNodes[0];
 			}
 		}
 

+ 1083 - 671
CSharp/Modules/BehaviorTree/Person.pb.cs

@@ -1,688 +1,1100 @@
 // Generated by ProtoGen, Version=2.4.1.473, Culture=neutral, PublicKeyToken=55f7125234beb589.  DO NOT EDIT!
+
 #pragma warning disable 1591, 0612
+
 #region Designer generated code
 
 using pb = global::Google.ProtocolBuffers;
 using pbc = global::Google.ProtocolBuffers.Collections;
 using pbd = global::Google.ProtocolBuffers.Descriptors;
 using scg = global::System.Collections.Generic;
-namespace BehaviorTree {
-  
-  namespace Proto {
-    
-    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
-    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ProtoGen", "2.4.1.473")]
-    public static partial class Person {
-    
-      #region Extension registration
-      public static void RegisterAllExtensions(pb::ExtensionRegistry registry) {
-      }
-      #endregion
-      #region Static variables
-      internal static pbd::MessageDescriptor internal__static_BehaviorTree_Person__Descriptor;
-      internal static pb::FieldAccess.FieldAccessorTable<global::BehaviorTree.Person, global::BehaviorTree.Person.Builder> internal__static_BehaviorTree_Person__FieldAccessorTable;
-      internal static pbd::MessageDescriptor internal__static_BehaviorTree_Group__Descriptor;
-      internal static pb::FieldAccess.FieldAccessorTable<global::BehaviorTree.Group, global::BehaviorTree.Group.Builder> internal__static_BehaviorTree_Group__FieldAccessorTable;
-      #endregion
-      #region Descriptor
-      public static pbd::FileDescriptor Descriptor {
-        get { return descriptor; }
-      }
-      private static pbd::FileDescriptor descriptor;
-      
-      static Person() {
-        byte[] descriptorData = global::System.Convert.FromBase64String(
-            "CgxQZXJzb24ucHJvdG8SDEJlaGF2aW9yVHJlZRokZ29vZ2xlL3Byb3RvYnVm" + 
-            "L2NzaGFycF9vcHRpb25zLnByb3RvIiIKBlBlcnNvbhILCgNudW0YASACKAUS" + 
-            "CwoDYWdlGAIgASgFIi4KBUdyb3VwEiUKB3BlcnNvbnMYASADKAsyFC5CZWhh" + 
-            "dmlvclRyZWUuUGVyc29u");
-        pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) {
-          descriptor = root;
-          internal__static_BehaviorTree_Person__Descriptor = Descriptor.MessageTypes[0];
-          internal__static_BehaviorTree_Person__FieldAccessorTable = 
-              new pb::FieldAccess.FieldAccessorTable<global::BehaviorTree.Person, global::BehaviorTree.Person.Builder>(internal__static_BehaviorTree_Person__Descriptor,
-                  new string[] { "Num", "Age", });
-          internal__static_BehaviorTree_Group__Descriptor = Descriptor.MessageTypes[1];
-          internal__static_BehaviorTree_Group__FieldAccessorTable = 
-              new pb::FieldAccess.FieldAccessorTable<global::BehaviorTree.Group, global::BehaviorTree.Group.Builder>(internal__static_BehaviorTree_Group__Descriptor,
-                  new string[] { "Persons", });
-          return null;
-        };
-        pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
-            new pbd::FileDescriptor[] {
-            global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor, 
-            }, assigner);
-      }
-      #endregion
-      
-    }
-  }
-  #region Messages
-  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-  [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
-  [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ProtoGen", "2.4.1.473")]
-  public sealed partial class Person : pb::GeneratedMessage<Person, Person.Builder> {
-    private Person() { }
-    private static readonly Person defaultInstance = new Person().MakeReadOnly();
-    private static readonly string[] _personFieldNames = new string[] { "age", "num" };
-    private static readonly uint[] _personFieldTags = new uint[] { 16, 8 };
-    public static Person DefaultInstance {
-      get { return defaultInstance; }
-    }
-    
-    public override Person DefaultInstanceForType {
-      get { return DefaultInstance; }
-    }
-    
-    protected override Person ThisMessage {
-      get { return this; }
-    }
-    
-    public static pbd::MessageDescriptor Descriptor {
-      get { return global::BehaviorTree.Proto.Person.internal__static_BehaviorTree_Person__Descriptor; }
-    }
-    
-    protected override pb::FieldAccess.FieldAccessorTable<Person, Person.Builder> InternalFieldAccessors {
-      get { return global::BehaviorTree.Proto.Person.internal__static_BehaviorTree_Person__FieldAccessorTable; }
-    }
-    
-    public const int NumFieldNumber = 1;
-    private bool hasNum;
-    private int num_;
-    public bool HasNum {
-      get { return hasNum; }
-    }
-    public int Num {
-      get { return num_; }
-    }
-    
-    public const int AgeFieldNumber = 2;
-    private bool hasAge;
-    private int age_;
-    public bool HasAge {
-      get { return hasAge; }
-    }
-    public int Age {
-      get { return age_; }
-    }
-    
-    public override bool IsInitialized {
-      get {
-        if (!hasNum) return false;
-        return true;
-      }
-    }
-    
-    public override void WriteTo(pb::ICodedOutputStream output) {
-      int size = SerializedSize;
-      string[] field_names = _personFieldNames;
-      if (hasNum) {
-        output.WriteInt32(1, field_names[1], Num);
-      }
-      if (hasAge) {
-        output.WriteInt32(2, field_names[0], Age);
-      }
-      UnknownFields.WriteTo(output);
-    }
-    
-    private int memoizedSerializedSize = -1;
-    public override int SerializedSize {
-      get {
-        int size = memoizedSerializedSize;
-        if (size != -1) return size;
-        
-        size = 0;
-        if (hasNum) {
-          size += pb::CodedOutputStream.ComputeInt32Size(1, Num);
-        }
-        if (hasAge) {
-          size += pb::CodedOutputStream.ComputeInt32Size(2, Age);
-        }
-        size += UnknownFields.SerializedSize;
-        memoizedSerializedSize = size;
-        return size;
-      }
-    }
-    
-    public static Person ParseFrom(pb::ByteString data) {
-      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
-    }
-    public static Person ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
-      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
-    }
-    public static Person ParseFrom(byte[] data) {
-      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
-    }
-    public static Person ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
-      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
-    }
-    public static Person ParseFrom(global::System.IO.Stream input) {
-      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
-    }
-    public static Person ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
-      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
-    }
-    public static Person ParseDelimitedFrom(global::System.IO.Stream input) {
-      return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
-    }
-    public static Person ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
-      return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
-    }
-    public static Person ParseFrom(pb::ICodedInputStream input) {
-      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
-    }
-    public static Person ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
-      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
-    }
-    private Person MakeReadOnly() {
-      return this;
-    }
+
+namespace BehaviorTree
+{
+	namespace Proto
+	{
+		[global::System.Diagnostics.DebuggerNonUserCodeAttribute(),
+		 global::System.Runtime.CompilerServices.CompilerGeneratedAttribute(),
+		 global::System.CodeDom.Compiler.GeneratedCodeAttribute("ProtoGen", "2.4.1.473")]
     
-    public static Builder CreateBuilder() { return new Builder(); }
-    public override Builder ToBuilder() { return CreateBuilder(this); }
-    public override Builder CreateBuilderForType() { return new Builder(); }
-    public static Builder CreateBuilder(Person prototype) {
-      return new Builder(prototype);
-    }
     
-    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
-    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ProtoGen", "2.4.1.473")]
-    public sealed partial class Builder : pb::GeneratedBuilder<Person, Builder> {
-      protected override Builder ThisBuilder {
-        get { return this; }
-      }
-      public Builder() {
-        result = DefaultInstance;
-        resultIsReadOnly = true;
-      }
-      internal Builder(Person cloneFrom) {
-        result = cloneFrom;
-        resultIsReadOnly = true;
-      }
-      
-      private bool resultIsReadOnly;
-      private Person result;
-      
-      private Person PrepareBuilder() {
-        if (resultIsReadOnly) {
-          Person original = result;
-          result = new Person();
-          resultIsReadOnly = false;
-          MergeFrom(original);
-        }
-        return result;
-      }
-      
-      public override bool IsInitialized {
-        get { return result.IsInitialized; }
-      }
-      
-      protected override Person MessageBeingBuilt {
-        get { return PrepareBuilder(); }
-      }
-      
-      public override Builder Clear() {
-        result = DefaultInstance;
-        resultIsReadOnly = true;
-        return this;
-      }
-      
-      public override Builder Clone() {
-        if (resultIsReadOnly) {
-          return new Builder(result);
-        } else {
-          return new Builder().MergeFrom(result);
-        }
-      }
-      
-      public override pbd::MessageDescriptor DescriptorForType {
-        get { return global::BehaviorTree.Person.Descriptor; }
-      }
-      
-      public override Person DefaultInstanceForType {
-        get { return global::BehaviorTree.Person.DefaultInstance; }
-      }
-      
-      public override Person BuildPartial() {
-        if (resultIsReadOnly) {
-          return result;
-        }
-        resultIsReadOnly = true;
-        return result.MakeReadOnly();
-      }
-      
-      public override Builder MergeFrom(pb::IMessage other) {
-        if (other is Person) {
-          return MergeFrom((Person) other);
-        } else {
-          base.MergeFrom(other);
-          return this;
-        }
-      }
-      
-      public override Builder MergeFrom(Person other) {
-        if (other == global::BehaviorTree.Person.DefaultInstance) return this;
-        PrepareBuilder();
-        if (other.HasNum) {
-          Num = other.Num;
-        }
-        if (other.HasAge) {
-          Age = other.Age;
-        }
-        this.MergeUnknownFields(other.UnknownFields);
-        return this;
-      }
-      
-      public override Builder MergeFrom(pb::ICodedInputStream input) {
-        return MergeFrom(input, pb::ExtensionRegistry.Empty);
-      }
-      
-      public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
-        PrepareBuilder();
-        pb::UnknownFieldSet.Builder unknownFields = null;
-        uint tag;
-        string field_name;
-        while (input.ReadTag(out tag, out field_name)) {
-          if(tag == 0 && field_name != null) {
-            int field_ordinal = global::System.Array.BinarySearch(_personFieldNames, field_name, global::System.StringComparer.Ordinal);
-            if(field_ordinal >= 0)
-              tag = _personFieldTags[field_ordinal];
-            else {
-              if (unknownFields == null) {
-                unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
-              }
-              ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
-              continue;
-            }
-          }
-          switch (tag) {
-            case 0: {
-              throw pb::InvalidProtocolBufferException.InvalidTag();
-            }
-            default: {
-              if (pb::WireFormat.IsEndGroupTag(tag)) {
-                if (unknownFields != null) {
-                  this.UnknownFields = unknownFields.Build();
-                }
-                return this;
-              }
-              if (unknownFields == null) {
-                unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
-              }
-              ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
-              break;
-            }
-            case 8: {
-              result.hasNum = input.ReadInt32(ref result.num_);
-              break;
-            }
-            case 16: {
-              result.hasAge = input.ReadInt32(ref result.age_);
-              break;
-            }
-          }
-        }
-        
-        if (unknownFields != null) {
-          this.UnknownFields = unknownFields.Build();
-        }
-        return this;
-      }
-      
-      
-      public bool HasNum {
-        get { return result.hasNum; }
-      }
-      public int Num {
-        get { return result.Num; }
-        set { SetNum(value); }
-      }
-      public Builder SetNum(int value) {
-        PrepareBuilder();
-        result.hasNum = true;
-        result.num_ = value;
-        return this;
-      }
-      public Builder ClearNum() {
-        PrepareBuilder();
-        result.hasNum = false;
-        result.num_ = 0;
-        return this;
-      }
-      
-      public bool HasAge {
-        get { return result.hasAge; }
-      }
-      public int Age {
-        get { return result.Age; }
-        set { SetAge(value); }
-      }
-      public Builder SetAge(int value) {
-        PrepareBuilder();
-        result.hasAge = true;
-        result.age_ = value;
-        return this;
-      }
-      public Builder ClearAge() {
-        PrepareBuilder();
-        result.hasAge = false;
-        result.age_ = 0;
-        return this;
-      }
-    }
-    static Person() {
-      object.ReferenceEquals(global::BehaviorTree.Proto.Person.Descriptor, null);
-    }
-  }
+		public static partial class Person
+		{
+			#region Extension registration
+
+			public static void RegisterAllExtensions(pb::ExtensionRegistry registry)
+			{
+			}
+
+			#endregion
+
+			#region Static variables
+
+			internal static pbd::MessageDescriptor internal__static_BehaviorTree_Person__Descriptor;
+
+			internal static pb::FieldAccess.FieldAccessorTable<global::BehaviorTree.Person, global::BehaviorTree.Person.Builder>
+					internal__static_BehaviorTree_Person__FieldAccessorTable;
+
+			internal static pbd::MessageDescriptor internal__static_BehaviorTree_Group__Descriptor;
+
+			internal static pb::FieldAccess.FieldAccessorTable<global::BehaviorTree.Group, global::BehaviorTree.Group.Builder>
+					internal__static_BehaviorTree_Group__FieldAccessorTable;
+
+			#endregion
+
+			#region Descriptor
+
+			public static pbd::FileDescriptor Descriptor
+			{
+				get
+				{
+					return descriptor;
+				}
+			}
+
+			private static pbd::FileDescriptor descriptor;
+
+			static Person()
+			{
+				byte[] descriptorData =
+						global::System.Convert.FromBase64String(
+						                                        "CgxQZXJzb24ucHJvdG8SDEJlaGF2aW9yVHJlZRokZ29vZ2xlL3Byb3RvYnVm" +
+						                                        		"L2NzaGFycF9vcHRpb25zLnByb3RvIiIKBlBlcnNvbhILCgNudW0YASACKAUS" +
+						                                        				"CwoDYWdlGAIgASgFIi4KBUdyb3VwEiUKB3BlcnNvbnMYASADKAsyFC5CZWhh" +
+						                                        						"dmlvclRyZWUuUGVyc29u");
+				pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root)
+				                                                          	{
+				                                                          		descriptor = root;
+				                                                          		internal__static_BehaviorTree_Person__Descriptor =
+				                                                          				Descriptor.MessageTypes[0];
+				                                                          		internal__static_BehaviorTree_Person__FieldAccessorTable
+				                                                          				=
+				                                                          				new pb::FieldAccess.FieldAccessorTable
+				                                                          						<global::BehaviorTree.Person,
+				                                                          								global::BehaviorTree.Person.Builder>(
+				                                                          						internal__static_BehaviorTree_Person__Descriptor,
+				                                                          						new string[] {"Num", "Age",});
+				                                                          		internal__static_BehaviorTree_Group__Descriptor =
+				                                                          				Descriptor.MessageTypes[1];
+				                                                          		internal__static_BehaviorTree_Group__FieldAccessorTable
+				                                                          				=
+				                                                          				new pb::FieldAccess.FieldAccessorTable
+				                                                          						<global::BehaviorTree.Group,
+				                                                          								global::BehaviorTree.Group.Builder>(
+				                                                          						internal__static_BehaviorTree_Group__Descriptor,
+				                                                          						new string[] {"Persons",});
+				                                                          		return null;
+				                                                          	};
+				pbd::FileDescriptor.InternalBuildGeneratedFileFrom(
+				                                                   descriptorData,
+				                                                   new pbd::FileDescriptor[]
+				                                                   	{
+				                                                   			global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.
+				                                                   					Descriptor,
+				                                                   	}, assigner);
+			}
+
+			#endregion
+		}
+	}
+
+	#region Messages
+
+	[global::System.Diagnostics.DebuggerNonUserCodeAttribute(),
+	 global::System.Runtime.CompilerServices.CompilerGeneratedAttribute(),
+	 global::System.CodeDom.Compiler.GeneratedCodeAttribute("ProtoGen", "2.4.1.473")]
   
-  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-  [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
-  [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ProtoGen", "2.4.1.473")]
-  public sealed partial class Group : pb::GeneratedMessage<Group, Group.Builder> {
-    private Group() { }
-    private static readonly Group defaultInstance = new Group().MakeReadOnly();
-    private static readonly string[] _groupFieldNames = new string[] { "persons" };
-    private static readonly uint[] _groupFieldTags = new uint[] { 10 };
-    public static Group DefaultInstance {
-      get { return defaultInstance; }
-    }
-    
-    public override Group DefaultInstanceForType {
-      get { return DefaultInstance; }
-    }
-    
-    protected override Group ThisMessage {
-      get { return this; }
-    }
-    
-    public static pbd::MessageDescriptor Descriptor {
-      get { return global::BehaviorTree.Proto.Person.internal__static_BehaviorTree_Group__Descriptor; }
-    }
-    
-    protected override pb::FieldAccess.FieldAccessorTable<Group, Group.Builder> InternalFieldAccessors {
-      get { return global::BehaviorTree.Proto.Person.internal__static_BehaviorTree_Group__FieldAccessorTable; }
-    }
-    
-    public const int PersonsFieldNumber = 1;
-    private pbc::PopsicleList<global::BehaviorTree.Person> persons_ = new pbc::PopsicleList<global::BehaviorTree.Person>();
-    public scg::IList<global::BehaviorTree.Person> PersonsList {
-      get { return persons_; }
-    }
-    public int PersonsCount {
-      get { return persons_.Count; }
-    }
-    public global::BehaviorTree.Person GetPersons(int index) {
-      return persons_[index];
-    }
-    
-    public override bool IsInitialized {
-      get {
-        foreach (global::BehaviorTree.Person element in PersonsList) {
-          if (!element.IsInitialized) return false;
-        }
-        return true;
-      }
-    }
-    
-    public override void WriteTo(pb::ICodedOutputStream output) {
-      int size = SerializedSize;
-      string[] field_names = _groupFieldNames;
-      if (persons_.Count > 0) {
-        output.WriteMessageArray(1, field_names[0], persons_);
-      }
-      UnknownFields.WriteTo(output);
-    }
-    
-    private int memoizedSerializedSize = -1;
-    public override int SerializedSize {
-      get {
-        int size = memoizedSerializedSize;
-        if (size != -1) return size;
-        
-        size = 0;
-        foreach (global::BehaviorTree.Person element in PersonsList) {
-          size += pb::CodedOutputStream.ComputeMessageSize(1, element);
-        }
-        size += UnknownFields.SerializedSize;
-        memoizedSerializedSize = size;
-        return size;
-      }
-    }
-    
-    public static Group ParseFrom(pb::ByteString data) {
-      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
-    }
-    public static Group ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
-      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
-    }
-    public static Group ParseFrom(byte[] data) {
-      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
-    }
-    public static Group ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
-      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
-    }
-    public static Group ParseFrom(global::System.IO.Stream input) {
-      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
-    }
-    public static Group ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
-      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
-    }
-    public static Group ParseDelimitedFrom(global::System.IO.Stream input) {
-      return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
-    }
-    public static Group ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
-      return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
-    }
-    public static Group ParseFrom(pb::ICodedInputStream input) {
-      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
-    }
-    public static Group ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
-      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
-    }
-    private Group MakeReadOnly() {
-      persons_.MakeReadOnly();
-      return this;
-    }
+  
+	public sealed partial class Person : pb::GeneratedMessage<Person, Person.Builder>
+	{
+		private Person()
+		{
+		}
+
+		private static readonly Person defaultInstance = new Person().MakeReadOnly();
+		private static readonly string[] _personFieldNames = new string[] {"age", "num"};
+		private static readonly uint[] _personFieldTags = new uint[] {16, 8};
+
+		public static Person DefaultInstance
+		{
+			get
+			{
+				return defaultInstance;
+			}
+		}
+
+		public override Person DefaultInstanceForType
+		{
+			get
+			{
+				return DefaultInstance;
+			}
+		}
+
+		protected override Person ThisMessage
+		{
+			get
+			{
+				return this;
+			}
+		}
+
+		public static pbd::MessageDescriptor Descriptor
+		{
+			get
+			{
+				return global::BehaviorTree.Proto.Person.internal__static_BehaviorTree_Person__Descriptor;
+			}
+		}
+
+		protected override pb::FieldAccess.FieldAccessorTable<Person, Person.Builder> InternalFieldAccessors
+		{
+			get
+			{
+				return global::BehaviorTree.Proto.Person.internal__static_BehaviorTree_Person__FieldAccessorTable;
+			}
+		}
+
+		public const int NumFieldNumber = 1;
+		private bool hasNum;
+		private int num_;
+
+		public bool HasNum
+		{
+			get
+			{
+				return hasNum;
+			}
+		}
+
+		public int Num
+		{
+			get
+			{
+				return num_;
+			}
+		}
+
+		public const int AgeFieldNumber = 2;
+		private bool hasAge;
+		private int age_;
+
+		public bool HasAge
+		{
+			get
+			{
+				return hasAge;
+			}
+		}
+
+		public int Age
+		{
+			get
+			{
+				return age_;
+			}
+		}
+
+		public override bool IsInitialized
+		{
+			get
+			{
+				if (!hasNum)
+				{
+					return false;
+				}
+				return true;
+			}
+		}
+
+		public override void WriteTo(pb::ICodedOutputStream output)
+		{
+			int size = SerializedSize;
+			string[] field_names = _personFieldNames;
+			if (hasNum)
+			{
+				output.WriteInt32(1, field_names[1], Num);
+			}
+			if (hasAge)
+			{
+				output.WriteInt32(2, field_names[0], Age);
+			}
+			UnknownFields.WriteTo(output);
+		}
+
+		private int memoizedSerializedSize = -1;
+
+		public override int SerializedSize
+		{
+			get
+			{
+				int size = memoizedSerializedSize;
+				if (size != -1)
+				{
+					return size;
+				}
+
+				size = 0;
+				if (hasNum)
+				{
+					size += pb::CodedOutputStream.ComputeInt32Size(1, Num);
+				}
+				if (hasAge)
+				{
+					size += pb::CodedOutputStream.ComputeInt32Size(2, Age);
+				}
+				size += UnknownFields.SerializedSize;
+				memoizedSerializedSize = size;
+				return size;
+			}
+		}
+
+		public static Person ParseFrom(pb::ByteString data)
+		{
+			return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+		}
+
+		public static Person ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry)
+		{
+			return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+		}
+
+		public static Person ParseFrom(byte[] data)
+		{
+			return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+		}
+
+		public static Person ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry)
+		{
+			return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+		}
+
+		public static Person ParseFrom(global::System.IO.Stream input)
+		{
+			return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+		}
+
+		public static Person ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry)
+		{
+			return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+		}
+
+		public static Person ParseDelimitedFrom(global::System.IO.Stream input)
+		{
+			return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
+		}
+
+		public static Person ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry)
+		{
+			return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
+		}
+
+		public static Person ParseFrom(pb::ICodedInputStream input)
+		{
+			return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+		}
+
+		public static Person ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry)
+		{
+			return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+		}
+
+		private Person MakeReadOnly()
+		{
+			return this;
+		}
+
+		public static Builder CreateBuilder()
+		{
+			return new Builder();
+		}
+
+		public override Builder ToBuilder()
+		{
+			return CreateBuilder(this);
+		}
+
+		public override Builder CreateBuilderForType()
+		{
+			return new Builder();
+		}
+
+		public static Builder CreateBuilder(Person prototype)
+		{
+			return new Builder(prototype);
+		}
+
+		[global::System.Diagnostics.DebuggerNonUserCodeAttribute(),
+		 global::System.Runtime.CompilerServices.CompilerGeneratedAttribute(),
+		 global::System.CodeDom.Compiler.GeneratedCodeAttribute("ProtoGen", "2.4.1.473")]
     
-    public static Builder CreateBuilder() { return new Builder(); }
-    public override Builder ToBuilder() { return CreateBuilder(this); }
-    public override Builder CreateBuilderForType() { return new Builder(); }
-    public static Builder CreateBuilder(Group prototype) {
-      return new Builder(prototype);
-    }
     
-    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
-    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("ProtoGen", "2.4.1.473")]
-    public sealed partial class Builder : pb::GeneratedBuilder<Group, Builder> {
-      protected override Builder ThisBuilder {
-        get { return this; }
-      }
-      public Builder() {
-        result = DefaultInstance;
-        resultIsReadOnly = true;
-      }
-      internal Builder(Group cloneFrom) {
-        result = cloneFrom;
-        resultIsReadOnly = true;
-      }
-      
-      private bool resultIsReadOnly;
-      private Group result;
-      
-      private Group PrepareBuilder() {
-        if (resultIsReadOnly) {
-          Group original = result;
-          result = new Group();
-          resultIsReadOnly = false;
-          MergeFrom(original);
-        }
-        return result;
-      }
-      
-      public override bool IsInitialized {
-        get { return result.IsInitialized; }
-      }
-      
-      protected override Group MessageBeingBuilt {
-        get { return PrepareBuilder(); }
-      }
-      
-      public override Builder Clear() {
-        result = DefaultInstance;
-        resultIsReadOnly = true;
-        return this;
-      }
-      
-      public override Builder Clone() {
-        if (resultIsReadOnly) {
-          return new Builder(result);
-        } else {
-          return new Builder().MergeFrom(result);
-        }
-      }
-      
-      public override pbd::MessageDescriptor DescriptorForType {
-        get { return global::BehaviorTree.Group.Descriptor; }
-      }
-      
-      public override Group DefaultInstanceForType {
-        get { return global::BehaviorTree.Group.DefaultInstance; }
-      }
-      
-      public override Group BuildPartial() {
-        if (resultIsReadOnly) {
-          return result;
-        }
-        resultIsReadOnly = true;
-        return result.MakeReadOnly();
-      }
-      
-      public override Builder MergeFrom(pb::IMessage other) {
-        if (other is Group) {
-          return MergeFrom((Group) other);
-        } else {
-          base.MergeFrom(other);
-          return this;
-        }
-      }
-      
-      public override Builder MergeFrom(Group other) {
-        if (other == global::BehaviorTree.Group.DefaultInstance) return this;
-        PrepareBuilder();
-        if (other.persons_.Count != 0) {
-          result.persons_.Add(other.persons_);
-        }
-        this.MergeUnknownFields(other.UnknownFields);
-        return this;
-      }
-      
-      public override Builder MergeFrom(pb::ICodedInputStream input) {
-        return MergeFrom(input, pb::ExtensionRegistry.Empty);
-      }
-      
-      public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
-        PrepareBuilder();
-        pb::UnknownFieldSet.Builder unknownFields = null;
-        uint tag;
-        string field_name;
-        while (input.ReadTag(out tag, out field_name)) {
-          if(tag == 0 && field_name != null) {
-            int field_ordinal = global::System.Array.BinarySearch(_groupFieldNames, field_name, global::System.StringComparer.Ordinal);
-            if(field_ordinal >= 0)
-              tag = _groupFieldTags[field_ordinal];
-            else {
-              if (unknownFields == null) {
-                unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
-              }
-              ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
-              continue;
-            }
-          }
-          switch (tag) {
-            case 0: {
-              throw pb::InvalidProtocolBufferException.InvalidTag();
-            }
-            default: {
-              if (pb::WireFormat.IsEndGroupTag(tag)) {
-                if (unknownFields != null) {
-                  this.UnknownFields = unknownFields.Build();
-                }
-                return this;
-              }
-              if (unknownFields == null) {
-                unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
-              }
-              ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
-              break;
-            }
-            case 10: {
-              input.ReadMessageArray(tag, field_name, result.persons_, global::BehaviorTree.Person.DefaultInstance, extensionRegistry);
-              break;
-            }
-          }
-        }
-        
-        if (unknownFields != null) {
-          this.UnknownFields = unknownFields.Build();
-        }
-        return this;
-      }
-      
-      
-      public pbc::IPopsicleList<global::BehaviorTree.Person> PersonsList {
-        get { return PrepareBuilder().persons_; }
-      }
-      public int PersonsCount {
-        get { return result.PersonsCount; }
-      }
-      public global::BehaviorTree.Person GetPersons(int index) {
-        return result.GetPersons(index);
-      }
-      public Builder SetPersons(int index, global::BehaviorTree.Person value) {
-        pb::ThrowHelper.ThrowIfNull(value, "value");
-        PrepareBuilder();
-        result.persons_[index] = value;
-        return this;
-      }
-      public Builder SetPersons(int index, global::BehaviorTree.Person.Builder builderForValue) {
-        pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
-        PrepareBuilder();
-        result.persons_[index] = builderForValue.Build();
-        return this;
-      }
-      public Builder AddPersons(global::BehaviorTree.Person value) {
-        pb::ThrowHelper.ThrowIfNull(value, "value");
-        PrepareBuilder();
-        result.persons_.Add(value);
-        return this;
-      }
-      public Builder AddPersons(global::BehaviorTree.Person.Builder builderForValue) {
-        pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
-        PrepareBuilder();
-        result.persons_.Add(builderForValue.Build());
-        return this;
-      }
-      public Builder AddRangePersons(scg::IEnumerable<global::BehaviorTree.Person> values) {
-        PrepareBuilder();
-        result.persons_.Add(values);
-        return this;
-      }
-      public Builder ClearPersons() {
-        PrepareBuilder();
-        result.persons_.Clear();
-        return this;
-      }
-    }
-    static Group() {
-      object.ReferenceEquals(global::BehaviorTree.Proto.Person.Descriptor, null);
-    }
-  }
+		public sealed partial class Builder : pb::GeneratedBuilder<Person, Builder>
+		{
+			protected override Builder ThisBuilder
+			{
+				get
+				{
+					return this;
+				}
+			}
+
+			public Builder()
+			{
+				result = DefaultInstance;
+				resultIsReadOnly = true;
+			}
+
+			internal Builder(Person cloneFrom)
+			{
+				result = cloneFrom;
+				resultIsReadOnly = true;
+			}
+
+			private bool resultIsReadOnly;
+			private Person result;
+
+			private Person PrepareBuilder()
+			{
+				if (resultIsReadOnly)
+				{
+					Person original = result;
+					result = new Person();
+					resultIsReadOnly = false;
+					MergeFrom(original);
+				}
+				return result;
+			}
+
+			public override bool IsInitialized
+			{
+				get
+				{
+					return result.IsInitialized;
+				}
+			}
+
+			protected override Person MessageBeingBuilt
+			{
+				get
+				{
+					return PrepareBuilder();
+				}
+			}
+
+			public override Builder Clear()
+			{
+				result = DefaultInstance;
+				resultIsReadOnly = true;
+				return this;
+			}
+
+			public override Builder Clone()
+			{
+				if (resultIsReadOnly)
+				{
+					return new Builder(result);
+				}
+				else
+				{
+					return new Builder().MergeFrom(result);
+				}
+			}
+
+			public override pbd::MessageDescriptor DescriptorForType
+			{
+				get
+				{
+					return global::BehaviorTree.Person.Descriptor;
+				}
+			}
+
+			public override Person DefaultInstanceForType
+			{
+				get
+				{
+					return global::BehaviorTree.Person.DefaultInstance;
+				}
+			}
+
+			public override Person BuildPartial()
+			{
+				if (resultIsReadOnly)
+				{
+					return result;
+				}
+				resultIsReadOnly = true;
+				return result.MakeReadOnly();
+			}
+
+			public override Builder MergeFrom(pb::IMessage other)
+			{
+				if (other is Person)
+				{
+					return MergeFrom((Person) other);
+				}
+				else
+				{
+					base.MergeFrom(other);
+					return this;
+				}
+			}
+
+			public override Builder MergeFrom(Person other)
+			{
+				if (other == global::BehaviorTree.Person.DefaultInstance)
+				{
+					return this;
+				}
+				PrepareBuilder();
+				if (other.HasNum)
+				{
+					Num = other.Num;
+				}
+				if (other.HasAge)
+				{
+					Age = other.Age;
+				}
+				this.MergeUnknownFields(other.UnknownFields);
+				return this;
+			}
+
+			public override Builder MergeFrom(pb::ICodedInputStream input)
+			{
+				return MergeFrom(input, pb::ExtensionRegistry.Empty);
+			}
+
+			public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry)
+			{
+				PrepareBuilder();
+				pb::UnknownFieldSet.Builder unknownFields = null;
+				uint tag;
+				string field_name;
+				while (input.ReadTag(out tag, out field_name))
+				{
+					if (tag == 0 && field_name != null)
+					{
+						int field_ordinal = global::System.Array.BinarySearch(
+						                                                      _personFieldNames, field_name,
+						                                                      global::System.StringComparer.Ordinal);
+						if (field_ordinal >= 0)
+						{
+							tag = _personFieldTags[field_ordinal];
+						}
+						else
+						{
+							if (unknownFields == null)
+							{
+								unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+							}
+							ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+							continue;
+						}
+					}
+					switch (tag)
+					{
+						case 0:
+						{
+							throw pb::InvalidProtocolBufferException.InvalidTag();
+						}
+						default:
+						{
+							if (pb::WireFormat.IsEndGroupTag(tag))
+							{
+								if (unknownFields != null)
+								{
+									this.UnknownFields = unknownFields.Build();
+								}
+								return this;
+							}
+							if (unknownFields == null)
+							{
+								unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+							}
+							ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+							break;
+						}
+						case 8:
+						{
+							result.hasNum = input.ReadInt32(ref result.num_);
+							break;
+						}
+						case 16:
+						{
+							result.hasAge = input.ReadInt32(ref result.age_);
+							break;
+						}
+					}
+				}
+
+				if (unknownFields != null)
+				{
+					this.UnknownFields = unknownFields.Build();
+				}
+				return this;
+			}
+
+			public bool HasNum
+			{
+				get
+				{
+					return result.hasNum;
+				}
+			}
+
+			public int Num
+			{
+				get
+				{
+					return result.Num;
+				}
+				set
+				{
+					SetNum(value);
+				}
+			}
+
+			public Builder SetNum(int value)
+			{
+				PrepareBuilder();
+				result.hasNum = true;
+				result.num_ = value;
+				return this;
+			}
+
+			public Builder ClearNum()
+			{
+				PrepareBuilder();
+				result.hasNum = false;
+				result.num_ = 0;
+				return this;
+			}
+
+			public bool HasAge
+			{
+				get
+				{
+					return result.hasAge;
+				}
+			}
+
+			public int Age
+			{
+				get
+				{
+					return result.Age;
+				}
+				set
+				{
+					SetAge(value);
+				}
+			}
+
+			public Builder SetAge(int value)
+			{
+				PrepareBuilder();
+				result.hasAge = true;
+				result.age_ = value;
+				return this;
+			}
+
+			public Builder ClearAge()
+			{
+				PrepareBuilder();
+				result.hasAge = false;
+				result.age_ = 0;
+				return this;
+			}
+		}
+
+		static Person()
+		{
+			object.ReferenceEquals(global::BehaviorTree.Proto.Person.Descriptor, null);
+		}
+	}
+
+	[global::System.Diagnostics.DebuggerNonUserCodeAttribute(),
+	 global::System.Runtime.CompilerServices.CompilerGeneratedAttribute(),
+	 global::System.CodeDom.Compiler.GeneratedCodeAttribute("ProtoGen", "2.4.1.473")]
   
-  #endregion
   
+	public sealed partial class Group : pb::GeneratedMessage<Group, Group.Builder>
+	{
+		private Group()
+		{
+		}
+
+		private static readonly Group defaultInstance = new Group().MakeReadOnly();
+		private static readonly string[] _groupFieldNames = new string[] {"persons"};
+		private static readonly uint[] _groupFieldTags = new uint[] {10};
+
+		public static Group DefaultInstance
+		{
+			get
+			{
+				return defaultInstance;
+			}
+		}
+
+		public override Group DefaultInstanceForType
+		{
+			get
+			{
+				return DefaultInstance;
+			}
+		}
+
+		protected override Group ThisMessage
+		{
+			get
+			{
+				return this;
+			}
+		}
+
+		public static pbd::MessageDescriptor Descriptor
+		{
+			get
+			{
+				return global::BehaviorTree.Proto.Person.internal__static_BehaviorTree_Group__Descriptor;
+			}
+		}
+
+		protected override pb::FieldAccess.FieldAccessorTable<Group, Group.Builder> InternalFieldAccessors
+		{
+			get
+			{
+				return global::BehaviorTree.Proto.Person.internal__static_BehaviorTree_Group__FieldAccessorTable;
+			}
+		}
+
+		public const int PersonsFieldNumber = 1;
+		private pbc::PopsicleList<global::BehaviorTree.Person> persons_ = new pbc::PopsicleList<global::BehaviorTree.Person>();
+
+		public scg::IList<global::BehaviorTree.Person> PersonsList
+		{
+			get
+			{
+				return persons_;
+			}
+		}
+
+		public int PersonsCount
+		{
+			get
+			{
+				return persons_.Count;
+			}
+		}
+
+		public global::BehaviorTree.Person GetPersons(int index)
+		{
+			return persons_[index];
+		}
+
+		public override bool IsInitialized
+		{
+			get
+			{
+				foreach (global::BehaviorTree.Person element in PersonsList)
+				{
+					if (!element.IsInitialized)
+					{
+						return false;
+					}
+				}
+				return true;
+			}
+		}
+
+		public override void WriteTo(pb::ICodedOutputStream output)
+		{
+			int size = SerializedSize;
+			string[] field_names = _groupFieldNames;
+			if (persons_.Count > 0)
+			{
+				output.WriteMessageArray(1, field_names[0], persons_);
+			}
+			UnknownFields.WriteTo(output);
+		}
+
+		private int memoizedSerializedSize = -1;
+
+		public override int SerializedSize
+		{
+			get
+			{
+				int size = memoizedSerializedSize;
+				if (size != -1)
+				{
+					return size;
+				}
+
+				size = 0;
+				foreach (global::BehaviorTree.Person element in PersonsList)
+				{
+					size += pb::CodedOutputStream.ComputeMessageSize(1, element);
+				}
+				size += UnknownFields.SerializedSize;
+				memoizedSerializedSize = size;
+				return size;
+			}
+		}
+
+		public static Group ParseFrom(pb::ByteString data)
+		{
+			return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+		}
+
+		public static Group ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry)
+		{
+			return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+		}
+
+		public static Group ParseFrom(byte[] data)
+		{
+			return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+		}
+
+		public static Group ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry)
+		{
+			return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+		}
+
+		public static Group ParseFrom(global::System.IO.Stream input)
+		{
+			return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+		}
+
+		public static Group ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry)
+		{
+			return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+		}
+
+		public static Group ParseDelimitedFrom(global::System.IO.Stream input)
+		{
+			return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
+		}
+
+		public static Group ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry)
+		{
+			return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
+		}
+
+		public static Group ParseFrom(pb::ICodedInputStream input)
+		{
+			return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+		}
+
+		public static Group ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry)
+		{
+			return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+		}
+
+		private Group MakeReadOnly()
+		{
+			persons_.MakeReadOnly();
+			return this;
+		}
+
+		public static Builder CreateBuilder()
+		{
+			return new Builder();
+		}
+
+		public override Builder ToBuilder()
+		{
+			return CreateBuilder(this);
+		}
+
+		public override Builder CreateBuilderForType()
+		{
+			return new Builder();
+		}
+
+		public static Builder CreateBuilder(Group prototype)
+		{
+			return new Builder(prototype);
+		}
+
+		[global::System.Diagnostics.DebuggerNonUserCodeAttribute(),
+		 global::System.Runtime.CompilerServices.CompilerGeneratedAttribute(),
+		 global::System.CodeDom.Compiler.GeneratedCodeAttribute("ProtoGen", "2.4.1.473")]
+    
+    
+		public sealed partial class Builder : pb::GeneratedBuilder<Group, Builder>
+		{
+			protected override Builder ThisBuilder
+			{
+				get
+				{
+					return this;
+				}
+			}
+
+			public Builder()
+			{
+				result = DefaultInstance;
+				resultIsReadOnly = true;
+			}
+
+			internal Builder(Group cloneFrom)
+			{
+				result = cloneFrom;
+				resultIsReadOnly = true;
+			}
+
+			private bool resultIsReadOnly;
+			private Group result;
+
+			private Group PrepareBuilder()
+			{
+				if (resultIsReadOnly)
+				{
+					Group original = result;
+					result = new Group();
+					resultIsReadOnly = false;
+					MergeFrom(original);
+				}
+				return result;
+			}
+
+			public override bool IsInitialized
+			{
+				get
+				{
+					return result.IsInitialized;
+				}
+			}
+
+			protected override Group MessageBeingBuilt
+			{
+				get
+				{
+					return PrepareBuilder();
+				}
+			}
+
+			public override Builder Clear()
+			{
+				result = DefaultInstance;
+				resultIsReadOnly = true;
+				return this;
+			}
+
+			public override Builder Clone()
+			{
+				if (resultIsReadOnly)
+				{
+					return new Builder(result);
+				}
+				else
+				{
+					return new Builder().MergeFrom(result);
+				}
+			}
+
+			public override pbd::MessageDescriptor DescriptorForType
+			{
+				get
+				{
+					return global::BehaviorTree.Group.Descriptor;
+				}
+			}
+
+			public override Group DefaultInstanceForType
+			{
+				get
+				{
+					return global::BehaviorTree.Group.DefaultInstance;
+				}
+			}
+
+			public override Group BuildPartial()
+			{
+				if (resultIsReadOnly)
+				{
+					return result;
+				}
+				resultIsReadOnly = true;
+				return result.MakeReadOnly();
+			}
+
+			public override Builder MergeFrom(pb::IMessage other)
+			{
+				if (other is Group)
+				{
+					return MergeFrom((Group) other);
+				}
+				else
+				{
+					base.MergeFrom(other);
+					return this;
+				}
+			}
+
+			public override Builder MergeFrom(Group other)
+			{
+				if (other == global::BehaviorTree.Group.DefaultInstance)
+				{
+					return this;
+				}
+				PrepareBuilder();
+				if (other.persons_.Count != 0)
+				{
+					result.persons_.Add(other.persons_);
+				}
+				this.MergeUnknownFields(other.UnknownFields);
+				return this;
+			}
+
+			public override Builder MergeFrom(pb::ICodedInputStream input)
+			{
+				return MergeFrom(input, pb::ExtensionRegistry.Empty);
+			}
+
+			public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry)
+			{
+				PrepareBuilder();
+				pb::UnknownFieldSet.Builder unknownFields = null;
+				uint tag;
+				string field_name;
+				while (input.ReadTag(out tag, out field_name))
+				{
+					if (tag == 0 && field_name != null)
+					{
+						int field_ordinal = global::System.Array.BinarySearch(
+						                                                      _groupFieldNames, field_name,
+						                                                      global::System.StringComparer.Ordinal);
+						if (field_ordinal >= 0)
+						{
+							tag = _groupFieldTags[field_ordinal];
+						}
+						else
+						{
+							if (unknownFields == null)
+							{
+								unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+							}
+							ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+							continue;
+						}
+					}
+					switch (tag)
+					{
+						case 0:
+						{
+							throw pb::InvalidProtocolBufferException.InvalidTag();
+						}
+						default:
+						{
+							if (pb::WireFormat.IsEndGroupTag(tag))
+							{
+								if (unknownFields != null)
+								{
+									this.UnknownFields = unknownFields.Build();
+								}
+								return this;
+							}
+							if (unknownFields == null)
+							{
+								unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+							}
+							ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+							break;
+						}
+						case 10:
+						{
+							input.ReadMessageArray(
+							                       tag, field_name, result.persons_, global::BehaviorTree.Person.DefaultInstance,
+							                       extensionRegistry);
+							break;
+						}
+					}
+				}
+
+				if (unknownFields != null)
+				{
+					this.UnknownFields = unknownFields.Build();
+				}
+				return this;
+			}
+
+			public pbc::IPopsicleList<global::BehaviorTree.Person> PersonsList
+			{
+				get
+				{
+					return PrepareBuilder().persons_;
+				}
+			}
+
+			public int PersonsCount
+			{
+				get
+				{
+					return result.PersonsCount;
+				}
+			}
+
+			public global::BehaviorTree.Person GetPersons(int index)
+			{
+				return result.GetPersons(index);
+			}
+
+			public Builder SetPersons(int index, global::BehaviorTree.Person value)
+			{
+				pb::ThrowHelper.ThrowIfNull(value, "value");
+				PrepareBuilder();
+				result.persons_[index] = value;
+				return this;
+			}
+
+			public Builder SetPersons(int index, global::BehaviorTree.Person.Builder builderForValue)
+			{
+				pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+				PrepareBuilder();
+				result.persons_[index] = builderForValue.Build();
+				return this;
+			}
+
+			public Builder AddPersons(global::BehaviorTree.Person value)
+			{
+				pb::ThrowHelper.ThrowIfNull(value, "value");
+				PrepareBuilder();
+				result.persons_.Add(value);
+				return this;
+			}
+
+			public Builder AddPersons(global::BehaviorTree.Person.Builder builderForValue)
+			{
+				pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+				PrepareBuilder();
+				result.persons_.Add(builderForValue.Build());
+				return this;
+			}
+
+			public Builder AddRangePersons(scg::IEnumerable<global::BehaviorTree.Person> values)
+			{
+				PrepareBuilder();
+				result.persons_.Add(values);
+				return this;
+			}
+
+			public Builder ClearPersons()
+			{
+				PrepareBuilder();
+				result.persons_.Clear();
+				return this;
+			}
+		}
+
+		static Group()
+		{
+			object.ReferenceEquals(global::BehaviorTree.Proto.Person.Descriptor, null);
+		}
+	}
+
+	#endregion
 }
 
-#endregion Designer generated code
+#endregion Designer generated code

+ 59 - 42
CSharp/Modules/BehaviorTree/TreeNodeViewModel.cs

@@ -5,6 +5,8 @@ namespace BehaviorTree
 {
 	public class TreeNodeViewModel : NotificationObject
 	{
+		private static int globalNum = 0;
+		private readonly int num;
 		private const double width = 80;
 		private const double height = 50;
 		private readonly TreeNode treeNode;
@@ -15,6 +17,7 @@ namespace BehaviorTree
 
 		public TreeNodeViewModel(TreeNode treeNode, TreeNodeViewModel parent)
 		{
+			num = globalNum++;
 			this.treeNode = treeNode;
 			this.parent = parent ?? this;
 			if (this.parent == this)
@@ -29,6 +32,14 @@ namespace BehaviorTree
 			}
 		}
 
+		public int Num
+		{
+			get
+			{
+				return this.num;
+			}
+		}
+
 		public static double Width
 		{
 			get
@@ -45,16 +56,42 @@ namespace BehaviorTree
 			}
 		}
 
+		public bool IsRoot
+		{
+			get
+			{
+				return Parent == this;
+			}
+		}
+
+		private double prelim;
+
 		public double Prelim
 		{
-			get;
-			set;
+			get
+			{
+				return this.prelim;
+			}
+			set
+			{
+				this.prelim = value;
+				RaisePropertyChanged("Prelim");
+			}
 		}
 
+		private double modify;
+
 		public double Modify
 		{
-			get;
-			set;
+			get
+			{
+				return this.modify;
+			}
+			set
+			{
+				RaisePropertyChanged("Modify");
+				this.modify = value;
+			}
 		}
 
 		public double X
@@ -72,11 +109,11 @@ namespace BehaviorTree
 				treeNode.X = value;
 				RaisePropertyChanged("X");
 
-				ConnectorX2 = Width + Parent.X - X;
+				ConnectorX2 = Width / 2 + Parent.X - X;
 
 				foreach (TreeNodeViewModel child in Children)
 				{
-					child.ConnectorX2 = Width + treeNode.X - child.X;
+					child.ConnectorX2 = Width / 2 + treeNode.X - child.X;
 				}
 			}
 		}
@@ -96,11 +133,11 @@ namespace BehaviorTree
 				treeNode.Y = value;
 				RaisePropertyChanged("Y");
 
-				ConnectorY2 = Height / 2 + Parent.Y - Y;
+				ConnectorY2 = Height + Parent.Y - Y;
 
-				foreach (TreeNodeViewModel child in Children)
+				foreach (var child in Children)
 				{
-					child.ConnectorY2 = Height / 2 + treeNode.Y - child.Y;
+					child.ConnectorY2 = Height + treeNode.Y - child.Y;
 				}
 			}
 		}
@@ -109,7 +146,7 @@ namespace BehaviorTree
 		{
 			get
 			{
-				return 0;
+				return Width / 2;
 			}
 		}
 
@@ -117,7 +154,7 @@ namespace BehaviorTree
 		{
 			get
 			{
-				return Height / 2;
+				return 0;
 			}
 		}
 
@@ -125,11 +162,7 @@ namespace BehaviorTree
 		{
 			get
 			{
-				if (Parent == this)
-				{
-					return 0;
-				}
-				return connectorX2;
+				return this.IsRoot ? width / 2 : this.connectorX2;
 			}
 			set
 			{
@@ -142,11 +175,7 @@ namespace BehaviorTree
 		{
 			get
 			{
-				if (Parent == this)
-				{
-					return Height / 2;
-				}
-				return connectorY2;
+				return this.IsRoot ? 0 : this.connectorY2;
 			}
 			set
 			{
@@ -200,20 +229,13 @@ namespace BehaviorTree
 		{
 			get
 			{
-				if (Parent == this)
+				if (this.IsRoot)
 				{
 					return null;
 				}
 
-				int index = Parent.Children.IndexOf(this);
-				if (index == 0)
-				{
-					return null;
-				}
-				else
-				{
-					return Parent.Children[index - 1];
-				}
+				int index = this.Parent.Children.IndexOf(this);
+				return index == 0 ? null : this.Parent.Children[index - 1];
 			}
 		}
 
@@ -221,8 +243,7 @@ namespace BehaviorTree
 		{
 			get
 			{
-				int index = Parent.Children.IndexOf(this);
-				return index;
+				return this.IsRoot ? 0 : this.Parent.Children.IndexOf(this);
 			}
 		}
 
@@ -230,13 +251,13 @@ namespace BehaviorTree
 		{
 			get
 			{
-				if (Children.Count == 0)
+				if (this.Children.Count == 0)
 				{
 					return null;
 				}
 
-				int maxIndex = Children.Count - 1;
-				return Children[Index];
+				int maxIndex = this.Children.Count - 1;
+				return this.Children[maxIndex];
 			}
 		}
 
@@ -244,11 +265,7 @@ namespace BehaviorTree
 		{
 			get
 			{
-				if (Children.Count == 0)
-				{
-					return null;
-				}
-				return Children[0];
+				return this.Children.Count == 0 ? null : this.Children[0];
 			}
 		}
 
@@ -256,7 +273,7 @@ namespace BehaviorTree
 		{
 			get
 			{
-				return Children.Count == 0;
+				return this.Children.Count == 0;
 			}
 		}
 	}