diff --git a/EndlessVendetta/Plugins/GenericGraph/.gitignore b/EndlessVendetta/Plugins/GenericGraph/.gitignore
new file mode 100644
index 00000000..7b887157
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/.gitignore
@@ -0,0 +1,14 @@
+Binaries
+DerivedDataCache
+Intermediate
+Saved
+Build
+*.sdf
+*.sln
+*.suo
+*.opensdf
+*.opendb
+*.db
+/docs/sphinx-build-result
+/.vs
+NoCommit
\ No newline at end of file
diff --git a/EndlessVendetta/Plugins/GenericGraph/GenericGraph.uplugin b/EndlessVendetta/Plugins/GenericGraph/GenericGraph.uplugin
new file mode 100644
index 00000000..68e4ef88
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/GenericGraph.uplugin
@@ -0,0 +1,30 @@
+{
+	"FileVersion" : 3,
+	"Version" : 1,
+	"VersionName" : "1.0",
+	"FriendlyName" : "Generic Graph Plugin",
+	"Description" : "",
+	"Category" : "GenericGraph",
+	"CreatedBy" : "jinyuliao",
+	"CreatedByURL" : "",
+	"DocsURL" : "",
+	"MarketplaceURL" : "",
+	"SupportURL" : "",
+	"EnabledByDefault" : true,
+	"CanContainContent" : true,
+	"IsBetaVersion" : false,
+	"Installed" : false,
+	"Modules" :
+	[
+		{
+			"Name" : "GenericGraphRuntime",
+			"Type" : "Runtime",
+			"LoadingPhase" : "PreDefault"
+		},
+		{
+			"Name" : "GenericGraphEditor",
+			"Type" : "Editor",
+			"LoadingPhase" : "Default"
+		}
+	]
+}
\ No newline at end of file
diff --git a/EndlessVendetta/Plugins/GenericGraph/LICENSE b/EndlessVendetta/Plugins/GenericGraph/LICENSE
new file mode 100644
index 00000000..9c189b15
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2016 jinyuliao
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/EndlessVendetta/Plugins/GenericGraph/Resources/AutoArrangeIcon.png b/EndlessVendetta/Plugins/GenericGraph/Resources/AutoArrangeIcon.png
new file mode 100644
index 00000000..b5e6c3b1
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Resources/AutoArrangeIcon.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:71dff338a731ee7bf2def0d378b0a866615d2ee72aa591ab4ed7ad1105049806
+size 5528
diff --git a/EndlessVendetta/Plugins/GenericGraph/Resources/Icon128.png b/EndlessVendetta/Plugins/GenericGraph/Resources/Icon128.png
new file mode 100644
index 00000000..57ee2a55
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Resources/Icon128.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:9eb6f69963ee569b0a8a4446e21f69d0a93205caf07b30cc37b1fddb62599602
+size 15543
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/GenericGraphEditor.Build.cs b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/GenericGraphEditor.Build.cs
new file mode 100644
index 00000000..aa57f0ce
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/GenericGraphEditor.Build.cs
@@ -0,0 +1,62 @@
+using UnrealBuildTool;
+
+public class GenericGraphEditor : ModuleRules
+{
+	public GenericGraphEditor(ReadOnlyTargetRules Target) : base(Target)
+    {
+        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
+		bLegacyPublicIncludePaths = false;
+		ShadowVariableWarningLevel = WarningLevel.Error;
+
+		PublicIncludePaths.AddRange(
+			new string[] {
+				// ... add public include paths required here ...
+			}
+			);
+
+		PrivateIncludePaths.AddRange(
+			new string[] {
+                // ... add other private include paths required here ...
+                "GenericGraphEditor/Private",
+				"GenericGraphEditor/Public",
+			}
+			);
+
+		PublicDependencyModuleNames.AddRange(
+			new string[]
+			{
+				"Core",
+				"CoreUObject",
+                "Engine",
+                "UnrealEd",
+				// ... add other public dependencies that you statically link with here ...
+			}
+			);
+
+		PrivateDependencyModuleNames.AddRange(
+			new string[]
+			{
+                "GenericGraphRuntime",
+                "AssetTools",
+                "Slate",
+                "InputCore",
+                "SlateCore",
+                "GraphEditor",
+                "PropertyEditor",
+                "EditorStyle",
+                "Kismet",
+                "KismetWidgets",
+                "ApplicationCore",
+				"ToolMenus",
+				// ... add private dependencies that you statically link with here ...
+			}
+			);
+
+		DynamicallyLoadedModuleNames.AddRange(
+			new string[]
+			{
+				// ... add any modules that your module loads dynamically here ...
+            }
+			);
+	}
+}
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/AssetTypeActions_GenericGraph.cpp b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/AssetTypeActions_GenericGraph.cpp
new file mode 100644
index 00000000..643911c7
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/AssetTypeActions_GenericGraph.cpp
@@ -0,0 +1,48 @@
+#include "AssetTypeActions_GenericGraph.h"
+#include "GenericGraphEditorPCH.h"
+#include "GenericGraphAssetEditor/AssetEditor_GenericGraph.h"
+
+#define LOCTEXT_NAMESPACE "AssetTypeActions_GenericGraph"
+
+FAssetTypeActions_GenericGraph::FAssetTypeActions_GenericGraph(EAssetTypeCategories::Type InAssetCategory)
+	: MyAssetCategory(InAssetCategory)
+{
+}
+
+FText FAssetTypeActions_GenericGraph::GetName() const
+{
+	return LOCTEXT("FGenericGraphAssetTypeActionsName", "Generic Graph");
+}
+
+FColor FAssetTypeActions_GenericGraph::GetTypeColor() const
+{
+	return FColor(129, 196, 115);
+}
+
+UClass* FAssetTypeActions_GenericGraph::GetSupportedClass() const
+{
+	return UGenericGraph::StaticClass();
+}
+
+void FAssetTypeActions_GenericGraph::OpenAssetEditor(const TArray<UObject*>& InObjects, TSharedPtr<class IToolkitHost> EditWithinLevelEditor)
+{
+	const EToolkitMode::Type Mode = EditWithinLevelEditor.IsValid() ? EToolkitMode::WorldCentric : EToolkitMode::Standalone;
+
+	for (auto ObjIt = InObjects.CreateConstIterator(); ObjIt; ++ObjIt)
+	{
+		if (UGenericGraph* Graph = Cast<UGenericGraph>(*ObjIt))
+		{
+			TSharedRef<FAssetEditor_GenericGraph> NewGraphEditor(new FAssetEditor_GenericGraph());
+			NewGraphEditor->InitGenericGraphAssetEditor(Mode, EditWithinLevelEditor, Graph);
+		}
+	}
+}
+
+uint32 FAssetTypeActions_GenericGraph::GetCategories()
+{
+	return MyAssetCategory;
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+#undef LOCTEXT_NAMESPACE
\ No newline at end of file
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/AutoLayout/AutoLayoutStrategy.cpp b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/AutoLayout/AutoLayoutStrategy.cpp
new file mode 100644
index 00000000..4d03bd87
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/AutoLayout/AutoLayoutStrategy.cpp
@@ -0,0 +1,96 @@
+#include "AutoLayout/AutoLayoutStrategy.h"
+#include "Kismet/KismetMathLibrary.h"
+#include "GenericGraphAssetEditor/EdNode_GenericGraphNode.h"
+#include "GenericGraphAssetEditor/SEdNode_GenericGraphNode.h"
+
+UAutoLayoutStrategy::UAutoLayoutStrategy()
+{
+	Settings = nullptr;
+	MaxIteration = 50;
+	OptimalDistance = 150;
+}
+
+UAutoLayoutStrategy::~UAutoLayoutStrategy()
+{
+
+}
+
+FBox2D UAutoLayoutStrategy::GetNodeBound(UEdGraphNode* EdNode)
+{
+	int32 NodeWidth = GetNodeWidth(Cast<UEdNode_GenericGraphNode>(EdNode));
+	int32 NodeHeight = GetNodeHeight(Cast<UEdNode_GenericGraphNode>(EdNode));
+	FVector2D Min(EdNode->NodePosX, EdNode->NodePosY);
+	FVector2D Max(EdNode->NodePosX + NodeWidth, EdNode->NodePosY + NodeHeight);
+	return FBox2D(Min, Max);
+}
+
+FBox2D UAutoLayoutStrategy::GetActualBounds(UGenericGraphNode* RootNode)
+{
+	int Level = 0;
+	TArray<UGenericGraphNode*> CurrLevelNodes = { RootNode };
+	TArray<UGenericGraphNode*> NextLevelNodes;
+
+	FBox2D Rtn = GetNodeBound(EdGraph->NodeMap[RootNode]);
+
+	while (CurrLevelNodes.Num() != 0)
+	{
+		for (int i = 0; i < CurrLevelNodes.Num(); ++i)
+		{
+			UGenericGraphNode* Node = CurrLevelNodes[i];
+			check(Node != nullptr);
+
+			Rtn += GetNodeBound(EdGraph->NodeMap[Node]);
+
+			for (int j = 0; j < Node->ChildrenNodes.Num(); ++j)
+			{
+				NextLevelNodes.Add(Node->ChildrenNodes[j]);
+			}
+		}
+
+		CurrLevelNodes = NextLevelNodes;
+		NextLevelNodes.Reset();
+		++Level;
+	}
+	return Rtn;
+}
+
+void UAutoLayoutStrategy::RandomLayoutOneTree(UGenericGraphNode* RootNode, const FBox2D& Bound)
+{
+	int Level = 0;
+	TArray<UGenericGraphNode*> CurrLevelNodes = { RootNode };
+	TArray<UGenericGraphNode*> NextLevelNodes;
+
+	while (CurrLevelNodes.Num() != 0)
+	{
+		for (int i = 0; i < CurrLevelNodes.Num(); ++i)
+		{
+			UGenericGraphNode* Node = CurrLevelNodes[i];
+			check(Node != nullptr);
+
+			UEdNode_GenericGraphNode* EdNode_Node = EdGraph->NodeMap[Node];
+
+			EdNode_Node->NodePosX = UKismetMathLibrary::RandomFloatInRange(Bound.Min.X, Bound.Max.X);
+			EdNode_Node->NodePosY = UKismetMathLibrary::RandomFloatInRange(Bound.Min.Y, Bound.Max.Y);
+
+			for (int j = 0; j < Node->ChildrenNodes.Num(); ++j)
+			{
+				NextLevelNodes.Add(Node->ChildrenNodes[j]);
+			}
+		}
+
+		CurrLevelNodes = NextLevelNodes;
+		NextLevelNodes.Reset();
+		++Level;
+	}
+}
+
+int32 UAutoLayoutStrategy::GetNodeWidth(UEdNode_GenericGraphNode* EdNode)
+{
+	return EdNode->SEdNode->GetCachedGeometry().GetLocalSize().X;
+}
+
+int32 UAutoLayoutStrategy::GetNodeHeight(UEdNode_GenericGraphNode* EdNode)
+{
+	return EdNode->SEdNode->GetCachedGeometry().GetLocalSize().Y;
+}
+
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/AutoLayout/ForceDirectedLayoutStrategy.cpp b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/AutoLayout/ForceDirectedLayoutStrategy.cpp
new file mode 100644
index 00000000..8d66bfcb
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/AutoLayout/ForceDirectedLayoutStrategy.cpp
@@ -0,0 +1,162 @@
+#include "AutoLayout/ForceDirectedLayoutStrategy.h"
+
+static inline float CoolDown(float Temp, float CoolDownRate)
+{
+	if (Temp < .01) return .01;
+	return Temp - (Temp / CoolDownRate);
+}
+
+static inline float GetAttractForce(float X, float K)
+{
+	return (X * X) / K;
+}
+
+static inline float GetRepulseForce(float X, float k)
+{
+	return X != 0 ? k * k / X : TNumericLimits<float>::Max();
+}
+
+UForceDirectedLayoutStrategy::UForceDirectedLayoutStrategy()
+{
+	bRandomInit = false;
+	CoolDownRate = 10;
+	InitTemperature = 10.f;
+}
+
+UForceDirectedLayoutStrategy::~UForceDirectedLayoutStrategy()
+{
+
+}
+
+void UForceDirectedLayoutStrategy::Layout(UEdGraph* _EdGraph)
+{
+	EdGraph = Cast<UEdGraph_GenericGraph>(_EdGraph);
+	check(EdGraph != nullptr);
+
+	EdGraph->RebuildGenericGraph();
+	Graph = EdGraph->GetGenericGraph();
+	check(Graph != nullptr);
+
+	if (Settings != nullptr)
+	{
+		OptimalDistance = Settings->OptimalDistance;
+		MaxIteration = Settings->MaxIteration;
+		bRandomInit = Settings->bRandomInit;
+	}
+
+	FBox2D PreTreeBound(ForceInitToZero);
+	for (int32 i = 0; i < Graph->RootNodes.Num(); ++i)
+	{
+		PreTreeBound = LayoutOneTree(Graph->RootNodes[i], PreTreeBound);
+	}
+}
+
+FBox2D UForceDirectedLayoutStrategy::LayoutOneTree(UGenericGraphNode* RootNode, const FBox2D& PreTreeBound)
+{
+	float Temp = InitTemperature;
+	FBox2D TreeBound = GetActualBounds(RootNode);
+	TreeBound.Min.X += PreTreeBound.Max.X + OptimalDistance;
+	TreeBound.Max.X += PreTreeBound.Max.X + OptimalDistance;
+
+	if (bRandomInit)
+	{
+		RandomLayoutOneTree(RootNode, TreeBound);
+	}
+
+	float RepulseForce, AttractForce, Distance;
+	FVector2D Diff;
+
+	TMap<UEdGraphNode*, FVector2D> NodeToDisplacement;
+
+	for (int32 i = 0; i < EdGraph->Nodes.Num(); ++i)
+	{
+		NodeToDisplacement.Add(EdGraph->Nodes[i], FVector2D(0.f, 0.f));
+	}
+
+	for (int32 IterrationNum = 0; IterrationNum < MaxIteration; ++IterrationNum)
+	{
+		// Calculate the repulsive forces.
+		for (int32 i = 0; i < EdGraph->Nodes.Num(); ++i)
+		{
+			for (int32 j = 0; j < EdGraph->Nodes.Num(); ++j)
+			{
+				if (i == j)
+					continue;
+				Diff.X = EdGraph->Nodes[i]->NodePosX - EdGraph->Nodes[j]->NodePosX;
+				Diff.Y = EdGraph->Nodes[i]->NodePosY - EdGraph->Nodes[j]->NodePosY;
+				Distance = Diff.Size();
+				Diff.Normalize();
+
+				RepulseForce = Distance > 2 * OptimalDistance ? 0 : GetRepulseForce(Distance, OptimalDistance);
+
+				NodeToDisplacement[EdGraph->Nodes[i]] += Diff * RepulseForce;
+			}
+		}
+
+		// Calculate the attractive forces.
+		int Level = 0;
+		TArray<UGenericGraphNode*> CurrLevelNodes = { RootNode };
+		TArray<UGenericGraphNode*> NextLevelNodes;
+
+		while (CurrLevelNodes.Num() != 0)
+		{
+			for (int32 i = 0; i < CurrLevelNodes.Num(); ++i)
+			{
+				UGenericGraphNode* Node = CurrLevelNodes[i];
+				check(Node != nullptr);
+
+				UEdNode_GenericGraphNode* EdNode_ParentNode = EdGraph->NodeMap[Node];
+
+				for (int32 j = 0; j < Node->ChildrenNodes.Num(); ++j)
+				{
+					NextLevelNodes.Add(Node->ChildrenNodes[j]);
+
+					UEdNode_GenericGraphNode* EdNode_ChildNode = EdGraph->NodeMap[Node->ChildrenNodes[j]];
+
+					Diff.X = EdNode_ChildNode->NodePosX - EdNode_ParentNode->NodePosY;
+					Diff.Y = EdNode_ChildNode->NodePosY - EdNode_ParentNode->NodePosY;
+					Distance = Diff.Size();
+					Diff.Normalize();
+
+					AttractForce = GetAttractForce(Distance, OptimalDistance);
+
+					NodeToDisplacement[EdNode_ParentNode] += Distance * Diff;
+					NodeToDisplacement[EdNode_ChildNode] -= Distance * Diff;
+				}
+			}
+
+			CurrLevelNodes = NextLevelNodes;
+			NextLevelNodes.Reset();
+			++Level;
+		}
+
+		for (int32 i = 0; i < EdGraph->Nodes.Num(); ++i)
+		{
+			UEdGraphNode* EdNode = EdGraph->Nodes[i];
+			Distance = NodeToDisplacement[EdNode].Size();
+			NodeToDisplacement[EdNode].Normalize();
+
+			float Minimum = Distance < Temp ? Distance : Temp;
+			EdNode->NodePosX += NodeToDisplacement[EdNode].X * Minimum;
+			EdNode->NodePosY += NodeToDisplacement[EdNode].Y * Minimum;
+		}
+
+		Temp = CoolDown(Temp, CoolDownRate);
+	}
+
+	FBox2D ActualBound = GetActualBounds(RootNode);
+
+	FVector2D Center = ActualBound.GetCenter();
+	FVector2D TreeCenter = TreeBound.GetCenter();
+
+	FVector2D Scale = (TreeBound.Max - TreeBound.Min) / (ActualBound.Max - ActualBound.Min);
+
+	for (int32 i = 0; i < EdGraph->Nodes.Num(); ++i)
+	{
+		UEdGraphNode* EdNode = EdGraph->Nodes[i];
+		EdNode->NodePosX = TreeCenter.X + Scale.X * (EdNode->NodePosX - Center.X);
+		EdNode->NodePosY = TreeCenter.Y + Scale.Y * (EdNode->NodePosY - Center.Y);
+	}
+
+	return TreeBound;
+}
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/AutoLayout/TreeLayoutStrategy.cpp b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/AutoLayout/TreeLayoutStrategy.cpp
new file mode 100644
index 00000000..93163208
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/AutoLayout/TreeLayoutStrategy.cpp
@@ -0,0 +1,241 @@
+#include "AutoLayout/TreeLayoutStrategy.h"
+#include "GenericGraphEditorPCH.h"
+#include "GenericGraphAssetEditor/SEdNode_GenericGraphNode.h"
+
+UTreeLayoutStrategy::UTreeLayoutStrategy()
+{
+}
+
+UTreeLayoutStrategy::~UTreeLayoutStrategy()
+{
+
+}
+
+void UTreeLayoutStrategy::Layout(UEdGraph* _EdGraph)
+{
+	EdGraph = Cast<UEdGraph_GenericGraph>(_EdGraph);
+	check(EdGraph != nullptr);
+
+	EdGraph->RebuildGenericGraph();
+	Graph = EdGraph->GetGenericGraph();
+	check(Graph != nullptr);
+
+	bool bFirstPassOnly = false;
+
+	if (Settings != nullptr)
+	{
+		OptimalDistance = Settings->OptimalDistance;
+		MaxIteration = Settings->MaxIteration;
+		bFirstPassOnly = Settings->bFirstPassOnly;
+	}
+
+	FVector2D Anchor(0.f, 0.f);
+	for (int32 i = 0; i < Graph->RootNodes.Num(); ++i)
+	{
+		UGenericGraphNode* RootNode = Graph->RootNodes[i];
+		InitPass(RootNode, Anchor);
+
+		if (!bFirstPassOnly)
+		{
+			for (int32 j = 0; j < MaxIteration; ++j)
+			{
+				bool HasConflict = ResolveConflictPass(RootNode);
+				if (!HasConflict)
+				{
+					break;
+				}
+			}
+		}
+	}
+
+	for (int32 i = 0; i < Graph->RootNodes.Num(); ++i)
+	{
+		for (int32 j = 0; j < i; ++j)
+		{
+			ResolveConflict(Graph->RootNodes[j], Graph->RootNodes[i]);
+		}
+	}
+}
+
+void UTreeLayoutStrategy::InitPass(UGenericGraphNode* RootNode, const FVector2D& Anchor)
+{
+	UEdNode_GenericGraphNode* EdNode_RootNode = EdGraph->NodeMap[RootNode];
+
+	FVector2D ChildAnchor(FVector2D(0.f, GetNodeHeight(EdNode_RootNode) + OptimalDistance + Anchor.Y));
+	for (int32 i = 0; i < RootNode->ChildrenNodes.Num(); ++i)
+	{
+		UGenericGraphNode* Child = RootNode->ChildrenNodes[i];
+		UEdNode_GenericGraphNode* EdNode_ChildNode = EdGraph->NodeMap[Child];
+		if (i > 0)
+		{
+			UGenericGraphNode* PreChild = RootNode->ChildrenNodes[i - 1];
+			UEdNode_GenericGraphNode* EdNode_PreChildNode = EdGraph->NodeMap[PreChild];
+			ChildAnchor.X += OptimalDistance + GetNodeWidth(EdNode_PreChildNode) / 2;
+		}
+		ChildAnchor.X += GetNodeWidth(EdNode_ChildNode) / 2;
+		InitPass(Child, ChildAnchor);
+	}
+	
+	float NodeWidth = GetNodeWidth(EdNode_RootNode);
+
+	EdNode_RootNode->NodePosY = Anchor.Y;
+	if (RootNode->ChildrenNodes.Num() == 0)
+	{
+		EdNode_RootNode->NodePosX = Anchor.X - NodeWidth / 2;
+	}
+	else
+	{
+		UpdateParentNodePosition(RootNode);
+	}
+}
+
+bool UTreeLayoutStrategy::ResolveConflictPass(UGenericGraphNode* Node)
+{
+	bool HasConflict = false;
+	for (int32 i = 0; i < Node->ChildrenNodes.Num(); ++i)
+	{
+		UGenericGraphNode* Child = Node->ChildrenNodes[i];
+		if (ResolveConflictPass(Child))
+		{
+			HasConflict = true;
+		}
+	}
+
+	for (int32 i = 0; i < Node->ParentNodes.Num(); ++i)
+	{
+		UGenericGraphNode* ParentNode = Node->ParentNodes[i];
+		for (int32 j = 0; j < ParentNode->ChildrenNodes.Num(); ++j)
+		{
+			UGenericGraphNode* LeftSibling = ParentNode->ChildrenNodes[j];
+			if (LeftSibling == Node)
+				break;
+			if (ResolveConflict(LeftSibling, Node))
+			{
+				HasConflict = true;
+			}
+		}
+	}
+
+	return HasConflict;
+}
+
+bool UTreeLayoutStrategy::ResolveConflict(UGenericGraphNode* LRoot, UGenericGraphNode* RRoot)
+{
+	TArray<UEdNode_GenericGraphNode*> RightContour, LeftContour;
+
+	GetRightContour(LRoot, 0, RightContour);
+	GetLeftContour(RRoot, 0, LeftContour);
+
+	int32 MaxOverlapDistance = 0;
+	int32 Num = FMath::Min(LeftContour.Num(), RightContour.Num());
+	for (int32 i = 0; i < Num; ++i)
+	{
+		if (RightContour.Contains(LeftContour[i]) || LeftContour.Contains(RightContour[i]))
+			break;
+
+		int32 RightBound = RightContour[i]->NodePosX + GetNodeWidth(RightContour[i]);
+		int32 LeftBound = LeftContour[i]->NodePosX;
+		int32 Distance = RightBound + OptimalDistance - LeftBound;
+		if (Distance > MaxOverlapDistance)
+		{
+			MaxOverlapDistance = Distance;
+		}
+	}
+
+	if (MaxOverlapDistance > 0)
+	{
+		ShiftSubTree(RRoot, FVector2D(MaxOverlapDistance, 0.f));
+
+		TArray<UGenericGraphNode*> ParentNodes = RRoot->ParentNodes;
+		TArray<UGenericGraphNode*> NextParentNodes;
+		while (ParentNodes.Num() != 0)
+		{
+			for (int32 i = 0; i < ParentNodes.Num(); ++i)
+			{
+				UpdateParentNodePosition(ParentNodes[i]);
+
+				NextParentNodes.Append(ParentNodes[i]->ParentNodes);
+			}
+
+			ParentNodes = NextParentNodes;
+			NextParentNodes.Reset();
+		}
+
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+void UTreeLayoutStrategy::GetLeftContour(UGenericGraphNode* RootNode, int32 Level, TArray<UEdNode_GenericGraphNode*>& Contour)
+{
+	UEdNode_GenericGraphNode* EdNode_Node = EdGraph->NodeMap[RootNode];
+	if (Level >= Contour.Num())
+	{
+		Contour.Add(EdNode_Node);
+	}
+	else if (EdNode_Node->NodePosX < Contour[Level]->NodePosX)
+	{
+		Contour[Level] = EdNode_Node;
+	}
+
+	for (int32 i = 0; i < RootNode->ChildrenNodes.Num(); ++i)
+	{
+		GetLeftContour(RootNode->ChildrenNodes[i], Level + 1, Contour);
+	}
+}
+
+void UTreeLayoutStrategy::GetRightContour(UGenericGraphNode* RootNode, int32 Level, TArray<UEdNode_GenericGraphNode*>& Contour)
+{
+	UEdNode_GenericGraphNode* EdNode_Node = EdGraph->NodeMap[RootNode];
+	if (Level >= Contour.Num())
+	{
+		Contour.Add(EdNode_Node);
+	}
+	else if (EdNode_Node->NodePosX + GetNodeWidth(EdNode_Node) > Contour[Level]->NodePosX + GetNodeWidth(Contour[Level]))
+	{
+		Contour[Level] = EdNode_Node;
+	}
+
+	for (int32 i = 0; i < RootNode->ChildrenNodes.Num(); ++i)
+	{
+		GetRightContour(RootNode->ChildrenNodes[i], Level + 1, Contour);
+	}
+}
+
+void UTreeLayoutStrategy::ShiftSubTree(UGenericGraphNode* RootNode, const FVector2D& Offset)
+{
+	UEdNode_GenericGraphNode* EdNode_Node = EdGraph->NodeMap[RootNode];
+	EdNode_Node->NodePosX += Offset.X;
+	EdNode_Node->NodePosY += Offset.Y;
+
+	for (int32 i = 0; i < RootNode->ChildrenNodes.Num(); ++i)
+	{
+		UGenericGraphNode* Child = RootNode->ChildrenNodes[i];
+
+		if (Child->ParentNodes[0] == RootNode)
+		{
+			ShiftSubTree(RootNode->ChildrenNodes[i], Offset);
+		}
+	}
+}
+
+void UTreeLayoutStrategy::UpdateParentNodePosition(UGenericGraphNode* ParentNode)
+{
+	UEdNode_GenericGraphNode* EdNode_ParentNode = EdGraph->NodeMap[ParentNode];
+	if (ParentNode->ChildrenNodes.Num() % 2 == 0)
+	{
+		UEdNode_GenericGraphNode* FirstChild = EdGraph->NodeMap[ParentNode->ChildrenNodes[0]];
+		UEdNode_GenericGraphNode* LastChild = EdGraph->NodeMap[ParentNode->ChildrenNodes.Last()];
+		float LeftBound = FirstChild->NodePosX;
+		float RightBound = LastChild->NodePosX + GetNodeWidth(LastChild);
+		EdNode_ParentNode->NodePosX = (LeftBound + RightBound) / 2 - GetNodeWidth(EdNode_ParentNode) / 2;
+	}
+	else
+	{
+		UEdNode_GenericGraphNode* MidChild = EdGraph->NodeMap[ParentNode->ChildrenNodes[ParentNode->ChildrenNodes.Num() / 2]];
+		EdNode_ParentNode->NodePosX = MidChild->NodePosX + GetNodeWidth(MidChild) / 2 - GetNodeWidth(EdNode_ParentNode) / 2;
+	}
+}
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/AssetEditorToolbar_GenericGraph.cpp b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/AssetEditorToolbar_GenericGraph.cpp
new file mode 100644
index 00000000..1d9127cc
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/AssetEditorToolbar_GenericGraph.cpp
@@ -0,0 +1,46 @@
+#include "GenericGraphAssetEditor/AssetEditorToolbar_GenericGraph.h"
+#include "GenericGraphAssetEditor/AssetEditor_GenericGraph.h"
+#include "GenericGraphAssetEditor/EditorCommands_GenericGraph.h"
+#include "GenericGraphAssetEditor/GenericGraphEditorStyle.h"
+
+#define LOCTEXT_NAMESPACE "AssetEditorToolbar_GenericGraph"
+
+void FAssetEditorToolbar_GenericGraph::AddGenericGraphToolbar(TSharedPtr<FExtender> Extender)
+{
+	check(GenericGraphEditor.IsValid());
+	TSharedPtr<FAssetEditor_GenericGraph> GenericGraphEditorPtr = GenericGraphEditor.Pin();
+
+	TSharedPtr<FExtender> ToolbarExtender = MakeShareable(new FExtender);
+	ToolbarExtender->AddToolBarExtension("Asset", EExtensionHook::After, GenericGraphEditorPtr->GetToolkitCommands(), FToolBarExtensionDelegate::CreateSP( this, &FAssetEditorToolbar_GenericGraph::FillGenericGraphToolbar ));
+	GenericGraphEditorPtr->AddToolbarExtender(ToolbarExtender);
+}
+
+void FAssetEditorToolbar_GenericGraph::FillGenericGraphToolbar(FToolBarBuilder& ToolbarBuilder)
+{
+	check(GenericGraphEditor.IsValid());
+	TSharedPtr<FAssetEditor_GenericGraph> GenericGraphEditorPtr = GenericGraphEditor.Pin();
+
+	ToolbarBuilder.BeginSection("Generic Graph");
+	{
+		ToolbarBuilder.AddToolBarButton(FEditorCommands_GenericGraph::Get().GraphSettings,
+			NAME_None,
+			LOCTEXT("GraphSettings_Label", "Graph Settings"),
+			LOCTEXT("GraphSettings_ToolTip", "Show the Graph Settings"),
+			FSlateIcon(FAppStyle::GetAppStyleSetName(), "LevelEditor.GameSettings"));
+	}
+	ToolbarBuilder.EndSection();
+
+	ToolbarBuilder.BeginSection("Util");
+	{
+		ToolbarBuilder.AddToolBarButton(FEditorCommands_GenericGraph::Get().AutoArrange,
+			NAME_None,
+			LOCTEXT("AutoArrange_Label", "Auto Arrange"),
+			LOCTEXT("AutoArrange_ToolTip", "Auto arrange nodes, not perfect, but still handy"),
+			FSlateIcon(FGenericGraphEditorStyle::GetStyleSetName(), "GenericGraphEditor.AutoArrange"));
+	}
+	ToolbarBuilder.EndSection();
+
+}
+
+
+#undef LOCTEXT_NAMESPACE
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/AssetEditor_GenericGraph.cpp b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/AssetEditor_GenericGraph.cpp
new file mode 100644
index 00000000..68507d39
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/AssetEditor_GenericGraph.cpp
@@ -0,0 +1,819 @@
+#include "GenericGraphAssetEditor/AssetEditor_GenericGraph.h"
+#include "GenericGraphEditorPCH.h"
+#include "GenericGraphAssetEditor/AssetEditorToolbar_GenericGraph.h"
+#include "GenericGraphAssetEditor/AssetGraphSchema_GenericGraph.h"
+#include "GenericGraphAssetEditor/EditorCommands_GenericGraph.h"
+#include "GenericGraphAssetEditor/EdGraph_GenericGraph.h"
+#include "AssetToolsModule.h"
+#include "HAL/PlatformApplicationMisc.h"
+#include "Framework/Commands/GenericCommands.h"
+#include "GraphEditorActions.h"
+#include "IDetailsView.h"
+#include "PropertyEditorModule.h"
+#include "Editor/UnrealEd/Public/Kismet2/BlueprintEditorUtils.h"
+#include "Kismet2/KismetEditorUtilities.h"
+#include "EdGraphUtilities.h"
+#include "GenericGraphAssetEditor/EdGraph_GenericGraph.h"
+#include "GenericGraphAssetEditor/EdNode_GenericGraphNode.h"
+#include "GenericGraphAssetEditor/EdNode_GenericGraphEdge.h"
+#include "AutoLayout/TreeLayoutStrategy.h"
+#include "AutoLayout/ForceDirectedLayoutStrategy.h"
+
+#define LOCTEXT_NAMESPACE "AssetEditor_GenericGraph"
+
+const FName GenericGraphEditorAppName = FName(TEXT("GenericGraphEditorApp"));
+
+struct FGenericGraphAssetEditorTabs
+{
+	// Tab identifiers
+	static const FName GenericGraphPropertyID;
+	static const FName ViewportID;
+	static const FName GenericGraphEditorSettingsID;
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+const FName FGenericGraphAssetEditorTabs::GenericGraphPropertyID(TEXT("GenericGraphProperty"));
+const FName FGenericGraphAssetEditorTabs::ViewportID(TEXT("Viewport"));
+const FName FGenericGraphAssetEditorTabs::GenericGraphEditorSettingsID(TEXT("GenericGraphEditorSettings"));
+
+//////////////////////////////////////////////////////////////////////////
+
+FAssetEditor_GenericGraph::FAssetEditor_GenericGraph()
+{
+	EditingGraph = nullptr;
+
+	GenricGraphEditorSettings = NewObject<UGenericGraphEditorSettings>(UGenericGraphEditorSettings::StaticClass());
+
+#if ENGINE_MAJOR_VERSION < 5
+	OnPackageSavedDelegateHandle = UPackage::PackageSavedEvent.AddRaw(this, &FAssetEditor_GenericGraph::OnPackageSaved);
+#else // #if ENGINE_MAJOR_VERSION < 5
+	OnPackageSavedDelegateHandle = UPackage::PackageSavedWithContextEvent.AddRaw(this, &FAssetEditor_GenericGraph::OnPackageSavedWithContext);
+#endif // #else // #if ENGINE_MAJOR_VERSION < 5
+}
+
+FAssetEditor_GenericGraph::~FAssetEditor_GenericGraph()
+{
+#if ENGINE_MAJOR_VERSION < 5
+	UPackage::PackageSavedEvent.Remove(OnPackageSavedDelegateHandle);
+#else // #if ENGINE_MAJOR_VERSION < 5
+	UPackage::PackageSavedWithContextEvent.Remove(OnPackageSavedDelegateHandle);
+#endif // #else // #if ENGINE_MAJOR_VERSION < 5
+}
+
+void FAssetEditor_GenericGraph::InitGenericGraphAssetEditor(const EToolkitMode::Type Mode, const TSharedPtr< IToolkitHost >& InitToolkitHost, UGenericGraph* Graph)
+{
+	EditingGraph = Graph;
+	CreateEdGraph();
+
+	FGenericCommands::Register();
+	FGraphEditorCommands::Register();
+	FEditorCommands_GenericGraph::Register();
+
+	if (!ToolbarBuilder.IsValid())
+	{
+		ToolbarBuilder = MakeShareable(new FAssetEditorToolbar_GenericGraph(SharedThis(this)));
+	}
+
+	BindCommands();
+
+	CreateInternalWidgets();
+
+	TSharedPtr<FExtender> ToolbarExtender = MakeShareable(new FExtender);
+
+	ToolbarBuilder->AddGenericGraphToolbar(ToolbarExtender);
+
+	// Layout
+	const TSharedRef<FTabManager::FLayout> StandaloneDefaultLayout = FTabManager::NewLayout("Standalone_GenericGraphEditor_Layout_v1")
+		->AddArea
+		(
+			FTabManager::NewPrimaryArea()->SetOrientation(Orient_Vertical)
+#if ENGINE_MAJOR_VERSION < 5
+			->Split
+			(
+				FTabManager::NewStack()
+				->SetSizeCoefficient(0.1f)
+				->AddTab(GetToolbarTabId(), ETabState::OpenedTab)->SetHideTabWell(true)
+			)
+#endif // #if ENGINE_MAJOR_VERSION < 5
+			->Split
+			(
+				FTabManager::NewSplitter()->SetOrientation(Orient_Horizontal)->SetSizeCoefficient(0.9f)
+				->Split
+				(
+					FTabManager::NewStack()
+					->SetSizeCoefficient(0.65f)
+					->AddTab(FGenericGraphAssetEditorTabs::ViewportID, ETabState::OpenedTab)->SetHideTabWell(true)
+				)
+				->Split
+				(
+					FTabManager::NewSplitter()->SetOrientation(Orient_Vertical)
+					->Split
+					(
+						FTabManager::NewStack()
+						->SetSizeCoefficient(0.7f)
+						->AddTab(FGenericGraphAssetEditorTabs::GenericGraphPropertyID, ETabState::OpenedTab)->SetHideTabWell(true)
+					)
+					->Split
+					(
+						FTabManager::NewStack()
+						->SetSizeCoefficient(0.3f)
+						->AddTab(FGenericGraphAssetEditorTabs::GenericGraphEditorSettingsID, ETabState::OpenedTab)
+					)
+				)
+			)
+		);
+
+	const bool bCreateDefaultStandaloneMenu = true;
+	const bool bCreateDefaultToolbar = true;
+	FAssetEditorToolkit::InitAssetEditor(Mode, InitToolkitHost, GenericGraphEditorAppName, StandaloneDefaultLayout, bCreateDefaultStandaloneMenu, bCreateDefaultToolbar, EditingGraph, false);
+
+	RegenerateMenusAndToolbars();
+}
+
+void FAssetEditor_GenericGraph::RegisterTabSpawners(const TSharedRef<FTabManager>& InTabManager)
+{
+	WorkspaceMenuCategory = InTabManager->AddLocalWorkspaceMenuCategory(LOCTEXT("WorkspaceMenu_GenericGraphEditor", "Generic Graph Editor"));
+	auto WorkspaceMenuCategoryRef = WorkspaceMenuCategory.ToSharedRef();
+
+	FAssetEditorToolkit::RegisterTabSpawners(InTabManager);
+
+	InTabManager->RegisterTabSpawner(FGenericGraphAssetEditorTabs::ViewportID, FOnSpawnTab::CreateSP(this, &FAssetEditor_GenericGraph::SpawnTab_Viewport))
+		.SetDisplayName(LOCTEXT("GraphCanvasTab", "Viewport"))
+		.SetGroup(WorkspaceMenuCategoryRef)
+		.SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "GraphEditor.EventGraph_16x"));
+
+	InTabManager->RegisterTabSpawner(FGenericGraphAssetEditorTabs::GenericGraphPropertyID, FOnSpawnTab::CreateSP(this, &FAssetEditor_GenericGraph::SpawnTab_Details))
+		.SetDisplayName(LOCTEXT("DetailsTab", "Property"))
+		.SetGroup(WorkspaceMenuCategoryRef)
+		.SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "LevelEditor.Tabs.Details"));
+
+	InTabManager->RegisterTabSpawner(FGenericGraphAssetEditorTabs::GenericGraphEditorSettingsID, FOnSpawnTab::CreateSP(this, &FAssetEditor_GenericGraph::SpawnTab_EditorSettings))
+		.SetDisplayName(LOCTEXT("EditorSettingsTab", "Generic Graph Editor Setttings"))
+		.SetGroup(WorkspaceMenuCategoryRef)
+		.SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "LevelEditor.Tabs.Details"));
+}
+
+void FAssetEditor_GenericGraph::UnregisterTabSpawners(const TSharedRef<FTabManager>& InTabManager)
+{
+	FAssetEditorToolkit::UnregisterTabSpawners(InTabManager);
+
+	InTabManager->UnregisterTabSpawner(FGenericGraphAssetEditorTabs::ViewportID);
+	InTabManager->UnregisterTabSpawner(FGenericGraphAssetEditorTabs::GenericGraphPropertyID);
+	InTabManager->UnregisterTabSpawner(FGenericGraphAssetEditorTabs::GenericGraphEditorSettingsID);
+}
+
+FName FAssetEditor_GenericGraph::GetToolkitFName() const
+{
+	return FName("FGenericGraphEditor");
+}
+
+FText FAssetEditor_GenericGraph::GetBaseToolkitName() const
+{
+	return LOCTEXT("GenericGraphEditorAppLabel", "Generic Graph Editor");
+}
+
+FText FAssetEditor_GenericGraph::GetToolkitName() const
+{
+	const bool bDirtyState = EditingGraph->GetOutermost()->IsDirty();
+
+	FFormatNamedArguments Args;
+	Args.Add(TEXT("GenericGraphName"), FText::FromString(EditingGraph->GetName()));
+	Args.Add(TEXT("DirtyState"), bDirtyState ? FText::FromString(TEXT("*")) : FText::GetEmpty());
+	return FText::Format(LOCTEXT("GenericGraphEditorToolkitName", "{GenericGraphName}{DirtyState}"), Args);
+}
+
+FText FAssetEditor_GenericGraph::GetToolkitToolTipText() const
+{
+	return FAssetEditorToolkit::GetToolTipTextForObject(EditingGraph);
+}
+
+FLinearColor FAssetEditor_GenericGraph::GetWorldCentricTabColorScale() const
+{
+	return FLinearColor::White;
+}
+
+FString FAssetEditor_GenericGraph::GetWorldCentricTabPrefix() const
+{
+	return TEXT("GenericGraphEditor");
+}
+
+FString FAssetEditor_GenericGraph::GetDocumentationLink() const
+{
+	return TEXT("");
+}
+
+void FAssetEditor_GenericGraph::SaveAsset_Execute()
+{
+	if (EditingGraph != nullptr)
+	{
+		RebuildGenericGraph();
+	}
+
+	FAssetEditorToolkit::SaveAsset_Execute();
+}
+
+void FAssetEditor_GenericGraph::AddReferencedObjects(FReferenceCollector& Collector)
+{
+	Collector.AddReferencedObject(EditingGraph);
+	Collector.AddReferencedObject(EditingGraph->EdGraph);
+}
+
+UGenericGraphEditorSettings* FAssetEditor_GenericGraph::GetSettings() const
+{
+	return GenricGraphEditorSettings;
+}
+
+TSharedRef<SDockTab> FAssetEditor_GenericGraph::SpawnTab_Viewport(const FSpawnTabArgs& Args)
+{
+	check(Args.GetTabId() == FGenericGraphAssetEditorTabs::ViewportID);
+
+	TSharedRef<SDockTab> SpawnedTab = SNew(SDockTab)
+		.Label(LOCTEXT("ViewportTab_Title", "Viewport"));
+
+	if (ViewportWidget.IsValid())
+	{
+		SpawnedTab->SetContent(ViewportWidget.ToSharedRef());
+	}
+
+	return SpawnedTab;
+}
+
+TSharedRef<SDockTab> FAssetEditor_GenericGraph::SpawnTab_Details(const FSpawnTabArgs& Args)
+{
+	check(Args.GetTabId() == FGenericGraphAssetEditorTabs::GenericGraphPropertyID);
+
+	return SNew(SDockTab)
+#if ENGINE_MAJOR_VERSION < 5
+		.Icon(FAppStyle::GetBrush("LevelEditor.Tabs.Details"))
+#endif // #if ENGINE_MAJOR_VERSION < 5
+		.Label(LOCTEXT("Details_Title", "Property"))
+		[
+			PropertyWidget.ToSharedRef()
+		];
+}
+
+TSharedRef<SDockTab> FAssetEditor_GenericGraph::SpawnTab_EditorSettings(const FSpawnTabArgs& Args)
+{
+	check(Args.GetTabId() == FGenericGraphAssetEditorTabs::GenericGraphEditorSettingsID);
+
+	return SNew(SDockTab)
+#if ENGINE_MAJOR_VERSION < 5
+		.Icon(FAppStyle::GetBrush("LevelEditor.Tabs.Details"))
+#endif // #if ENGINE_MAJOR_VERSION < 5
+		.Label(LOCTEXT("EditorSettings_Title", "Generic Graph Editor Setttings"))
+		[
+			EditorSettingsWidget.ToSharedRef()
+		];
+}
+
+void FAssetEditor_GenericGraph::CreateInternalWidgets()
+{
+	ViewportWidget = CreateViewportWidget();
+
+	FDetailsViewArgs Args;
+	Args.bHideSelectionTip = true;
+	Args.NotifyHook = this;
+
+	FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");
+	PropertyWidget = PropertyModule.CreateDetailView(Args);
+	PropertyWidget->SetObject(EditingGraph);
+	PropertyWidget->OnFinishedChangingProperties().AddSP(this, &FAssetEditor_GenericGraph::OnFinishedChangingProperties);
+
+	EditorSettingsWidget = PropertyModule.CreateDetailView(Args);
+	EditorSettingsWidget->SetObject(GenricGraphEditorSettings);
+}
+
+TSharedRef<SGraphEditor> FAssetEditor_GenericGraph::CreateViewportWidget()
+{
+	FGraphAppearanceInfo AppearanceInfo;
+	AppearanceInfo.CornerText = LOCTEXT("AppearanceCornerText_GenericGraph", "Generic Graph");
+
+	CreateCommandList();
+
+	SGraphEditor::FGraphEditorEvents InEvents;
+	InEvents.OnSelectionChanged = SGraphEditor::FOnSelectionChanged::CreateSP(this, &FAssetEditor_GenericGraph::OnSelectedNodesChanged);
+	InEvents.OnNodeDoubleClicked = FSingleNodeEvent::CreateSP(this, &FAssetEditor_GenericGraph::OnNodeDoubleClicked);
+
+	return SNew(SGraphEditor)
+		.AdditionalCommands(GraphEditorCommands)
+		.IsEditable(true)
+		.Appearance(AppearanceInfo)
+		.GraphToEdit(EditingGraph->EdGraph)
+		.GraphEvents(InEvents)
+		.AutoExpandActionMenu(true)
+		.ShowGraphStateOverlay(false);
+}
+
+void FAssetEditor_GenericGraph::BindCommands()
+{
+	ToolkitCommands->MapAction(FEditorCommands_GenericGraph::Get().GraphSettings,
+		FExecuteAction::CreateSP(this, &FAssetEditor_GenericGraph::GraphSettings),
+		FCanExecuteAction::CreateSP(this, &FAssetEditor_GenericGraph::CanGraphSettings)
+	);
+
+	ToolkitCommands->MapAction(FEditorCommands_GenericGraph::Get().AutoArrange,
+		FExecuteAction::CreateSP(this, &FAssetEditor_GenericGraph::AutoArrange),
+		FCanExecuteAction::CreateSP(this, &FAssetEditor_GenericGraph::CanAutoArrange)
+	);
+}
+
+void FAssetEditor_GenericGraph::CreateEdGraph()
+{
+	if (EditingGraph->EdGraph == nullptr)
+	{
+		EditingGraph->EdGraph = CastChecked<UEdGraph_GenericGraph>(FBlueprintEditorUtils::CreateNewGraph(EditingGraph, NAME_None, UEdGraph_GenericGraph::StaticClass(), UAssetGraphSchema_GenericGraph::StaticClass()));
+		EditingGraph->EdGraph->bAllowDeletion = false;
+
+		// Give the schema a chance to fill out any required nodes (like the results node)
+		const UEdGraphSchema* Schema = EditingGraph->EdGraph->GetSchema();
+		Schema->CreateDefaultNodesForGraph(*EditingGraph->EdGraph);
+	}
+}
+
+void FAssetEditor_GenericGraph::CreateCommandList()
+{
+	if (GraphEditorCommands.IsValid())
+	{
+		return;
+	}
+
+	GraphEditorCommands = MakeShareable(new FUICommandList);
+
+	// Can't use CreateSP here because derived editor are already implementing TSharedFromThis<FAssetEditorToolkit>
+	// however it should be safe, since commands are being used only within this editor
+	// if it ever crashes, this function will have to go away and be reimplemented in each derived class
+
+	GraphEditorCommands->MapAction(FEditorCommands_GenericGraph::Get().GraphSettings,
+		FExecuteAction::CreateRaw(this, &FAssetEditor_GenericGraph::GraphSettings),
+		FCanExecuteAction::CreateRaw(this, &FAssetEditor_GenericGraph::CanGraphSettings));
+
+	GraphEditorCommands->MapAction(FEditorCommands_GenericGraph::Get().AutoArrange,
+		FExecuteAction::CreateRaw(this, &FAssetEditor_GenericGraph::AutoArrange),
+		FCanExecuteAction::CreateRaw(this, &FAssetEditor_GenericGraph::CanAutoArrange));
+
+	GraphEditorCommands->MapAction(FGenericCommands::Get().SelectAll,
+		FExecuteAction::CreateRaw(this, &FAssetEditor_GenericGraph::SelectAllNodes),
+		FCanExecuteAction::CreateRaw(this, &FAssetEditor_GenericGraph::CanSelectAllNodes)
+	);
+
+	GraphEditorCommands->MapAction(FGenericCommands::Get().Delete,
+		FExecuteAction::CreateRaw(this, &FAssetEditor_GenericGraph::DeleteSelectedNodes),
+		FCanExecuteAction::CreateRaw(this, &FAssetEditor_GenericGraph::CanDeleteNodes)
+	);
+
+	GraphEditorCommands->MapAction(FGenericCommands::Get().Copy,
+		FExecuteAction::CreateRaw(this, &FAssetEditor_GenericGraph::CopySelectedNodes),
+		FCanExecuteAction::CreateRaw(this, &FAssetEditor_GenericGraph::CanCopyNodes)
+	);
+
+	GraphEditorCommands->MapAction(FGenericCommands::Get().Cut,
+		FExecuteAction::CreateRaw(this, &FAssetEditor_GenericGraph::CutSelectedNodes),
+		FCanExecuteAction::CreateRaw(this, &FAssetEditor_GenericGraph::CanCutNodes)
+	);
+
+	GraphEditorCommands->MapAction(FGenericCommands::Get().Paste,
+		FExecuteAction::CreateRaw(this, &FAssetEditor_GenericGraph::PasteNodes),
+		FCanExecuteAction::CreateRaw(this, &FAssetEditor_GenericGraph::CanPasteNodes)
+	);
+
+	GraphEditorCommands->MapAction(FGenericCommands::Get().Duplicate,
+		FExecuteAction::CreateRaw(this, &FAssetEditor_GenericGraph::DuplicateNodes),
+		FCanExecuteAction::CreateRaw(this, &FAssetEditor_GenericGraph::CanDuplicateNodes)
+	);
+
+	GraphEditorCommands->MapAction(FGenericCommands::Get().Rename,
+		FExecuteAction::CreateSP(this, &FAssetEditor_GenericGraph::OnRenameNode),
+		FCanExecuteAction::CreateSP(this, &FAssetEditor_GenericGraph::CanRenameNodes)
+	);
+}
+
+TSharedPtr<SGraphEditor> FAssetEditor_GenericGraph::GetCurrGraphEditor() const
+{
+	return ViewportWidget;
+}
+
+FGraphPanelSelectionSet FAssetEditor_GenericGraph::GetSelectedNodes() const
+{
+	FGraphPanelSelectionSet CurrentSelection;
+	TSharedPtr<SGraphEditor> FocusedGraphEd = GetCurrGraphEditor();
+	if (FocusedGraphEd.IsValid())
+	{
+		CurrentSelection = FocusedGraphEd->GetSelectedNodes();
+	}
+
+	return CurrentSelection;
+}
+
+void FAssetEditor_GenericGraph::RebuildGenericGraph()
+{
+	if (EditingGraph == nullptr)
+	{
+		LOG_WARNING(TEXT("FGenericGraphAssetEditor::RebuildGenericGraph EditingGraph is nullptr"));
+		return;
+	}
+
+	UEdGraph_GenericGraph* EdGraph = Cast<UEdGraph_GenericGraph>(EditingGraph->EdGraph);
+	check(EdGraph != nullptr);
+
+	EdGraph->RebuildGenericGraph();
+}
+
+void FAssetEditor_GenericGraph::SelectAllNodes()
+{
+	TSharedPtr<SGraphEditor> CurrentGraphEditor = GetCurrGraphEditor();
+	if (CurrentGraphEditor.IsValid())
+	{
+		CurrentGraphEditor->SelectAllNodes();
+	}
+}
+
+bool FAssetEditor_GenericGraph::CanSelectAllNodes()
+{
+	return true;
+}
+
+void FAssetEditor_GenericGraph::DeleteSelectedNodes()
+{
+	TSharedPtr<SGraphEditor> CurrentGraphEditor = GetCurrGraphEditor();
+	if (!CurrentGraphEditor.IsValid())
+	{
+		return;
+	}
+
+	const FScopedTransaction Transaction(FGenericCommands::Get().Delete->GetDescription());
+
+	CurrentGraphEditor->GetCurrentGraph()->Modify();
+
+	const FGraphPanelSelectionSet SelectedNodes = CurrentGraphEditor->GetSelectedNodes();
+	CurrentGraphEditor->ClearSelectionSet();
+
+	for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt)
+	{
+		UEdGraphNode* EdNode = Cast<UEdGraphNode>(*NodeIt);
+		if (EdNode == nullptr || !EdNode->CanUserDeleteNode())
+			continue;;
+
+		if (UEdNode_GenericGraphNode* EdNode_Node = Cast<UEdNode_GenericGraphNode>(EdNode))
+		{
+			EdNode_Node->Modify();
+
+			const UEdGraphSchema* Schema = EdNode_Node->GetSchema();
+			if (Schema != nullptr)
+			{
+				Schema->BreakNodeLinks(*EdNode_Node);
+			}
+
+			EdNode_Node->DestroyNode();
+		}
+		else
+		{
+			EdNode->Modify();
+			EdNode->DestroyNode();
+		}
+	}
+}
+
+bool FAssetEditor_GenericGraph::CanDeleteNodes()
+{
+	// If any of the nodes can be deleted then we should allow deleting
+	const FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes();
+	for (FGraphPanelSelectionSet::TConstIterator SelectedIter(SelectedNodes); SelectedIter; ++SelectedIter)
+	{
+		UEdGraphNode* Node = Cast<UEdGraphNode>(*SelectedIter);
+		if (Node != nullptr && Node->CanUserDeleteNode())
+		{
+			return true;
+		}
+	}
+
+	return false;
+}
+
+void FAssetEditor_GenericGraph::DeleteSelectedDuplicatableNodes()
+{
+	TSharedPtr<SGraphEditor> CurrentGraphEditor = GetCurrGraphEditor();
+	if (!CurrentGraphEditor.IsValid())
+	{
+		return;
+	}
+
+	const FGraphPanelSelectionSet OldSelectedNodes = CurrentGraphEditor->GetSelectedNodes();
+	CurrentGraphEditor->ClearSelectionSet();
+
+	for (FGraphPanelSelectionSet::TConstIterator SelectedIter(OldSelectedNodes); SelectedIter; ++SelectedIter)
+	{
+		UEdGraphNode* Node = Cast<UEdGraphNode>(*SelectedIter);
+		if (Node && Node->CanDuplicateNode())
+		{
+			CurrentGraphEditor->SetNodeSelection(Node, true);
+		}
+	}
+
+	// Delete the duplicatable nodes
+	DeleteSelectedNodes();
+
+	CurrentGraphEditor->ClearSelectionSet();
+
+	for (FGraphPanelSelectionSet::TConstIterator SelectedIter(OldSelectedNodes); SelectedIter; ++SelectedIter)
+	{
+		if (UEdGraphNode* Node = Cast<UEdGraphNode>(*SelectedIter))
+		{
+			CurrentGraphEditor->SetNodeSelection(Node, true);
+		}
+	}
+}
+
+void FAssetEditor_GenericGraph::CutSelectedNodes()
+{
+	CopySelectedNodes();
+	DeleteSelectedDuplicatableNodes();
+}
+
+bool FAssetEditor_GenericGraph::CanCutNodes()
+{
+	return CanCopyNodes() && CanDeleteNodes();
+}
+
+void FAssetEditor_GenericGraph::CopySelectedNodes()
+{
+	// Export the selected nodes and place the text on the clipboard
+	FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes();
+
+	FString ExportedText;
+
+	for (FGraphPanelSelectionSet::TIterator SelectedIter(SelectedNodes); SelectedIter; ++SelectedIter)
+	{
+		UEdGraphNode* Node = Cast<UEdGraphNode>(*SelectedIter);
+		if (Node == nullptr)
+		{
+			SelectedIter.RemoveCurrent();
+			continue;
+		}
+
+		if (UEdNode_GenericGraphEdge* EdNode_Edge = Cast<UEdNode_GenericGraphEdge>(*SelectedIter))
+		{
+			UEdNode_GenericGraphNode* StartNode = EdNode_Edge->GetStartNode();
+			UEdNode_GenericGraphNode* EndNode = EdNode_Edge->GetEndNode();
+
+			if (!SelectedNodes.Contains(StartNode) || !SelectedNodes.Contains(EndNode))
+			{
+				SelectedIter.RemoveCurrent();
+				continue;
+			}
+		}
+
+		Node->PrepareForCopying();
+	}
+
+	FEdGraphUtilities::ExportNodesToText(SelectedNodes, ExportedText);
+	FPlatformApplicationMisc::ClipboardCopy(*ExportedText);
+}
+
+bool FAssetEditor_GenericGraph::CanCopyNodes()
+{
+	// If any of the nodes can be duplicated then we should allow copying
+	const FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes();
+	for (FGraphPanelSelectionSet::TConstIterator SelectedIter(SelectedNodes); SelectedIter; ++SelectedIter)
+	{
+		UEdGraphNode* Node = Cast<UEdGraphNode>(*SelectedIter);
+		if (Node && Node->CanDuplicateNode())
+		{
+			return true;
+		}
+	}
+
+	return false;
+}
+
+void FAssetEditor_GenericGraph::PasteNodes()
+{
+	TSharedPtr<SGraphEditor> CurrentGraphEditor = GetCurrGraphEditor();
+	if (CurrentGraphEditor.IsValid())
+	{
+		PasteNodesHere(CurrentGraphEditor->GetPasteLocation());
+	}
+}
+
+void FAssetEditor_GenericGraph::PasteNodesHere(const FVector2D& Location)
+{
+	// Find the graph editor with focus
+	TSharedPtr<SGraphEditor> CurrentGraphEditor = GetCurrGraphEditor();
+	if (!CurrentGraphEditor.IsValid())
+	{
+		return;
+	}
+	// Select the newly pasted stuff
+	UEdGraph* EdGraph = CurrentGraphEditor->GetCurrentGraph();
+
+	{
+		const FScopedTransaction Transaction(FGenericCommands::Get().Paste->GetDescription());
+		EdGraph->Modify();
+
+		// Clear the selection set (newly pasted stuff will be selected)
+		CurrentGraphEditor->ClearSelectionSet();
+
+		// Grab the text to paste from the clipboard.
+		FString TextToImport;
+		FPlatformApplicationMisc::ClipboardPaste(TextToImport);
+
+		// Import the nodes
+		TSet<UEdGraphNode*> PastedNodes;
+		FEdGraphUtilities::ImportNodesFromText(EdGraph, TextToImport, PastedNodes);
+
+		//Average position of nodes so we can move them while still maintaining relative distances to each other
+		FVector2D AvgNodePosition(0.0f, 0.0f);
+
+		for (TSet<UEdGraphNode*>::TIterator It(PastedNodes); It; ++It)
+		{
+			UEdGraphNode* Node = *It;
+			AvgNodePosition.X += Node->NodePosX;
+			AvgNodePosition.Y += Node->NodePosY;
+		}
+
+		float InvNumNodes = 1.0f / float(PastedNodes.Num());
+		AvgNodePosition.X *= InvNumNodes;
+		AvgNodePosition.Y *= InvNumNodes;
+
+		for (TSet<UEdGraphNode*>::TIterator It(PastedNodes); It; ++It)
+		{
+			UEdGraphNode* Node = *It;
+			CurrentGraphEditor->SetNodeSelection(Node, true);
+
+			Node->NodePosX = (Node->NodePosX - AvgNodePosition.X) + Location.X;
+			Node->NodePosY = (Node->NodePosY - AvgNodePosition.Y) + Location.Y;
+
+			Node->SnapToGrid(16);
+
+			// Give new node a different Guid from the old one
+			Node->CreateNewGuid();
+		}
+	}
+
+	// Update UI
+	CurrentGraphEditor->NotifyGraphChanged();
+
+	UObject* GraphOwner = EdGraph->GetOuter();
+	if (GraphOwner)
+	{
+		GraphOwner->PostEditChange();
+		GraphOwner->MarkPackageDirty();
+	}
+}
+
+bool FAssetEditor_GenericGraph::CanPasteNodes()
+{
+	TSharedPtr<SGraphEditor> CurrentGraphEditor = GetCurrGraphEditor();
+	if (!CurrentGraphEditor.IsValid())
+	{
+		return false;
+	}
+
+	FString ClipboardContent;
+	FPlatformApplicationMisc::ClipboardPaste(ClipboardContent);
+
+	return FEdGraphUtilities::CanImportNodesFromText(CurrentGraphEditor->GetCurrentGraph(), ClipboardContent);
+}
+
+void FAssetEditor_GenericGraph::DuplicateNodes()
+{
+	CopySelectedNodes();
+	PasteNodes();
+}
+
+bool FAssetEditor_GenericGraph::CanDuplicateNodes()
+{
+	return CanCopyNodes();
+}
+
+void FAssetEditor_GenericGraph::GraphSettings()
+{
+	PropertyWidget->SetObject(EditingGraph);
+}
+
+bool FAssetEditor_GenericGraph::CanGraphSettings() const
+{
+	return true;
+}
+
+void FAssetEditor_GenericGraph::AutoArrange()
+{
+	UEdGraph_GenericGraph* EdGraph = Cast<UEdGraph_GenericGraph>(EditingGraph->EdGraph);
+	check(EdGraph != nullptr);
+
+	const FScopedTransaction Transaction(LOCTEXT("GenericGraphEditorAutoArrange", "Generic Graph Editor: Auto Arrange"));
+
+	EdGraph->Modify();
+
+	UAutoLayoutStrategy* LayoutStrategy = nullptr;
+	switch (GenricGraphEditorSettings->AutoLayoutStrategy)
+	{
+	case EAutoLayoutStrategy::Tree:
+		LayoutStrategy = NewObject<UAutoLayoutStrategy>(EdGraph, UTreeLayoutStrategy::StaticClass());
+		break;
+	case EAutoLayoutStrategy::ForceDirected:
+		LayoutStrategy = NewObject<UAutoLayoutStrategy>(EdGraph, UForceDirectedLayoutStrategy::StaticClass());
+		break;
+	default:
+		break;
+	}
+
+	if (LayoutStrategy != nullptr)
+	{
+		LayoutStrategy->Settings = GenricGraphEditorSettings;
+		LayoutStrategy->Layout(EdGraph);
+		LayoutStrategy->ConditionalBeginDestroy();
+	}
+	else
+	{
+		LOG_ERROR(TEXT("FAssetEditor_GenericGraph::AutoArrange LayoutStrategy is null."));
+	}
+}
+
+bool FAssetEditor_GenericGraph::CanAutoArrange() const
+{
+	return EditingGraph != nullptr && Cast<UEdGraph_GenericGraph>(EditingGraph->EdGraph) != nullptr;
+}
+
+void FAssetEditor_GenericGraph::OnRenameNode()
+{
+	TSharedPtr<SGraphEditor> CurrentGraphEditor = GetCurrGraphEditor();
+	if (CurrentGraphEditor.IsValid())
+	{
+		const FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes();
+		for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt)
+		{
+			UEdGraphNode* SelectedNode = Cast<UEdGraphNode>(*NodeIt);
+			if (SelectedNode != NULL && SelectedNode->bCanRenameNode)
+			{
+				CurrentGraphEditor->IsNodeTitleVisible(SelectedNode, true);
+				break;
+			}
+		}
+	}
+}
+
+bool FAssetEditor_GenericGraph::CanRenameNodes() const
+{
+	UEdGraph_GenericGraph* EdGraph = Cast<UEdGraph_GenericGraph>(EditingGraph->EdGraph);
+	check(EdGraph != nullptr);
+
+	UGenericGraph* Graph = EdGraph->GetGenericGraph();
+	check(Graph != nullptr)
+
+	return Graph->bCanRenameNode && GetSelectedNodes().Num() == 1;
+}
+
+void FAssetEditor_GenericGraph::OnSelectedNodesChanged(const TSet<class UObject*>& NewSelection)
+{
+	TArray<UObject*> Selection;
+
+	for (UObject* SelectionEntry : NewSelection)
+	{
+		Selection.Add(SelectionEntry);
+	}
+
+	if (Selection.Num() == 0) 
+	{
+		PropertyWidget->SetObject(EditingGraph);
+
+	}
+	else
+	{
+		PropertyWidget->SetObjects(Selection);
+	}
+}
+
+void FAssetEditor_GenericGraph::OnNodeDoubleClicked(UEdGraphNode* Node)
+{
+	
+}
+
+void FAssetEditor_GenericGraph::OnFinishedChangingProperties(const FPropertyChangedEvent& PropertyChangedEvent)
+{
+	if (EditingGraph == nullptr)
+		return;
+
+	EditingGraph->EdGraph->GetSchema()->ForceVisualizationCacheClear();
+}
+
+#if ENGINE_MAJOR_VERSION < 5
+void FAssetEditor_GenericGraph::OnPackageSaved(const FString& PackageFileName, UObject* Outer)
+{
+	RebuildGenericGraph();
+}
+#else // #if ENGINE_MAJOR_VERSION < 5
+void FAssetEditor_GenericGraph::OnPackageSavedWithContext(const FString& PackageFileName, UPackage* Package, FObjectPostSaveContext ObjectSaveContext)
+{
+	RebuildGenericGraph();
+}
+#endif // #else // #if ENGINE_MAJOR_VERSION < 5
+
+void FAssetEditor_GenericGraph::RegisterToolbarTab(const TSharedRef<class FTabManager>& InTabManager) 
+{
+	FAssetEditorToolkit::RegisterTabSpawners(InTabManager);
+}
+
+
+#undef LOCTEXT_NAMESPACE
+
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/AssetGraphSchema_GenericGraph.cpp b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/AssetGraphSchema_GenericGraph.cpp
new file mode 100644
index 00000000..8c873f8d
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/AssetGraphSchema_GenericGraph.cpp
@@ -0,0 +1,476 @@
+#include "GenericGraphAssetEditor/AssetGraphSchema_GenericGraph.h"
+#include "ToolMenus.h"
+#include "GenericGraphEditorPCH.h"
+#include "GenericGraphAssetEditor/EdNode_GenericGraphNode.h"
+#include "GenericGraphAssetEditor/EdNode_GenericGraphEdge.h"
+#include "GenericGraphAssetEditor/ConnectionDrawingPolicy_GenericGraph.h"
+#include "GraphEditorActions.h"
+#include "Framework/Commands/GenericCommands.h"
+#include "AutoLayout/ForceDirectedLayoutStrategy.h"
+#include "AutoLayout/TreeLayoutStrategy.h"
+
+#define LOCTEXT_NAMESPACE "AssetSchema_GenericGraph"
+
+int32 UAssetGraphSchema_GenericGraph::CurrentCacheRefreshID = 0;
+
+
+class FNodeVisitorCycleChecker
+{
+public:
+	/** Check whether a loop in the graph would be caused by linking the passed-in nodes */
+	bool CheckForLoop(UEdGraphNode* StartNode, UEdGraphNode* EndNode)
+	{
+
+		VisitedNodes.Add(StartNode);
+
+		return TraverseNodes(EndNode);
+	}
+
+private:
+	bool TraverseNodes(UEdGraphNode* Node)
+	{
+		VisitedNodes.Add(Node);
+
+		for (auto MyPin : Node->Pins)
+		{
+			if (MyPin->Direction == EGPD_Output)
+			{
+				for (auto OtherPin : MyPin->LinkedTo)
+				{
+					UEdGraphNode* OtherNode = OtherPin->GetOwningNode();
+					if (VisitedNodes.Contains(OtherNode))
+					{
+						// Only  an issue if this is a back-edge
+						return false;
+					}
+					else if (!FinishedNodes.Contains(OtherNode))
+					{
+						// Only should traverse if this node hasn't been traversed
+						if (!TraverseNodes(OtherNode))
+							return false;
+					}
+				}
+			}
+		}
+
+		VisitedNodes.Remove(Node);
+		FinishedNodes.Add(Node);
+		return true;
+	};
+
+
+	TSet<UEdGraphNode*> VisitedNodes;
+	TSet<UEdGraphNode*> FinishedNodes;
+};
+
+UEdGraphNode* FAssetSchemaAction_GenericGraph_NewNode::PerformAction(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2D Location, bool bSelectNewNode /*= true*/)
+{
+	UEdGraphNode* ResultNode = nullptr;
+
+	if (NodeTemplate != nullptr)
+	{
+		const FScopedTransaction Transaction(LOCTEXT("GenericGraphEditorNewNode", "Generic Graph Editor: New Node"));
+		ParentGraph->Modify();
+		if (FromPin != nullptr)
+			FromPin->Modify();
+
+		NodeTemplate->Rename(nullptr, ParentGraph);
+		ParentGraph->AddNode(NodeTemplate, true, bSelectNewNode);
+
+		NodeTemplate->CreateNewGuid();
+		NodeTemplate->PostPlacedNewNode();
+		NodeTemplate->AllocateDefaultPins();
+		NodeTemplate->AutowireNewNode(FromPin);
+
+		NodeTemplate->NodePosX = Location.X;
+		NodeTemplate->NodePosY = Location.Y;
+
+		NodeTemplate->GenericGraphNode->SetFlags(RF_Transactional);
+		NodeTemplate->SetFlags(RF_Transactional);
+
+		ResultNode = NodeTemplate;
+	}
+
+	return ResultNode;
+}
+
+void FAssetSchemaAction_GenericGraph_NewNode::AddReferencedObjects(FReferenceCollector& Collector)
+{
+	FEdGraphSchemaAction::AddReferencedObjects(Collector);
+	Collector.AddReferencedObject(NodeTemplate);
+}
+
+UEdGraphNode* FAssetSchemaAction_GenericGraph_NewEdge::PerformAction(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2D Location, bool bSelectNewNode /*= true*/)
+{
+	UEdGraphNode* ResultNode = nullptr;
+
+	if (NodeTemplate != nullptr)
+	{
+		const FScopedTransaction Transaction(LOCTEXT("GenericGraphEditorNewEdge", "Generic Graph Editor: New Edge"));
+		ParentGraph->Modify();
+		if (FromPin != nullptr)
+			FromPin->Modify();
+
+		NodeTemplate->Rename(nullptr, ParentGraph);
+		ParentGraph->AddNode(NodeTemplate, true, bSelectNewNode);
+
+		NodeTemplate->CreateNewGuid();
+		NodeTemplate->PostPlacedNewNode();
+		NodeTemplate->AllocateDefaultPins();
+		NodeTemplate->AutowireNewNode(FromPin);
+
+		NodeTemplate->NodePosX = Location.X;
+		NodeTemplate->NodePosY = Location.Y;
+
+		NodeTemplate->GenericGraphEdge->SetFlags(RF_Transactional);
+		NodeTemplate->SetFlags(RF_Transactional);
+
+		ResultNode = NodeTemplate;
+	}
+	
+	return ResultNode;
+}
+
+void FAssetSchemaAction_GenericGraph_NewEdge::AddReferencedObjects(FReferenceCollector& Collector)
+{
+	FEdGraphSchemaAction::AddReferencedObjects(Collector);
+	Collector.AddReferencedObject(NodeTemplate);
+}
+
+void UAssetGraphSchema_GenericGraph::GetBreakLinkToSubMenuActions(UToolMenu* Menu, UEdGraphPin* InGraphPin)
+{
+	// Make sure we have a unique name for every entry in the list
+	TMap< FString, uint32 > LinkTitleCount;
+
+	FToolMenuSection& Section = Menu->FindOrAddSection("GenericGraphAssetGraphSchemaPinActions");
+
+	// Add all the links we could break from
+	for (TArray<class UEdGraphPin*>::TConstIterator Links(InGraphPin->LinkedTo); Links; ++Links)
+	{
+		UEdGraphPin* Pin = *Links;
+		FString TitleString = Pin->GetOwningNode()->GetNodeTitle(ENodeTitleType::ListView).ToString();
+		FText Title = FText::FromString(TitleString);
+		if (Pin->PinName != TEXT(""))
+		{
+			TitleString = FString::Printf(TEXT("%s (%s)"), *TitleString, *Pin->PinName.ToString());
+
+			// Add name of connection if possible
+			FFormatNamedArguments Args;
+			Args.Add(TEXT("NodeTitle"), Title);
+			Args.Add(TEXT("PinName"), Pin->GetDisplayName());
+			Title = FText::Format(LOCTEXT("BreakDescPin", "{NodeTitle} ({PinName})"), Args);
+		}
+
+		uint32& Count = LinkTitleCount.FindOrAdd(TitleString);
+
+		FText Description;
+		FFormatNamedArguments Args;
+		Args.Add(TEXT("NodeTitle"), Title);
+		Args.Add(TEXT("NumberOfNodes"), Count);
+
+		if (Count == 0)
+		{
+			Description = FText::Format(LOCTEXT("BreakDesc", "Break link to {NodeTitle}"), Args);
+		}
+		else
+		{
+			Description = FText::Format(LOCTEXT("BreakDescMulti", "Break link to {NodeTitle} ({NumberOfNodes})"), Args);
+		}
+		++Count;
+
+		Section.AddMenuEntry(NAME_None, Description, Description, FSlateIcon(), FUIAction(
+			FExecuteAction::CreateUObject(this, &UAssetGraphSchema_GenericGraph::BreakSinglePinLink, const_cast<UEdGraphPin*>(InGraphPin), *Links)));
+	}
+}
+
+EGraphType UAssetGraphSchema_GenericGraph::GetGraphType(const UEdGraph* TestEdGraph) const
+{
+	return GT_StateMachine;
+}
+
+void UAssetGraphSchema_GenericGraph::GetGraphContextActions(FGraphContextMenuBuilder& ContextMenuBuilder) const
+{
+	UGenericGraph* Graph = CastChecked<UGenericGraph>(ContextMenuBuilder.CurrentGraph->GetOuter());
+
+	if (Graph->NodeType == nullptr)
+	{
+		return;
+	}
+
+	const bool bNoParent = (ContextMenuBuilder.FromPin == NULL);
+
+	const FText AddToolTip = LOCTEXT("NewGenericGraphNodeTooltip", "Add node here");
+
+	TSet<TSubclassOf<UGenericGraphNode> > Visited;
+
+	FText Desc = Graph->NodeType.GetDefaultObject()->ContextMenuName;
+
+	if (Desc.IsEmpty())
+	{
+		FString Title = Graph->NodeType->GetName();
+		Title.RemoveFromEnd("_C");
+		Desc = FText::FromString(Title);
+	}
+
+	if (!Graph->NodeType->HasAnyClassFlags(CLASS_Abstract))
+	{
+		TSharedPtr<FAssetSchemaAction_GenericGraph_NewNode> NewNodeAction(new FAssetSchemaAction_GenericGraph_NewNode(LOCTEXT("GenericGraphNodeAction", "Generic Graph Node"), Desc, AddToolTip, 0));
+		NewNodeAction->NodeTemplate = NewObject<UEdNode_GenericGraphNode>(ContextMenuBuilder.OwnerOfTemporaries);
+		NewNodeAction->NodeTemplate->GenericGraphNode = NewObject<UGenericGraphNode>(NewNodeAction->NodeTemplate, Graph->NodeType);
+		NewNodeAction->NodeTemplate->GenericGraphNode->Graph = Graph;
+		ContextMenuBuilder.AddAction(NewNodeAction);
+
+		Visited.Add(Graph->NodeType);
+	}
+
+	for (TObjectIterator<UClass> It; It; ++It)
+	{
+		if (It->IsChildOf(Graph->NodeType) && !It->HasAnyClassFlags(CLASS_Abstract) && !Visited.Contains(*It))
+		{
+			TSubclassOf<UGenericGraphNode> NodeType = *It;
+
+			if (It->GetName().StartsWith("REINST") || It->GetName().StartsWith("SKEL"))
+				continue;
+
+			if (!Graph->GetClass()->IsChildOf(NodeType.GetDefaultObject()->CompatibleGraphType))
+				continue;
+
+			Desc = NodeType.GetDefaultObject()->ContextMenuName;
+
+			if (Desc.IsEmpty())
+			{
+				FString Title = NodeType->GetName();
+				Title.RemoveFromEnd("_C");
+				Desc = FText::FromString(Title);
+			}
+
+			TSharedPtr<FAssetSchemaAction_GenericGraph_NewNode> Action(new FAssetSchemaAction_GenericGraph_NewNode(LOCTEXT("GenericGraphNodeAction", "Generic Graph Node"), Desc, AddToolTip, 0));
+			Action->NodeTemplate = NewObject<UEdNode_GenericGraphNode>(ContextMenuBuilder.OwnerOfTemporaries);
+			Action->NodeTemplate->GenericGraphNode = NewObject<UGenericGraphNode>(Action->NodeTemplate, NodeType);
+			Action->NodeTemplate->GenericGraphNode->Graph = Graph;
+			ContextMenuBuilder.AddAction(Action);
+
+			Visited.Add(NodeType);
+		}
+	}
+}
+
+void UAssetGraphSchema_GenericGraph::GetContextMenuActions(UToolMenu* Menu, UGraphNodeContextMenuContext* Context) const
+{
+	if (Context->Pin)
+	{
+		{
+			FToolMenuSection& Section = Menu->AddSection("GenericGraphAssetGraphSchemaNodeActions", LOCTEXT("PinActionsMenuHeader", "Pin Actions"));
+			// Only display the 'Break Links' option if there is a link to break!
+			if (Context->Pin->LinkedTo.Num() > 0)
+			{
+				Section.AddMenuEntry(FGraphEditorCommands::Get().BreakPinLinks);
+
+				// add sub menu for break link to
+				if (Context->Pin->LinkedTo.Num() > 1)
+				{
+					Section.AddSubMenu(
+						"BreakLinkTo",
+						LOCTEXT("BreakLinkTo", "Break Link To..."),
+						LOCTEXT("BreakSpecificLinks", "Break a specific link..."),
+						FNewToolMenuDelegate::CreateUObject((UAssetGraphSchema_GenericGraph* const)this, &UAssetGraphSchema_GenericGraph::GetBreakLinkToSubMenuActions, const_cast<UEdGraphPin*>(Context->Pin)));
+				}
+				else
+				{
+					((UAssetGraphSchema_GenericGraph* const)this)->GetBreakLinkToSubMenuActions(Menu, const_cast<UEdGraphPin*>(Context->Pin));
+				}
+			}
+		}
+	}
+	else if (Context->Node)
+	{
+		{
+			FToolMenuSection& Section = Menu->AddSection("GenericGraphAssetGraphSchemaNodeActions", LOCTEXT("ClassActionsMenuHeader", "Node Actions"));
+			Section.AddMenuEntry(FGenericCommands::Get().Delete);
+			Section.AddMenuEntry(FGenericCommands::Get().Cut);
+			Section.AddMenuEntry(FGenericCommands::Get().Copy);
+			Section.AddMenuEntry(FGenericCommands::Get().Duplicate);
+
+			Section.AddMenuEntry(FGraphEditorCommands::Get().BreakNodeLinks);
+		}
+	}
+
+	Super::GetContextMenuActions(Menu, Context);
+}
+
+const FPinConnectionResponse UAssetGraphSchema_GenericGraph::CanCreateConnection(const UEdGraphPin* A, const UEdGraphPin* B) const
+{
+	// Make sure the pins are not on the same node
+	if (A->GetOwningNode() == B->GetOwningNode())
+	{
+		return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("PinErrorSameNode", "Can't connect node to itself"));
+	}
+
+	const UEdGraphPin *Out = A;
+	const UEdGraphPin *In = B;
+
+	UEdNode_GenericGraphNode* EdNode_Out = Cast<UEdNode_GenericGraphNode>(Out->GetOwningNode());
+	UEdNode_GenericGraphNode* EdNode_In = Cast<UEdNode_GenericGraphNode>(In->GetOwningNode());
+
+	if (EdNode_Out == nullptr || EdNode_In == nullptr)
+	{
+		return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("PinError", "Not a valid UGenericGraphEdNode"));
+	}
+		
+	//Determine if we can have cycles or not
+	bool bAllowCycles = false;
+	auto EdGraph = Cast<UEdGraph_GenericGraph>(Out->GetOwningNode()->GetGraph());
+	if (EdGraph != nullptr)
+	{
+		bAllowCycles = EdGraph->GetGenericGraph()->bCanBeCyclical;
+	}
+
+	// check for cycles
+	FNodeVisitorCycleChecker CycleChecker;
+	if (!bAllowCycles && !CycleChecker.CheckForLoop(Out->GetOwningNode(), In->GetOwningNode()))
+	{
+		return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("PinErrorCycle", "Can't create a graph cycle"));
+	}
+
+	FText ErrorMessage;
+	if (!EdNode_Out->GenericGraphNode->CanCreateConnectionTo(EdNode_In->GenericGraphNode, EdNode_Out->GetOutputPin()->LinkedTo.Num(), ErrorMessage))
+	{
+		return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, ErrorMessage);
+	}
+	if (!EdNode_In->GenericGraphNode->CanCreateConnectionFrom(EdNode_Out->GenericGraphNode, EdNode_In->GetInputPin()->LinkedTo.Num(), ErrorMessage))
+	{
+		return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, ErrorMessage);
+	}
+
+
+	if (EdNode_Out->GenericGraphNode->GetGraph()->bEdgeEnabled)
+	{
+		return FPinConnectionResponse(CONNECT_RESPONSE_MAKE_WITH_CONVERSION_NODE, LOCTEXT("PinConnect", "Connect nodes with edge"));
+	}
+	else
+	{
+		return FPinConnectionResponse(CONNECT_RESPONSE_MAKE, LOCTEXT("PinConnect", "Connect nodes"));
+	}
+}
+
+bool UAssetGraphSchema_GenericGraph::TryCreateConnection(UEdGraphPin* A, UEdGraphPin* B) const
+{
+	// We don't actually care about the pin, we want the node that is being dragged between
+	UEdNode_GenericGraphNode* NodeA = Cast<UEdNode_GenericGraphNode>(A->GetOwningNode());
+	UEdNode_GenericGraphNode* NodeB = Cast<UEdNode_GenericGraphNode>(B->GetOwningNode());
+
+	// Check that this edge doesn't already exist
+	for (UEdGraphPin *TestPin : NodeA->GetOutputPin()->LinkedTo)
+	{
+		UEdGraphNode* ChildNode = TestPin->GetOwningNode();
+		if (UEdNode_GenericGraphEdge* EdNode_Edge = Cast<UEdNode_GenericGraphEdge>(ChildNode))
+		{
+			ChildNode = EdNode_Edge->GetEndNode();
+		}
+
+		if (ChildNode == NodeB)
+			return false;
+	}
+
+	if (NodeA && NodeB)
+	{
+		// Always create connections from node A to B, don't allow adding in reverse
+		Super::TryCreateConnection(NodeA->GetOutputPin(), NodeB->GetInputPin());
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+bool UAssetGraphSchema_GenericGraph::CreateAutomaticConversionNodeAndConnections(UEdGraphPin* A, UEdGraphPin* B) const
+{
+	UEdNode_GenericGraphNode* NodeA = Cast<UEdNode_GenericGraphNode>(A->GetOwningNode());
+	UEdNode_GenericGraphNode* NodeB = Cast<UEdNode_GenericGraphNode>(B->GetOwningNode());
+
+	// Are nodes and pins all valid?
+	if (!NodeA || !NodeA->GetOutputPin() || !NodeB || !NodeB->GetInputPin())
+		return false;
+	
+	UGenericGraph* Graph = NodeA->GenericGraphNode->GetGraph();
+
+	FVector2D InitPos((NodeA->NodePosX + NodeB->NodePosX) / 2, (NodeA->NodePosY + NodeB->NodePosY) / 2);
+
+	FAssetSchemaAction_GenericGraph_NewEdge Action;
+	Action.NodeTemplate = NewObject<UEdNode_GenericGraphEdge>(NodeA->GetGraph());
+	Action.NodeTemplate->SetEdge(NewObject<UGenericGraphEdge>(Action.NodeTemplate, Graph->EdgeType));
+	UEdNode_GenericGraphEdge* EdgeNode = Cast<UEdNode_GenericGraphEdge>(Action.PerformAction(NodeA->GetGraph(), nullptr, InitPos, false));
+
+	// Always create connections from node A to B, don't allow adding in reverse
+	EdgeNode->CreateConnections(NodeA, NodeB);
+
+	return true;
+}
+
+class FConnectionDrawingPolicy* UAssetGraphSchema_GenericGraph::CreateConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID, float InZoomFactor, const FSlateRect& InClippingRect, class FSlateWindowElementList& InDrawElements, class UEdGraph* InGraphObj) const
+{
+	return new FConnectionDrawingPolicy_GenericGraph(InBackLayerID, InFrontLayerID, InZoomFactor, InClippingRect, InDrawElements, InGraphObj);
+}
+
+FLinearColor UAssetGraphSchema_GenericGraph::GetPinTypeColor(const FEdGraphPinType& PinType) const
+{
+	return FColor::White;
+}
+
+void UAssetGraphSchema_GenericGraph::BreakNodeLinks(UEdGraphNode& TargetNode) const
+{
+	const FScopedTransaction Transaction(NSLOCTEXT("UnrealEd", "GraphEd_BreakNodeLinks", "Break Node Links"));
+
+	Super::BreakNodeLinks(TargetNode);
+}
+
+void UAssetGraphSchema_GenericGraph::BreakPinLinks(UEdGraphPin& TargetPin, bool bSendsNodeNotifcation) const
+{
+	const FScopedTransaction Transaction(NSLOCTEXT("UnrealEd", "GraphEd_BreakPinLinks", "Break Pin Links"));
+
+	Super::BreakPinLinks(TargetPin, bSendsNodeNotifcation);
+}
+
+void UAssetGraphSchema_GenericGraph::BreakSinglePinLink(UEdGraphPin* SourcePin, UEdGraphPin* TargetPin) const
+{
+	const FScopedTransaction Transaction(NSLOCTEXT("UnrealEd", "GraphEd_BreakSinglePinLink", "Break Pin Link"));
+
+	Super::BreakSinglePinLink(SourcePin, TargetPin);
+}
+
+UEdGraphPin* UAssetGraphSchema_GenericGraph::DropPinOnNode(UEdGraphNode* InTargetNode, const FName& InSourcePinName, const FEdGraphPinType& InSourcePinType, EEdGraphPinDirection InSourcePinDirection) const
+{
+	UEdNode_GenericGraphNode* EdNode = Cast<UEdNode_GenericGraphNode>(InTargetNode);
+	switch (InSourcePinDirection)
+	{
+	case EGPD_Input:
+		return EdNode->GetOutputPin();
+	case EGPD_Output:
+		return EdNode->GetInputPin();
+	default:
+		return nullptr;
+	}
+}
+
+bool UAssetGraphSchema_GenericGraph::SupportsDropPinOnNode(UEdGraphNode* InTargetNode, const FEdGraphPinType& InSourcePinType, EEdGraphPinDirection InSourcePinDirection, FText& OutErrorMessage) const
+{
+	return Cast<UEdNode_GenericGraphNode>(InTargetNode) != nullptr;
+}
+
+bool UAssetGraphSchema_GenericGraph::IsCacheVisualizationOutOfDate(int32 InVisualizationCacheID) const
+{
+	return CurrentCacheRefreshID != InVisualizationCacheID;
+}
+
+int32 UAssetGraphSchema_GenericGraph::GetCurrentVisualizationCacheID() const
+{
+	return CurrentCacheRefreshID;
+}
+
+void UAssetGraphSchema_GenericGraph::ForceVisualizationCacheClear() const
+{
+	++CurrentCacheRefreshID;
+}
+
+#undef LOCTEXT_NAMESPACE
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/ConnectionDrawingPolicy_GenericGraph.cpp b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/ConnectionDrawingPolicy_GenericGraph.cpp
new file mode 100644
index 00000000..a727293d
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/ConnectionDrawingPolicy_GenericGraph.cpp
@@ -0,0 +1,149 @@
+#include "GenericGraphAssetEditor/ConnectionDrawingPolicy_GenericGraph.h"
+#include "GenericGraphAssetEditor/EdNode_GenericGraphNode.h"
+#include "GenericGraphAssetEditor/EdNode_GenericGraphEdge.h"
+
+FConnectionDrawingPolicy_GenericGraph::FConnectionDrawingPolicy_GenericGraph(int32 InBackLayerID, int32 InFrontLayerID, float ZoomFactor, const FSlateRect& InClippingRect, FSlateWindowElementList& InDrawElements, UEdGraph* InGraphObj)
+	: FConnectionDrawingPolicy(InBackLayerID, InFrontLayerID, ZoomFactor, InClippingRect, InDrawElements)
+	, GraphObj(InGraphObj)
+{
+}
+
+void FConnectionDrawingPolicy_GenericGraph::DetermineWiringStyle(UEdGraphPin* OutputPin, UEdGraphPin* InputPin, /*inout*/ FConnectionParams& Params)
+{
+	Params.AssociatedPin1 = OutputPin;
+	Params.AssociatedPin2 = InputPin;
+	Params.WireThickness = 1.5f;
+
+	const bool bDeemphasizeUnhoveredPins = HoveredPins.Num() > 0;
+	if (bDeemphasizeUnhoveredPins)
+	{
+		ApplyHoverDeemphasis(OutputPin, InputPin, /*inout*/ Params.WireThickness, /*inout*/ Params.WireColor);
+	}
+}
+
+void FConnectionDrawingPolicy_GenericGraph::Draw(TMap<TSharedRef<SWidget>, FArrangedWidget>& InPinGeometries, FArrangedChildren& ArrangedNodes)
+{
+	// Build an acceleration structure to quickly find geometry for the nodes
+	NodeWidgetMap.Empty();
+	for (int32 NodeIndex = 0; NodeIndex < ArrangedNodes.Num(); ++NodeIndex)
+	{
+		FArrangedWidget& CurWidget = ArrangedNodes[NodeIndex];
+		TSharedRef<SGraphNode> ChildNode = StaticCastSharedRef<SGraphNode>(CurWidget.Widget);
+		NodeWidgetMap.Add(ChildNode->GetNodeObj(), NodeIndex);
+	}
+
+	// Now draw
+	FConnectionDrawingPolicy::Draw(InPinGeometries, ArrangedNodes);
+}
+
+void FConnectionDrawingPolicy_GenericGraph::DrawPreviewConnector(const FGeometry& PinGeometry, const FVector2D& StartPoint, const FVector2D& EndPoint, UEdGraphPin* Pin)
+{
+	FConnectionParams Params;
+	DetermineWiringStyle(Pin, nullptr, /*inout*/ Params);
+
+	if (Pin->Direction == EEdGraphPinDirection::EGPD_Output)
+	{
+		DrawSplineWithArrow(FGeometryHelper::FindClosestPointOnGeom(PinGeometry, EndPoint), EndPoint, Params);
+	}
+	else
+	{
+		DrawSplineWithArrow(FGeometryHelper::FindClosestPointOnGeom(PinGeometry, StartPoint), StartPoint, Params);
+	}
+}
+
+void FConnectionDrawingPolicy_GenericGraph::DrawSplineWithArrow(const FVector2D& StartAnchorPoint, const FVector2D& EndAnchorPoint, const FConnectionParams& Params)
+{
+	// bUserFlag1 indicates that we need to reverse the direction of connection (used by debugger)
+	const FVector2D& P0 = Params.bUserFlag1 ? EndAnchorPoint : StartAnchorPoint;
+	const FVector2D& P1 = Params.bUserFlag1 ? StartAnchorPoint : EndAnchorPoint;
+
+	Internal_DrawLineWithArrow(P0, P1, Params);
+}
+
+void FConnectionDrawingPolicy_GenericGraph::Internal_DrawLineWithArrow(const FVector2D& StartAnchorPoint, const FVector2D& EndAnchorPoint, const FConnectionParams& Params)
+{
+	//@TODO: Should this be scaled by zoom factor?
+	const float LineSeparationAmount = 4.5f;
+
+	const FVector2D DeltaPos = EndAnchorPoint - StartAnchorPoint;
+	const FVector2D UnitDelta = DeltaPos.GetSafeNormal();
+	const FVector2D Normal = FVector2D(DeltaPos.Y, -DeltaPos.X).GetSafeNormal();
+
+	// Come up with the final start/end points
+	const FVector2D DirectionBias = Normal * LineSeparationAmount;
+	const FVector2D LengthBias = ArrowRadius.X * UnitDelta;
+	const FVector2D StartPoint = StartAnchorPoint + DirectionBias + LengthBias;
+	const FVector2D EndPoint = EndAnchorPoint + DirectionBias - LengthBias;
+
+	// Draw a line/spline
+	DrawConnection(WireLayerID, StartPoint, EndPoint, Params);
+
+	// Draw the arrow
+	const FVector2D ArrowDrawPos = EndPoint - ArrowRadius;
+	const float AngleInRadians = FMath::Atan2(DeltaPos.Y, DeltaPos.X);
+
+	FSlateDrawElement::MakeRotatedBox(
+		DrawElementsList,
+		ArrowLayerID,
+		FPaintGeometry(ArrowDrawPos, ArrowImage->ImageSize * ZoomFactor, ZoomFactor),
+		ArrowImage,
+		ESlateDrawEffect::None,
+		AngleInRadians,
+		TOptional<FVector2D>(),
+		FSlateDrawElement::RelativeToElement,
+		Params.WireColor
+	);
+}
+
+void FConnectionDrawingPolicy_GenericGraph::DrawSplineWithArrow(const FGeometry& StartGeom, const FGeometry& EndGeom, const FConnectionParams& Params)
+{
+	// Get a reasonable seed point (halfway between the boxes)
+	const FVector2D StartCenter = FGeometryHelper::CenterOf(StartGeom);
+	const FVector2D EndCenter = FGeometryHelper::CenterOf(EndGeom);
+	const FVector2D SeedPoint = (StartCenter + EndCenter) * 0.5f;
+
+	// Find the (approximate) closest points between the two boxes
+	const FVector2D StartAnchorPoint = FGeometryHelper::FindClosestPointOnGeom(StartGeom, SeedPoint);
+	const FVector2D EndAnchorPoint = FGeometryHelper::FindClosestPointOnGeom(EndGeom, SeedPoint);
+
+	DrawSplineWithArrow(StartAnchorPoint, EndAnchorPoint, Params);
+}
+
+FVector2D FConnectionDrawingPolicy_GenericGraph::ComputeSplineTangent(const FVector2D& Start, const FVector2D& End) const
+{
+	const FVector2D Delta = End - Start;
+	const FVector2D NormDelta = Delta.GetSafeNormal();
+
+	return NormDelta;
+}
+
+void FConnectionDrawingPolicy_GenericGraph::DetermineLinkGeometry(FArrangedChildren& ArrangedNodes, TSharedRef<SWidget>& OutputPinWidget,
+	UEdGraphPin* OutputPin, UEdGraphPin* InputPin, FArrangedWidget*& StartWidgetGeometry, FArrangedWidget*& EndWidgetGeometry)
+{
+	if (UEdNode_GenericGraphEdge* EdgeNode = Cast<UEdNode_GenericGraphEdge>(InputPin->GetOwningNode()))
+	{
+		UEdNode_GenericGraphNode* Start = EdgeNode->GetStartNode();
+		UEdNode_GenericGraphNode* End = EdgeNode->GetEndNode();
+		if (Start != nullptr && End != nullptr)
+		{
+			int32* StartNodeIndex = NodeWidgetMap.Find(Start);
+			int32* EndNodeIndex = NodeWidgetMap.Find(End);
+			if (StartNodeIndex != nullptr && EndNodeIndex != nullptr)
+			{
+				StartWidgetGeometry = &(ArrangedNodes[*StartNodeIndex]);
+				EndWidgetGeometry = &(ArrangedNodes[*EndNodeIndex]);
+			}
+		}
+	}
+	else
+	{
+		StartWidgetGeometry = PinGeometries->Find(OutputPinWidget);
+
+		if (TSharedPtr<SGraphPin>* pTargetWidget = PinToPinWidgetMap.Find(InputPin))
+		{
+			TSharedRef<SGraphPin> InputWidget = (*pTargetWidget).ToSharedRef();
+			EndWidgetGeometry = PinGeometries->Find(InputWidget);
+		}
+	}
+}
+
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/EdGraph_GenericGraph.cpp b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/EdGraph_GenericGraph.cpp
new file mode 100644
index 00000000..f730756f
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/EdGraph_GenericGraph.cpp
@@ -0,0 +1,205 @@
+#include "GenericGraphAssetEditor/EdGraph_GenericGraph.h"
+#include "GenericGraphEditorPCH.h"
+#include "GenericGraph.h"
+#include "GenericGraphAssetEditor/EdNode_GenericGraphNode.h"
+#include "GenericGraphAssetEditor/EdNode_GenericGraphEdge.h"
+
+UEdGraph_GenericGraph::UEdGraph_GenericGraph()
+{
+
+}
+
+UEdGraph_GenericGraph::~UEdGraph_GenericGraph()
+{
+
+}
+
+void UEdGraph_GenericGraph::RebuildGenericGraph()
+{
+	LOG_INFO(TEXT("UGenericGraphEdGraph::RebuildGenericGraph has been called"));
+
+	UGenericGraph* Graph = GetGenericGraph();
+
+	Clear();
+
+	for (int i = 0; i < Nodes.Num(); ++i)
+	{
+		if (UEdNode_GenericGraphNode* EdNode = Cast<UEdNode_GenericGraphNode>(Nodes[i]))
+		{
+			if (EdNode->GenericGraphNode == nullptr)
+				continue;
+
+			UGenericGraphNode* GenericGraphNode = EdNode->GenericGraphNode;
+
+			NodeMap.Add(GenericGraphNode, EdNode);
+
+			Graph->AllNodes.Add(GenericGraphNode);
+
+			for (int PinIdx = 0; PinIdx < EdNode->Pins.Num(); ++PinIdx)
+			{
+				UEdGraphPin* Pin = EdNode->Pins[PinIdx];
+
+				if (Pin->Direction != EEdGraphPinDirection::EGPD_Output)
+					continue;
+
+				for (int LinkToIdx = 0; LinkToIdx < Pin->LinkedTo.Num(); ++LinkToIdx)
+				{
+					UGenericGraphNode* ChildNode = nullptr;
+					if (UEdNode_GenericGraphNode* EdNode_Child = Cast<UEdNode_GenericGraphNode>(Pin->LinkedTo[LinkToIdx]->GetOwningNode()))
+					{
+						ChildNode = EdNode_Child->GenericGraphNode;
+					}
+					else if (UEdNode_GenericGraphEdge* EdNode_Edge = Cast<UEdNode_GenericGraphEdge>(Pin->LinkedTo[LinkToIdx]->GetOwningNode()))
+					{
+						UEdNode_GenericGraphNode* Child = EdNode_Edge->GetEndNode();;
+						if (Child != nullptr)
+						{
+							ChildNode = Child->GenericGraphNode;
+						}
+					}
+
+					if (ChildNode != nullptr)
+					{
+						GenericGraphNode->ChildrenNodes.Add(ChildNode);
+
+						ChildNode->ParentNodes.Add(GenericGraphNode);
+					}
+					else
+					{
+						LOG_ERROR(TEXT("UEdGraph_GenericGraph::RebuildGenericGraph can't find child node"));
+					}
+				}
+			}
+		}
+		else if (UEdNode_GenericGraphEdge* EdgeNode = Cast<UEdNode_GenericGraphEdge>(Nodes[i]))
+		{
+			UEdNode_GenericGraphNode* StartNode = EdgeNode->GetStartNode();
+			UEdNode_GenericGraphNode* EndNode = EdgeNode->GetEndNode();
+			UGenericGraphEdge* Edge = EdgeNode->GenericGraphEdge;
+
+			if (StartNode == nullptr || EndNode == nullptr || Edge == nullptr)
+			{
+				LOG_ERROR(TEXT("UEdGraph_GenericGraph::RebuildGenericGraph add edge failed."));
+				continue;
+			}
+
+			EdgeMap.Add(Edge, EdgeNode);
+
+			Edge->Graph = Graph;
+			Edge->Rename(nullptr, Graph, REN_DontCreateRedirectors | REN_DoNotDirty);
+			Edge->StartNode = StartNode->GenericGraphNode;
+			Edge->EndNode = EndNode->GenericGraphNode;
+			Edge->StartNode->Edges.Add(Edge->EndNode, Edge);
+		}
+	}
+
+	for (int i = 0; i < Graph->AllNodes.Num(); ++i)
+	{
+		UGenericGraphNode* Node = Graph->AllNodes[i];
+		if (Node->ParentNodes.Num() == 0)
+		{
+			Graph->RootNodes.Add(Node);
+
+			SortNodes(Node);
+		}
+
+		Node->Graph = Graph;
+		Node->Rename(nullptr, Graph, REN_DontCreateRedirectors | REN_DoNotDirty);
+	}
+
+	Graph->RootNodes.Sort([&](const UGenericGraphNode& L, const UGenericGraphNode& R)
+	{
+		UEdNode_GenericGraphNode* EdNode_LNode = NodeMap[&L];
+		UEdNode_GenericGraphNode* EdNode_RNode = NodeMap[&R];
+		return EdNode_LNode->NodePosX < EdNode_RNode->NodePosX;
+	});
+}
+
+UGenericGraph* UEdGraph_GenericGraph::GetGenericGraph() const
+{
+	return CastChecked<UGenericGraph>(GetOuter());
+}
+
+bool UEdGraph_GenericGraph::Modify(bool bAlwaysMarkDirty /*= true*/)
+{
+	bool Rtn = Super::Modify(bAlwaysMarkDirty);
+
+	GetGenericGraph()->Modify();
+
+	for (int32 i = 0; i < Nodes.Num(); ++i)
+	{
+		Nodes[i]->Modify();
+	}
+
+	return Rtn;
+}
+
+void UEdGraph_GenericGraph::Clear()
+{
+	UGenericGraph* Graph = GetGenericGraph();
+
+	Graph->ClearGraph();
+	NodeMap.Reset();
+	EdgeMap.Reset();
+
+	for (int i = 0; i < Nodes.Num(); ++i)
+	{
+		if (UEdNode_GenericGraphNode* EdNode = Cast<UEdNode_GenericGraphNode>(Nodes[i]))
+		{
+			UGenericGraphNode* GenericGraphNode = EdNode->GenericGraphNode;
+			if (GenericGraphNode)
+			{
+				GenericGraphNode->ParentNodes.Reset();
+				GenericGraphNode->ChildrenNodes.Reset();
+				GenericGraphNode->Edges.Reset();
+			}
+		}
+	}
+}
+
+void UEdGraph_GenericGraph::SortNodes(UGenericGraphNode* RootNode)
+{
+	int Level = 0;
+	TArray<UGenericGraphNode*> CurrLevelNodes = { RootNode };
+	TArray<UGenericGraphNode*> NextLevelNodes;
+	TSet<UGenericGraphNode*> Visited;
+
+	while (CurrLevelNodes.Num() != 0)
+	{
+		int32 LevelWidth = 0;
+		for (int i = 0; i < CurrLevelNodes.Num(); ++i)
+		{
+			UGenericGraphNode* Node = CurrLevelNodes[i];
+			Visited.Add(Node);
+
+			auto Comp = [&](const UGenericGraphNode& L, const UGenericGraphNode& R)
+			{
+				UEdNode_GenericGraphNode* EdNode_LNode = NodeMap[&L];
+				UEdNode_GenericGraphNode* EdNode_RNode = NodeMap[&R];
+				return EdNode_LNode->NodePosX < EdNode_RNode->NodePosX;
+			};
+
+			Node->ChildrenNodes.Sort(Comp);
+			Node->ParentNodes.Sort(Comp);
+
+			for (int j = 0; j < Node->ChildrenNodes.Num(); ++j)
+			{
+				UGenericGraphNode* ChildNode = Node->ChildrenNodes[j];
+				if(!Visited.Contains(ChildNode))
+					NextLevelNodes.Add(Node->ChildrenNodes[j]);
+			}
+		}
+
+		CurrLevelNodes = NextLevelNodes;
+		NextLevelNodes.Reset();
+		++Level;
+	}
+}
+
+void UEdGraph_GenericGraph::PostEditUndo()
+{
+	Super::PostEditUndo();
+
+	NotifyGraphChanged();
+}
+
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/EdNode_GenericGraphEdge.cpp b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/EdNode_GenericGraphEdge.cpp
new file mode 100644
index 00000000..636ce9c4
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/EdNode_GenericGraphEdge.cpp
@@ -0,0 +1,97 @@
+#include "GenericGraphAssetEditor/EdNode_GenericGraphEdge.h"
+#include "GenericGraphEdge.h"
+#include "GenericGraphAssetEditor/EdNode_GenericGraphNode.h"
+
+#define LOCTEXT_NAMESPACE "EdNode_GenericGraphEdge"
+
+UEdNode_GenericGraphEdge::UEdNode_GenericGraphEdge()
+{
+	bCanRenameNode = true;
+}
+
+void UEdNode_GenericGraphEdge::SetEdge(UGenericGraphEdge* Edge)
+{
+	GenericGraphEdge = Edge;
+}
+
+void UEdNode_GenericGraphEdge::AllocateDefaultPins()
+{
+	UEdGraphPin* Inputs = CreatePin(EGPD_Input, TEXT("Edge"), FName(), TEXT("In"));
+	Inputs->bHidden = true;
+	UEdGraphPin* Outputs = CreatePin(EGPD_Output, TEXT("Edge"), FName(), TEXT("Out"));
+	Outputs->bHidden = true;
+}
+
+FText UEdNode_GenericGraphEdge::GetNodeTitle(ENodeTitleType::Type TitleType) const
+{
+	if (GenericGraphEdge)
+	{
+		return GenericGraphEdge->GetNodeTitle();
+	}
+	return FText();
+}
+
+void UEdNode_GenericGraphEdge::PinConnectionListChanged(UEdGraphPin* Pin)
+{
+	if (Pin->LinkedTo.Num() == 0)
+	{
+		// Commit suicide; transitions must always have an input and output connection
+		Modify();
+
+		// Our parent graph will have our graph in SubGraphs so needs to be modified to record that.
+		if (UEdGraph* ParentGraph = GetGraph())
+		{
+			ParentGraph->Modify();
+		}
+
+		DestroyNode();
+	}
+}
+
+void UEdNode_GenericGraphEdge::PrepareForCopying()
+{
+	GenericGraphEdge->Rename(nullptr, this, REN_DontCreateRedirectors | REN_DoNotDirty);
+}
+
+void UEdNode_GenericGraphEdge::CreateConnections(UEdNode_GenericGraphNode* Start, UEdNode_GenericGraphNode* End)
+{
+	Pins[0]->Modify();
+	Pins[0]->LinkedTo.Empty();
+
+	Start->GetOutputPin()->Modify();
+	Pins[0]->MakeLinkTo(Start->GetOutputPin());
+
+	// This to next
+	Pins[1]->Modify();
+	Pins[1]->LinkedTo.Empty();
+
+	End->GetInputPin()->Modify();
+	Pins[1]->MakeLinkTo(End->GetInputPin());
+}
+
+UEdNode_GenericGraphNode* UEdNode_GenericGraphEdge::GetStartNode()
+{
+	if (Pins[0]->LinkedTo.Num() > 0)
+	{
+		return Cast<UEdNode_GenericGraphNode>(Pins[0]->LinkedTo[0]->GetOwningNode());
+	}
+	else
+	{
+		return nullptr;
+	}
+}
+
+UEdNode_GenericGraphNode* UEdNode_GenericGraphEdge::GetEndNode()
+{
+	if (Pins[1]->LinkedTo.Num() > 0)
+	{
+		return Cast<UEdNode_GenericGraphNode>(Pins[1]->LinkedTo[0]->GetOwningNode());
+	}
+	else
+	{
+		return nullptr;
+	}
+}
+
+#undef LOCTEXT_NAMESPACE
+
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/EdNode_GenericGraphNode.cpp b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/EdNode_GenericGraphNode.cpp
new file mode 100644
index 00000000..9a487cf6
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/EdNode_GenericGraphNode.cpp
@@ -0,0 +1,84 @@
+#include "GenericGraphAssetEditor/EdNode_GenericGraphNode.h"
+#include "GenericGraphAssetEditor/EdGraph_GenericGraph.h"
+#include "Kismet2/Kismet2NameValidators.h"
+#include "Kismet2/BlueprintEditorUtils.h"
+
+#define LOCTEXT_NAMESPACE "EdNode_GenericGraph"
+
+UEdNode_GenericGraphNode::UEdNode_GenericGraphNode()
+{
+	bCanRenameNode = true;
+}
+
+UEdNode_GenericGraphNode::~UEdNode_GenericGraphNode()
+{
+
+}
+
+void UEdNode_GenericGraphNode::AllocateDefaultPins()
+{
+	CreatePin(EGPD_Input, "MultipleNodes", FName(), TEXT("In"));
+	CreatePin(EGPD_Output, "MultipleNodes", FName(), TEXT("Out"));
+}
+
+UEdGraph_GenericGraph* UEdNode_GenericGraphNode::GetGenericGraphEdGraph()
+{
+	return Cast<UEdGraph_GenericGraph>(GetGraph());
+}
+
+FText UEdNode_GenericGraphNode::GetNodeTitle(ENodeTitleType::Type TitleType) const
+{
+	if (GenericGraphNode == nullptr)
+	{
+		return Super::GetNodeTitle(TitleType);
+	}
+	else
+	{
+		return GenericGraphNode->GetNodeTitle();
+	}
+}
+
+void UEdNode_GenericGraphNode::PrepareForCopying()
+{
+	GenericGraphNode->Rename(nullptr, this, REN_DontCreateRedirectors | REN_DoNotDirty);
+}
+
+void UEdNode_GenericGraphNode::AutowireNewNode(UEdGraphPin* FromPin)
+{
+	Super::AutowireNewNode(FromPin);
+
+	if (FromPin != nullptr)
+	{
+		if (GetSchema()->TryCreateConnection(FromPin, GetInputPin()))
+		{
+			FromPin->GetOwningNode()->NodeConnectionListChanged();
+		}
+	}
+}
+
+void UEdNode_GenericGraphNode::SetGenericGraphNode(UGenericGraphNode* InNode)
+{
+	GenericGraphNode = InNode;
+}
+
+FLinearColor UEdNode_GenericGraphNode::GetBackgroundColor() const
+{
+	return GenericGraphNode == nullptr ? FLinearColor::Black : GenericGraphNode->GetBackgroundColor();
+}
+
+UEdGraphPin* UEdNode_GenericGraphNode::GetInputPin() const
+{
+	return Pins[0];
+}
+
+UEdGraphPin* UEdNode_GenericGraphNode::GetOutputPin() const
+{
+	return Pins[1];
+}
+
+void UEdNode_GenericGraphNode::PostEditUndo()
+{
+	UEdGraphNode::PostEditUndo();
+}
+
+#undef LOCTEXT_NAMESPACE
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/EditorCommands_GenericGraph.cpp b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/EditorCommands_GenericGraph.cpp
new file mode 100644
index 00000000..8cd338f5
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/EditorCommands_GenericGraph.cpp
@@ -0,0 +1,11 @@
+#include "GenericGraphAssetEditor/EditorCommands_GenericGraph.h"
+
+#define LOCTEXT_NAMESPACE "EditorCommands_GenericGraph"
+
+void FEditorCommands_GenericGraph::RegisterCommands()
+{
+	UI_COMMAND(GraphSettings, "Graph Settings", "Graph Settings", EUserInterfaceActionType::Button, FInputChord());
+	UI_COMMAND(AutoArrange, "Auto Arrange", "Auto Arrange", EUserInterfaceActionType::Button, FInputChord());
+}
+
+#undef LOCTEXT_NAMESPACE
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/GenericGraphDragConnection.cpp b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/GenericGraphDragConnection.cpp
new file mode 100644
index 00000000..c8c3999d
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/GenericGraphDragConnection.cpp
@@ -0,0 +1,325 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+
+#include "GenericGraphAssetEditor/GenericGraphDragConnection.h"
+#include "Widgets/SBoxPanel.h"
+#include "Framework/Application/SlateApplication.h"
+#include "Widgets/Images/SImage.h"
+#include "EdGraph/EdGraph.h"
+#include "SGraphPanel.h"
+#include "ScopedTransaction.h"
+
+TSharedRef<FGenericGraphDragConnection> FGenericGraphDragConnection::New(const TSharedRef<SGraphPanel>& GraphPanel, const FDraggedPinTable& DraggedPins)
+{
+	TSharedRef<FGenericGraphDragConnection> Operation = MakeShareable(new FGenericGraphDragConnection(GraphPanel, DraggedPins));
+	Operation->Construct();
+
+	return Operation;
+}
+
+void FGenericGraphDragConnection::OnDrop(bool bDropWasHandled, const FPointerEvent& MouseEvent)
+{
+	GraphPanel->OnStopMakingConnection();
+
+	Super::OnDrop(bDropWasHandled, MouseEvent);
+}
+
+void FGenericGraphDragConnection::OnDragged(const class FDragDropEvent& DragDropEvent)
+{
+	FVector2D TargetPosition = DragDropEvent.GetScreenSpacePosition();
+
+	// Reposition the info window wrt to the drag
+	CursorDecoratorWindow->MoveWindowTo(DragDropEvent.GetScreenSpacePosition() + DecoratorAdjust);
+	// Request the active panel to scroll if required
+	GraphPanel->RequestDeferredPan(TargetPosition);
+}
+
+void FGenericGraphDragConnection::HoverTargetChanged()
+{
+	TArray<FPinConnectionResponse> UniqueMessages;
+
+	if (UEdGraphPin* TargetPinObj = GetHoveredPin())
+	{
+		TArray<UEdGraphPin*> ValidSourcePins;
+		ValidateGraphPinList(/*out*/ ValidSourcePins);
+
+		// Check the schema for connection responses
+		for (UEdGraphPin* StartingPinObj : ValidSourcePins)
+		{
+			// The Graph object in which the pins reside.
+			UEdGraph* GraphObj = StartingPinObj->GetOwningNode()->GetGraph();
+
+			// Determine what the schema thinks about the wiring action
+			const FPinConnectionResponse Response = GraphObj->GetSchema()->CanCreateConnection(StartingPinObj, TargetPinObj);
+
+			if (Response.Response == ECanCreateConnectionResponse::CONNECT_RESPONSE_DISALLOW)
+			{
+				TSharedPtr<SGraphNode> NodeWidget = TargetPinObj->GetOwningNode()->DEPRECATED_NodeWidget.Pin();
+				if (NodeWidget.IsValid())
+				{
+					NodeWidget->NotifyDisallowedPinConnection(StartingPinObj, TargetPinObj);
+				}
+			}
+
+			UniqueMessages.AddUnique(Response);
+		}
+	}
+	else if (UEdNode_GenericGraphNode* TargetNodeObj = Cast<UEdNode_GenericGraphNode>(GetHoveredNode()))
+	{
+		TArray<UEdGraphPin*> ValidSourcePins;
+		ValidateGraphPinList(/*out*/ ValidSourcePins);
+
+		// Check the schema for connection responses
+		for (UEdGraphPin* StartingPinObj : ValidSourcePins)
+		{
+			FPinConnectionResponse Response;			
+			FText ResponseText;
+
+			const UEdGraphSchema *Schema = StartingPinObj->GetSchema();
+			UEdGraphPin *TargetPin = TargetNodeObj->GetInputPin();
+
+			if (Schema && TargetPin)
+			{
+				Response = Schema->CanCreateConnection(StartingPinObj, TargetPin);
+				if (Response.Response == ECanCreateConnectionResponse::CONNECT_RESPONSE_DISALLOW)
+				{
+					TSharedPtr<SGraphNode> NodeWidget = TargetPin->GetOwningNode()->DEPRECATED_NodeWidget.Pin();
+					if (NodeWidget.IsValid())
+					{
+						NodeWidget->NotifyDisallowedPinConnection(StartingPinObj, TargetPinObj);
+					}
+				}
+			}
+			else
+			{
+#define LOCTEXT_NAMESPACE "AssetSchema_GenericGraph"
+				Response = FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("PinError", "Not a valid UGenericGraphEdNode"));
+#undef LOCTEXT_NAMESPACE
+			}
+
+			UniqueMessages.AddUnique(Response);
+		}
+	}
+	else if (UEdGraph* CurrentHoveredGraph = GetHoveredGraph())
+	{
+		TArray<UEdGraphPin*> ValidSourcePins;
+		ValidateGraphPinList(/*out*/ ValidSourcePins);
+
+		for (UEdGraphPin* StartingPinObj : ValidSourcePins)
+		{
+			// Let the schema describe the connection we might make
+			FPinConnectionResponse Response = CurrentHoveredGraph->GetSchema()->CanCreateNewNodes(StartingPinObj);
+			if (!Response.Message.IsEmpty())
+			{
+				UniqueMessages.AddUnique(Response);
+			}
+		}
+	}
+
+	// Let the user know the status of dropping now
+	if (UniqueMessages.Num() == 0)
+	{
+		// Display the place a new node icon, we're not over a valid pin and have no message from the schema
+		SetSimpleFeedbackMessage(
+			FAppStyle::GetBrush(TEXT("Graph.ConnectorFeedback.NewNode")),
+			FLinearColor::White,
+			NSLOCTEXT("GraphEditor.Feedback", "PlaceNewNode", "Place a new node."));
+	}
+	else
+	{
+		// Take the unique responses and create visual feedback for it
+		TSharedRef<SVerticalBox> FeedbackBox = SNew(SVerticalBox);
+		for (auto ResponseIt = UniqueMessages.CreateConstIterator(); ResponseIt; ++ResponseIt)
+		{
+			// Determine the icon
+			const FSlateBrush* StatusSymbol = NULL;
+
+			switch (ResponseIt->Response)
+			{
+			case CONNECT_RESPONSE_MAKE:
+			case CONNECT_RESPONSE_BREAK_OTHERS_A:
+			case CONNECT_RESPONSE_BREAK_OTHERS_B:
+			case CONNECT_RESPONSE_BREAK_OTHERS_AB:
+				StatusSymbol = FAppStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OK"));
+				break;
+
+			case CONNECT_RESPONSE_MAKE_WITH_CONVERSION_NODE:
+				StatusSymbol = FAppStyle::GetBrush(TEXT("Graph.ConnectorFeedback.ViaCast"));
+				break;
+
+			case CONNECT_RESPONSE_DISALLOW:
+			default:
+				StatusSymbol = FAppStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error"));
+				break;
+			}
+
+			// Add a new message row
+			FeedbackBox->AddSlot()
+				.AutoHeight()
+				[
+					SNew(SHorizontalBox)
+					+ SHorizontalBox::Slot()
+				.AutoWidth()
+				.Padding(3.0f)
+				.VAlign(VAlign_Center)
+				[
+					SNew(SImage).Image(StatusSymbol)
+				]
+			+ SHorizontalBox::Slot()
+				.AutoWidth()
+				.VAlign(VAlign_Center)
+				[
+					SNew(STextBlock).Text(ResponseIt->Message)
+				]
+				];
+		}
+
+		SetFeedbackMessage(FeedbackBox);
+	}
+}
+
+FGenericGraphDragConnection::FGenericGraphDragConnection(const TSharedRef<SGraphPanel>& GraphPanelIn, const FDraggedPinTable& DraggedPinsIn)
+	: GraphPanel(GraphPanelIn)
+	, DraggingPins(DraggedPinsIn)
+	, DecoratorAdjust(FSlateApplication::Get().GetCursorSize())
+{
+	if (DraggingPins.Num() > 0)
+	{
+		const UEdGraphPin* PinObj = FDraggedPinTable::TConstIterator(DraggedPinsIn)->GetPinObj(*GraphPanelIn);
+		if (PinObj && PinObj->Direction == EGPD_Input)
+		{
+			DecoratorAdjust *= FVector2D(-1.0f, 1.0f);
+		}
+	}
+
+	for (const FGraphPinHandle& DraggedPin : DraggedPinsIn)
+	{
+		GraphPanelIn->OnBeginMakingConnection(DraggedPin);
+	}
+}
+
+FReply FGenericGraphDragConnection::DroppedOnPin(FVector2D ScreenPosition, FVector2D GraphPosition)
+{
+	TArray<UEdGraphPin*> ValidSourcePins;
+	ValidateGraphPinList(/*out*/ ValidSourcePins);
+
+	const FScopedTransaction Transaction(NSLOCTEXT("UnrealEd", "GraphEd_CreateConnection", "Create Pin Link"));
+
+	UEdGraphPin* PinB = GetHoveredPin();
+	bool bError = false;
+	TSet<UEdGraphNode*> NodeList;
+
+	for (UEdGraphPin* PinA : ValidSourcePins)
+	{
+		if ((PinA != NULL) && (PinB != NULL))
+		{
+			UEdGraph* MyGraphObj = PinA->GetOwningNode()->GetGraph();
+
+			if (MyGraphObj->GetSchema()->TryCreateConnection(PinA, PinB))
+			{
+				if (!PinA->IsPendingKill())
+				{
+					NodeList.Add(PinA->GetOwningNode());
+				}
+				if (!PinB->IsPendingKill())
+				{
+					NodeList.Add(PinB->GetOwningNode());
+				}
+			}
+		}
+		else
+		{
+			bError = true;
+		}
+	}
+
+	// Send all nodes that received a new pin connection a notification
+	for (auto It = NodeList.CreateConstIterator(); It; ++It)
+	{
+		UEdGraphNode* Node = (*It);
+		Node->NodeConnectionListChanged();
+	}
+
+	if (bError)
+	{
+		return FReply::Unhandled();
+	}
+
+	return FReply::Handled();
+}
+
+FReply FGenericGraphDragConnection::DroppedOnNode(FVector2D ScreenPosition, FVector2D GraphPosition)
+{
+	bool bHandledPinDropOnNode = false;
+	UEdGraphNode* NodeOver = GetHoveredNode();
+
+	if (NodeOver)
+	{
+		// Gather any source drag pins
+		TArray<UEdGraphPin*> ValidSourcePins;
+		ValidateGraphPinList(/*out*/ ValidSourcePins);
+
+		if (ValidSourcePins.Num())
+		{
+			for (UEdGraphPin* SourcePin : ValidSourcePins)
+			{
+				// Check for pin drop support
+				FText ResponseText;
+				if (SourcePin->GetOwningNode() != NodeOver && SourcePin->GetSchema()->SupportsDropPinOnNode(NodeOver, SourcePin->PinType, SourcePin->Direction, ResponseText))
+				{
+					bHandledPinDropOnNode = true;
+
+					// Find which pin name to use and drop the pin on the node
+					const FName PinName = SourcePin->PinFriendlyName.IsEmpty() ? SourcePin->PinName : *SourcePin->PinFriendlyName.ToString();
+
+					const FScopedTransaction Transaction((SourcePin->Direction == EGPD_Output) ? NSLOCTEXT("UnrealEd", "AddInParam", "Add In Parameter") : NSLOCTEXT("UnrealEd", "AddOutParam", "Add Out Parameter"));
+
+					UEdGraphPin* EdGraphPin = NodeOver->GetSchema()->DropPinOnNode(GetHoveredNode(), PinName, SourcePin->PinType, SourcePin->Direction);
+
+					// This can invalidate the source pin due to node reconstruction, abort in that case
+					if (SourcePin->GetOwningNodeUnchecked() && EdGraphPin)
+					{
+						SourcePin->Modify();
+						EdGraphPin->Modify();
+						SourcePin->GetSchema()->TryCreateConnection(SourcePin, EdGraphPin);
+					}
+				}
+
+				// If we have not handled the pin drop on node and there is an error message, do not let other actions occur.
+				if (!bHandledPinDropOnNode && !ResponseText.IsEmpty())
+				{
+					bHandledPinDropOnNode = true;
+				}
+			}
+		}
+	}
+	return bHandledPinDropOnNode ? FReply::Handled() : FReply::Unhandled();
+}
+
+FReply FGenericGraphDragConnection::DroppedOnPanel(const TSharedRef< SWidget >& Panel, FVector2D ScreenPosition, FVector2D GraphPosition, UEdGraph& Graph)
+{
+	// Gather any source drag pins
+	TArray<UEdGraphPin*> PinObjects;
+	ValidateGraphPinList(/*out*/ PinObjects);
+
+	// Create a context menu
+	TSharedPtr<SWidget> WidgetToFocus = GraphPanel->SummonContextMenu(ScreenPosition, GraphPosition, NULL, NULL, PinObjects);
+
+	// Give the context menu focus
+	return (WidgetToFocus.IsValid())
+		? FReply::Handled().SetUserFocus(WidgetToFocus.ToSharedRef(), EFocusCause::SetDirectly)
+		: FReply::Handled();
+}
+
+
+void FGenericGraphDragConnection::ValidateGraphPinList(TArray<UEdGraphPin*>& OutValidPins)
+{
+	OutValidPins.Empty(DraggingPins.Num());
+	for (const FGraphPinHandle& PinHandle : DraggingPins)
+	{
+		if (UEdGraphPin* GraphPin = PinHandle.GetPinObj(*GraphPanel))
+		{
+			OutValidPins.Add(GraphPin);
+		}
+	}
+}
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/GenericGraphEditorStyle.cpp b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/GenericGraphEditorStyle.cpp
new file mode 100644
index 00000000..6870128f
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/GenericGraphEditorStyle.cpp
@@ -0,0 +1,54 @@
+#include "GenericGraphAssetEditor/GenericGraphEditorStyle.h"
+#include "Styling/SlateStyleRegistry.h"
+#include "Styling/SlateTypes.h"
+#include "Misc/Paths.h"
+
+TSharedPtr<FSlateStyleSet> FGenericGraphEditorStyle::StyleSet = nullptr;
+
+#define IMAGE_BRUSH( RelativePath, ... ) FSlateImageBrush( StyleSet->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ )
+#define BOX_BRUSH( RelativePath, ... ) FSlateBoxBrush( StyleSet->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ )
+#define BORDER_BRUSH( RelativePath, ... ) FSlateBorderBrush( StyleSet->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ )
+#define TTF_FONT( RelativePath, ... ) FSlateFontInfo( StyleSet->RootToContentDir( RelativePath, TEXT(".ttf") ), __VA_ARGS__ )
+#define OTF_FONT( RelativePath, ... ) FSlateFontInfo( StyleSet->RootToContentDir( RelativePath, TEXT(".otf") ), __VA_ARGS__ )
+
+void FGenericGraphEditorStyle::Initialize()
+{
+	const FVector2D Icon20x20(20.0f, 20.0f);
+	const FVector2D Icon40x40(40.0f, 40.0f);
+	const FVector2D Icon64x64(64.0f, 64.0f);
+
+	if (StyleSet.IsValid())
+	{
+		return;
+	}
+
+	StyleSet = MakeShareable(new FSlateStyleSet("GenericGraphEditorStyle"));
+
+	StyleSet->SetContentRoot(FPaths::ProjectPluginsDir() / TEXT("GenericGraph/Resources"));
+
+	StyleSet->Set("GenericGraphEditor.AutoArrange", new IMAGE_BRUSH("AutoArrangeIcon", Icon40x40));
+	StyleSet->Set("GenericGraphEditor.AutoArrange.Small", new IMAGE_BRUSH( "AutoArrangeIcon", Icon20x20 ) );
+
+	FSlateStyleRegistry::RegisterSlateStyle(*StyleSet.Get());
+}
+
+void FGenericGraphEditorStyle::Shutdown()
+{
+	if (StyleSet.IsValid())
+	{
+		FSlateStyleRegistry::UnRegisterSlateStyle(*StyleSet.Get());
+		ensure(StyleSet.IsUnique());
+		StyleSet.Reset();
+	}
+}
+
+const FName& FGenericGraphEditorStyle::GetStyleSetName()
+{
+	return StyleSet->GetStyleSetName();
+}
+
+#undef IMAGE_BRUSH
+#undef BOX_BRUSH
+#undef BORDER_BRUSH
+#undef TTF_FONT
+#undef OTF_FONT
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/SEdNode_GenericGraphEdge.cpp b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/SEdNode_GenericGraphEdge.cpp
new file mode 100644
index 00000000..d46b0777
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/SEdNode_GenericGraphEdge.cpp
@@ -0,0 +1,199 @@
+#include "GenericGraphAssetEditor/SEdNode_GenericGraphEdge.h"
+#include "Widgets/SBoxPanel.h"
+#include "Widgets/Images/SImage.h"
+#include "Widgets/Text/SInlineEditableTextBlock.h"
+#include "Widgets/SToolTip.h"
+#include "SGraphPanel.h"
+#include "EdGraphSchema_K2.h"
+#include "GenericGraphAssetEditor/EdNode_GenericGraphNode.h"
+#include "GenericGraphAssetEditor/EdNode_GenericGraphEdge.h"
+#include "GenericGraphAssetEditor/ConnectionDrawingPolicy_GenericGraph.h"
+
+#define LOCTEXT_NAMESPACE "SGenericGraphEdge"
+
+void SEdNode_GenericGraphEdge::Construct(const FArguments& InArgs, UEdNode_GenericGraphEdge* InNode)
+{
+	this->GraphNode = InNode;
+	this->UpdateGraphNode();
+}
+
+bool SEdNode_GenericGraphEdge::RequiresSecondPassLayout() const
+{
+	return true;
+}
+
+void SEdNode_GenericGraphEdge::PerformSecondPassLayout(const TMap< UObject*, TSharedRef<SNode> >& NodeToWidgetLookup) const
+{
+	UEdNode_GenericGraphEdge* EdgeNode = CastChecked<UEdNode_GenericGraphEdge>(GraphNode);
+
+	FGeometry StartGeom;
+	FGeometry EndGeom;
+
+	UEdNode_GenericGraphNode* Start = EdgeNode->GetStartNode();
+	UEdNode_GenericGraphNode* End = EdgeNode->GetEndNode();
+	if (Start != nullptr && End != nullptr)
+	{
+		const TSharedRef<SNode>* pFromWidget = NodeToWidgetLookup.Find(Start);
+		const TSharedRef<SNode>* pToWidget = NodeToWidgetLookup.Find(End);
+		if (pFromWidget != nullptr && pToWidget != nullptr)
+		{
+			const TSharedRef<SNode>& FromWidget = *pFromWidget;
+			const TSharedRef<SNode>& ToWidget = *pToWidget;
+
+			StartGeom = FGeometry(FVector2D(Start->NodePosX, Start->NodePosY), FVector2D::ZeroVector, FromWidget->GetDesiredSize(), 1.0f);
+			EndGeom = FGeometry(FVector2D(End->NodePosX, End->NodePosY), FVector2D::ZeroVector, ToWidget->GetDesiredSize(), 1.0f);
+		}
+	}
+
+	PositionBetweenTwoNodesWithOffset(StartGeom, EndGeom, 0, 1);
+}
+
+void SEdNode_GenericGraphEdge::OnNameTextCommited(const FText& InText, ETextCommit::Type CommitInfo)
+{
+	SGraphNode::OnNameTextCommited(InText, CommitInfo);
+
+	UEdNode_GenericGraphEdge* MyNode = CastChecked<UEdNode_GenericGraphEdge>(GraphNode);
+
+	if (MyNode != nullptr && MyNode->GenericGraphEdge != nullptr)
+	{
+		const FScopedTransaction Transaction(LOCTEXT("GenericGraphEditorRenameEdge", "Generic Graph Editor: Rename Edge"));
+		MyNode->Modify();
+		MyNode->GenericGraphEdge->SetNodeTitle(InText);
+		UpdateGraphNode();
+	}
+}
+
+void SEdNode_GenericGraphEdge::UpdateGraphNode()
+{
+	InputPins.Empty();
+	OutputPins.Empty();
+
+	RightNodeBox.Reset();
+	LeftNodeBox.Reset();
+
+	TSharedPtr<SNodeTitle> NodeTitle = SNew(SNodeTitle, GraphNode);
+
+	this->ContentScale.Bind( this, &SGraphNode::GetContentScale );
+	this->GetOrAddSlot( ENodeZone::Center )
+		.HAlign(HAlign_Center)
+		.VAlign(VAlign_Center)
+		[
+			SNew(SOverlay)
+			+ SOverlay::Slot()
+			[
+				SNew(SImage)
+				.Image(FAppStyle::GetBrush("Graph.TransitionNode.ColorSpill"))
+				.ColorAndOpacity(this, &SEdNode_GenericGraphEdge::GetEdgeColor)
+			]
+			+ SOverlay::Slot()
+			[
+				SNew(SImage)
+				.Image(this, &SEdNode_GenericGraphEdge::GetEdgeImage)
+				.Visibility(this, &SEdNode_GenericGraphEdge::GetEdgeImageVisibility)
+			]
+
+			+ SOverlay::Slot()
+			.Padding(FMargin(4.0f, 4.0f, 4.0f, 4.0f))
+			[
+				SNew(SVerticalBox)
+				+ SVerticalBox::Slot()
+				.HAlign(HAlign_Center)
+				.AutoHeight()
+				[
+					SAssignNew(InlineEditableText, SInlineEditableTextBlock)
+					.ColorAndOpacity(FLinearColor::Black)
+					.Visibility(this, &SEdNode_GenericGraphEdge::GetEdgeTitleVisbility)
+					.Font(FCoreStyle::GetDefaultFontStyle("Regular", 12))
+					.Text(NodeTitle.Get(), &SNodeTitle::GetHeadTitle)
+					.OnTextCommitted(this, &SEdNode_GenericGraphEdge::OnNameTextCommited)
+				]
+				+ SVerticalBox::Slot()
+				.AutoHeight()
+				[
+					NodeTitle.ToSharedRef()
+				]
+				
+			]
+		];
+}
+
+void SEdNode_GenericGraphEdge::PositionBetweenTwoNodesWithOffset(const FGeometry& StartGeom, const FGeometry& EndGeom, int32 NodeIndex, int32 MaxNodes) const
+{
+	// Get a reasonable seed point (halfway between the boxes)
+	const FVector2D StartCenter = FGeometryHelper::CenterOf(StartGeom);
+	const FVector2D EndCenter = FGeometryHelper::CenterOf(EndGeom);
+	const FVector2D SeedPoint = (StartCenter + EndCenter) * 0.5f;
+
+	// Find the (approximate) closest points between the two boxes
+	const FVector2D StartAnchorPoint = FGeometryHelper::FindClosestPointOnGeom(StartGeom, SeedPoint);
+	const FVector2D EndAnchorPoint = FGeometryHelper::FindClosestPointOnGeom(EndGeom, SeedPoint);
+
+	// Position ourselves halfway along the connecting line between the nodes, elevated away perpendicular to the direction of the line
+	const float Height = 30.0f;
+
+	const FVector2D DesiredNodeSize = GetDesiredSize();
+
+	FVector2D DeltaPos(EndAnchorPoint - StartAnchorPoint);
+
+	if (DeltaPos.IsNearlyZero())
+	{
+		DeltaPos = FVector2D(10.0f, 0.0f);
+	}
+
+	const FVector2D Normal = FVector2D(DeltaPos.Y, -DeltaPos.X).GetSafeNormal();
+
+	const FVector2D NewCenter = StartAnchorPoint + (0.5f * DeltaPos) + (Height * Normal);
+
+	FVector2D DeltaNormal = DeltaPos.GetSafeNormal();
+	
+	// Calculate node offset in the case of multiple transitions between the same two nodes
+	// MultiNodeOffset: the offset where 0 is the centre of the transition, -1 is 1 <size of node>
+	// towards the PrevStateNode and +1 is 1 <size of node> towards the NextStateNode.
+
+	const float MutliNodeSpace = 0.2f; // Space between multiple transition nodes (in units of <size of node> )
+	const float MultiNodeStep = (1.f + MutliNodeSpace); //Step between node centres (Size of node + size of node spacer)
+
+	const float MultiNodeStart = -((MaxNodes - 1) * MultiNodeStep) / 2.f;
+	const float MultiNodeOffset = MultiNodeStart + (NodeIndex * MultiNodeStep);
+
+	// Now we need to adjust the new center by the node size, zoom factor and multi node offset
+	const FVector2D NewCorner = NewCenter - (0.5f * DesiredNodeSize) + (DeltaNormal * MultiNodeOffset * DesiredNodeSize.Size());
+
+	GraphNode->NodePosX = NewCorner.X;
+	GraphNode->NodePosY = NewCorner.Y;
+}
+
+FSlateColor SEdNode_GenericGraphEdge::GetEdgeColor() const
+{
+	UEdNode_GenericGraphEdge* EdgeNode = CastChecked<UEdNode_GenericGraphEdge>(GraphNode);
+	if (EdgeNode != nullptr && EdgeNode->GenericGraphEdge != nullptr)
+	{
+		return EdgeNode->GenericGraphEdge->GetEdgeColour();
+	}
+	return FLinearColor(0.9f, 0.9f, 0.9f, 1.0f);
+}
+
+const FSlateBrush* SEdNode_GenericGraphEdge::GetEdgeImage() const
+{
+	return FAppStyle::GetBrush("Graph.TransitionNode.Icon");
+}
+
+EVisibility SEdNode_GenericGraphEdge::GetEdgeImageVisibility() const
+{
+	UEdNode_GenericGraphEdge* EdgeNode = CastChecked<UEdNode_GenericGraphEdge>(GraphNode);
+	if (EdgeNode && EdgeNode->GenericGraphEdge && EdgeNode->GenericGraphEdge->bShouldDrawTitle)
+			return EVisibility::Hidden;
+
+	return EVisibility::Visible;
+}
+
+EVisibility SEdNode_GenericGraphEdge::GetEdgeTitleVisbility() const
+{
+	UEdNode_GenericGraphEdge* EdgeNode = CastChecked<UEdNode_GenericGraphEdge>(GraphNode);
+	if (EdgeNode && EdgeNode->GenericGraphEdge && EdgeNode->GenericGraphEdge->bShouldDrawTitle)
+		return EVisibility::Visible;
+
+	return EVisibility::Collapsed;
+}
+
+#undef LOCTEXT_NAMESPACE
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/SEdNode_GenericGraphNode.cpp b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/SEdNode_GenericGraphNode.cpp
new file mode 100644
index 00000000..d69e7eea
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/SEdNode_GenericGraphNode.cpp
@@ -0,0 +1,336 @@
+#include "GenericGraphAssetEditor/SEdNode_GenericGraphNode.h"
+#include "GenericGraphEditorPCH.h"
+#include "GenericGraphAssetEditor/Colors_GenericGraph.h"
+#include "SLevelOfDetailBranchNode.h"
+#include "Widgets/Text/SInlineEditableTextBlock.h"
+#include "SCommentBubble.h"
+#include "SlateOptMacros.h"
+#include "SGraphPin.h"
+#include "GraphEditorSettings.h"
+#include "GenericGraphAssetEditor/EdNode_GenericGraphNode.h"
+#include "GenericGraphAssetEditor/GenericGraphDragConnection.h"
+
+#define LOCTEXT_NAMESPACE "EdNode_GenericGraph"
+
+//////////////////////////////////////////////////////////////////////////
+class SGenericGraphPin : public SGraphPin
+{
+public:
+	SLATE_BEGIN_ARGS(SGenericGraphPin) {}
+	SLATE_END_ARGS()
+
+	void Construct(const FArguments& InArgs, UEdGraphPin* InPin)
+	{
+		this->SetCursor(EMouseCursor::Default);
+
+		bShowLabel = true;
+
+		GraphPinObj = InPin;
+		check(GraphPinObj != nullptr);
+
+		const UEdGraphSchema* Schema = GraphPinObj->GetSchema();
+		check(Schema);
+
+		SBorder::Construct(SBorder::FArguments()
+			.BorderImage(this, &SGenericGraphPin::GetPinBorder)
+			.BorderBackgroundColor(this, &SGenericGraphPin::GetPinColor)
+			.OnMouseButtonDown(this, &SGenericGraphPin::OnPinMouseDown)
+			.Cursor(this, &SGenericGraphPin::GetPinCursor)
+			.Padding(FMargin(5.0f))
+		);
+	}
+
+protected:
+	virtual FSlateColor GetPinColor() const override
+	{
+		return GenericGraphColors::Pin::Default;
+	}
+
+	virtual TSharedRef<SWidget>	GetDefaultValueWidget() override
+	{
+		return SNew(STextBlock);
+	}
+
+	const FSlateBrush* GetPinBorder() const
+	{
+		return FAppStyle::GetBrush(TEXT("Graph.StateNode.Body"));
+	}
+
+	virtual TSharedRef<FDragDropOperation> SpawnPinDragEvent(const TSharedRef<class SGraphPanel>& InGraphPanel, const TArray< TSharedRef<SGraphPin> >& InStartingPins) override
+	{
+		FGenericGraphDragConnection::FDraggedPinTable PinHandles;
+		PinHandles.Reserve(InStartingPins.Num());
+		// since the graph can be refreshed and pins can be reconstructed/replaced 
+		// behind the scenes, the DragDropOperation holds onto FGraphPinHandles 
+		// instead of direct widgets/graph-pins
+		for (const TSharedRef<SGraphPin>& PinWidget : InStartingPins)
+		{
+			PinHandles.Add(PinWidget->GetPinObj());
+		}
+
+		return FGenericGraphDragConnection::New(InGraphPanel, PinHandles);
+	}
+
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+void SEdNode_GenericGraphNode::Construct(const FArguments& InArgs, UEdNode_GenericGraphNode* InNode)
+{
+	GraphNode = InNode;
+	UpdateGraphNode();
+	InNode->SEdNode = this;
+}
+
+BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
+void SEdNode_GenericGraphNode::UpdateGraphNode()
+{
+	const FMargin NodePadding = FMargin(5);
+	const FMargin NamePadding = FMargin(2);
+
+	InputPins.Empty();
+	OutputPins.Empty();
+
+	// Reset variables that are going to be exposed, in case we are refreshing an already setup node.
+	RightNodeBox.Reset();
+	LeftNodeBox.Reset();
+
+	const FSlateBrush *NodeTypeIcon = GetNameIcon();
+
+	FLinearColor TitleShadowColor(0.6f, 0.6f, 0.6f);
+	TSharedPtr<SErrorText> ErrorText;
+	TSharedPtr<SVerticalBox> NodeBody;
+	TSharedPtr<SNodeTitle> NodeTitle = SNew(SNodeTitle, GraphNode);
+
+	this->ContentScale.Bind(this, &SGraphNode::GetContentScale);
+	this->GetOrAddSlot(ENodeZone::Center)
+		.HAlign(HAlign_Fill)
+		.VAlign(VAlign_Center)
+		[
+			SNew(SBorder)
+			.BorderImage(FAppStyle::GetBrush("Graph.StateNode.Body"))
+			.Padding(0.0f)
+			.BorderBackgroundColor(this, &SEdNode_GenericGraphNode::GetBorderBackgroundColor)
+			[
+				SNew(SOverlay)
+
+				+ SOverlay::Slot()
+				.HAlign(HAlign_Fill)
+				.VAlign(VAlign_Fill)
+				[
+					SNew(SVerticalBox)
+
+					// Input Pin Area
+					+ SVerticalBox::Slot()
+					.FillHeight(1)
+					[
+						SAssignNew(LeftNodeBox, SVerticalBox)
+					]
+
+					// Output Pin Area	
+					+ SVerticalBox::Slot()
+					.FillHeight(1)
+					[
+						SAssignNew(RightNodeBox, SVerticalBox)
+					]
+				]
+
+				+ SOverlay::Slot()
+				.HAlign(HAlign_Center)
+				.VAlign(VAlign_Center)
+				.Padding(8.0f)
+				[
+					SNew(SBorder)
+					.BorderImage(FAppStyle::GetBrush("Graph.StateNode.ColorSpill"))
+					.BorderBackgroundColor(TitleShadowColor)
+					.HAlign(HAlign_Center)
+					.VAlign(VAlign_Center)
+					.Visibility(EVisibility::SelfHitTestInvisible)
+					.Padding(6.0f)
+					[
+						SAssignNew(NodeBody, SVerticalBox)
+									
+						// Title
+						+ SVerticalBox::Slot()
+						.AutoHeight()
+						[
+							SNew(SHorizontalBox)
+
+							// Error message
+							+ SHorizontalBox::Slot()
+							.AutoWidth()
+							[
+								SAssignNew(ErrorText, SErrorText)
+								.BackgroundColor(this, &SEdNode_GenericGraphNode::GetErrorColor)
+								.ToolTipText(this, &SEdNode_GenericGraphNode::GetErrorMsgToolTip)
+							]
+
+							// Icon
+							+SHorizontalBox::Slot()
+							.AutoWidth()
+							.VAlign(VAlign_Center)
+							[
+								SNew(SImage)
+								.Image(NodeTypeIcon)
+							]
+										
+							// Node Title
+							+ SHorizontalBox::Slot()
+							.Padding(FMargin(4.0f, 0.0f, 4.0f, 0.0f))
+							[
+								SNew(SVerticalBox)
+								+ SVerticalBox::Slot()
+								.AutoHeight()
+								[
+									SAssignNew(InlineEditableText, SInlineEditableTextBlock)
+									.Style(FAppStyle::Get(), "Graph.StateNode.NodeTitleInlineEditableText")
+									.Text(NodeTitle.Get(), &SNodeTitle::GetHeadTitle)
+									.OnVerifyTextChanged(this, &SEdNode_GenericGraphNode::OnVerifyNameTextChanged)
+									.OnTextCommitted(this, &SEdNode_GenericGraphNode::OnNameTextCommited)
+									.IsReadOnly(this, &SEdNode_GenericGraphNode::IsNameReadOnly)
+									.IsSelected(this, &SEdNode_GenericGraphNode::IsSelectedExclusively)
+								]
+								+ SVerticalBox::Slot()
+								.AutoHeight()
+								[
+									NodeTitle.ToSharedRef()
+								]
+							]
+						]					
+					]
+				]
+			]
+		];
+
+	// Create comment bubble
+	TSharedPtr<SCommentBubble> CommentBubble;
+	const FSlateColor CommentColor = GetDefault<UGraphEditorSettings>()->DefaultCommentNodeTitleColor;
+
+	SAssignNew(CommentBubble, SCommentBubble)
+		.GraphNode(GraphNode)
+		.Text(this, &SGraphNode::GetNodeComment)
+		.OnTextCommitted(this, &SGraphNode::OnCommentTextCommitted)
+		.ColorAndOpacity(CommentColor)
+		.AllowPinning(true)
+		.EnableTitleBarBubble(true)
+		.EnableBubbleCtrls(true)
+		.GraphLOD(this, &SGraphNode::GetCurrentLOD)
+		.IsGraphNodeHovered(this, &SGraphNode::IsHovered);
+
+	GetOrAddSlot(ENodeZone::TopCenter)
+		.SlotOffset(TAttribute<FVector2D>(CommentBubble.Get(), &SCommentBubble::GetOffset))
+		.SlotSize(TAttribute<FVector2D>(CommentBubble.Get(), &SCommentBubble::GetSize))
+		.AllowScaling(TAttribute<bool>(CommentBubble.Get(), &SCommentBubble::IsScalingAllowed))
+		.VAlign(VAlign_Top)
+		[
+			CommentBubble.ToSharedRef()
+		];
+
+	ErrorReporting = ErrorText;
+	ErrorReporting->SetError(ErrorMsg);
+	CreatePinWidgets();
+}
+
+void SEdNode_GenericGraphNode::CreatePinWidgets()
+{
+	UEdNode_GenericGraphNode* StateNode = CastChecked<UEdNode_GenericGraphNode>(GraphNode);
+
+	for (int32 PinIdx = 0; PinIdx < StateNode->Pins.Num(); PinIdx++)
+	{
+		UEdGraphPin* MyPin = StateNode->Pins[PinIdx];
+		if (!MyPin->bHidden)
+		{
+			TSharedPtr<SGraphPin> NewPin = SNew(SGenericGraphPin, MyPin);
+
+			AddPin(NewPin.ToSharedRef());
+		}
+	}
+}
+
+void SEdNode_GenericGraphNode::AddPin(const TSharedRef<SGraphPin>& PinToAdd)
+{
+	PinToAdd->SetOwner(SharedThis(this));
+
+	const UEdGraphPin* PinObj = PinToAdd->GetPinObj();
+	const bool bAdvancedParameter = PinObj && PinObj->bAdvancedView;
+	if (bAdvancedParameter)
+	{
+		PinToAdd->SetVisibility( TAttribute<EVisibility>(PinToAdd, &SGraphPin::IsPinVisibleAsAdvanced) );
+	}
+
+	TSharedPtr<SVerticalBox> PinBox;
+	if (PinToAdd->GetDirection() == EEdGraphPinDirection::EGPD_Input)
+	{
+		PinBox = LeftNodeBox;
+		InputPins.Add(PinToAdd);
+	}
+	else // Direction == EEdGraphPinDirection::EGPD_Output
+	{
+		PinBox = RightNodeBox;
+		OutputPins.Add(PinToAdd);
+	}
+
+	if (PinBox)
+	{
+		PinBox->AddSlot()
+			.HAlign(HAlign_Fill)
+			.VAlign(VAlign_Fill)
+			.FillHeight(1.0f)
+			//.Padding(6.0f, 0.0f)
+			[
+				PinToAdd
+			];
+	}
+}
+
+bool SEdNode_GenericGraphNode::IsNameReadOnly() const
+{
+	UEdNode_GenericGraphNode* EdNode_Node = Cast<UEdNode_GenericGraphNode>(GraphNode);
+	check(EdNode_Node != nullptr);
+
+	UGenericGraph* GenericGraph = EdNode_Node->GenericGraphNode->Graph;
+	check(GenericGraph != nullptr);
+
+	return (!GenericGraph->bCanRenameNode || !EdNode_Node->GenericGraphNode->IsNameEditable()) || SGraphNode::IsNameReadOnly();
+}
+
+END_SLATE_FUNCTION_BUILD_OPTIMIZATION
+
+void SEdNode_GenericGraphNode::OnNameTextCommited(const FText& InText, ETextCommit::Type CommitInfo)
+{
+	SGraphNode::OnNameTextCommited(InText, CommitInfo);
+
+	UEdNode_GenericGraphNode* MyNode = CastChecked<UEdNode_GenericGraphNode>(GraphNode);
+
+	if (MyNode != nullptr && MyNode->GenericGraphNode != nullptr)
+	{
+		const FScopedTransaction Transaction(LOCTEXT("GenericGraphEditorRenameNode", "Generic Graph Editor: Rename Node"));
+		MyNode->Modify();
+		MyNode->GenericGraphNode->Modify();
+		MyNode->GenericGraphNode->SetNodeTitle(InText);
+		UpdateGraphNode();
+	}
+}
+
+FSlateColor SEdNode_GenericGraphNode::GetBorderBackgroundColor() const
+{
+	UEdNode_GenericGraphNode* MyNode = CastChecked<UEdNode_GenericGraphNode>(GraphNode);
+	return MyNode ? MyNode->GetBackgroundColor() : GenericGraphColors::NodeBorder::HighlightAbortRange0;
+}
+
+FSlateColor SEdNode_GenericGraphNode::GetBackgroundColor() const
+{
+	return GenericGraphColors::NodeBody::Default;
+}
+
+EVisibility SEdNode_GenericGraphNode::GetDragOverMarkerVisibility() const
+{
+	return EVisibility::Visible;
+}
+
+const FSlateBrush* SEdNode_GenericGraphNode::GetNameIcon() const
+{
+	return FAppStyle::GetBrush(TEXT("BTEditor.Graph.BTNode.Icon"));
+}
+
+#undef LOCTEXT_NAMESPACE
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/Settings_GenericGraphEditor.cpp b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/Settings_GenericGraphEditor.cpp
new file mode 100644
index 00000000..a5180a8d
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphAssetEditor/Settings_GenericGraphEditor.cpp
@@ -0,0 +1,24 @@
+#include "GenericGraphAssetEditor/Settings_GenericGraphEditor.h"
+
+UGenericGraphEditorSettings::UGenericGraphEditorSettings()
+{
+	AutoLayoutStrategy = EAutoLayoutStrategy::Tree;
+
+	bFirstPassOnly = false;
+
+	bRandomInit = false;
+
+	OptimalDistance = 100.f;
+
+	MaxIteration = 50;
+
+	InitTemperature = 10.f;
+
+	CoolDownRate = 10.f;
+}
+
+UGenericGraphEditorSettings::~UGenericGraphEditorSettings()
+{
+
+}
+
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphEditor.cpp b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphEditor.cpp
new file mode 100644
index 00000000..b83d1f6d
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphEditor.cpp
@@ -0,0 +1,55 @@
+#include "GenericGraphEditor.h"
+#include "GenericGraphNodeFactory.h"
+#include "AssetTypeActions_GenericGraph.h"
+#include "GenericGraphAssetEditor/GenericGraphEditorStyle.h"
+
+DEFINE_LOG_CATEGORY(GenericGraphEditor)
+
+#define LOCTEXT_NAMESPACE "Editor_GenericGraph"
+
+void FGenericGraphEditor::StartupModule()
+{
+	FGenericGraphEditorStyle::Initialize();
+
+	GraphPanelNodeFactory_GenericGraph = MakeShareable(new FGraphPanelNodeFactory_GenericGraph());
+	FEdGraphUtilities::RegisterVisualNodeFactory(GraphPanelNodeFactory_GenericGraph);
+
+	IAssetTools& AssetTools = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get();
+
+	GenericGraphAssetCategoryBit = AssetTools.RegisterAdvancedAssetCategory(FName(TEXT("GenericGraph")), LOCTEXT("GenericGraphAssetCategory", "GenericGraph"));
+
+	RegisterAssetTypeAction(AssetTools, MakeShareable(new FAssetTypeActions_GenericGraph(GenericGraphAssetCategoryBit)));
+}
+
+
+void FGenericGraphEditor::ShutdownModule()
+{
+	// Unregister all the asset types that we registered
+	if (FModuleManager::Get().IsModuleLoaded("AssetTools"))
+	{
+		IAssetTools& AssetTools = FModuleManager::GetModuleChecked<FAssetToolsModule>("AssetTools").Get();
+		for (int32 Index = 0; Index < CreatedAssetTypeActions.Num(); ++Index)
+		{
+			AssetTools.UnregisterAssetTypeActions(CreatedAssetTypeActions[Index].ToSharedRef());
+		}
+	}
+
+	if (GraphPanelNodeFactory_GenericGraph.IsValid())
+	{
+		FEdGraphUtilities::UnregisterVisualNodeFactory(GraphPanelNodeFactory_GenericGraph);
+		GraphPanelNodeFactory_GenericGraph.Reset();
+	}
+
+	FGenericGraphEditorStyle::Shutdown();
+}
+
+void FGenericGraphEditor::RegisterAssetTypeAction(IAssetTools& AssetTools, TSharedRef<IAssetTypeActions> Action)
+{
+	AssetTools.RegisterAssetTypeActions(Action);
+	CreatedAssetTypeActions.Add(Action);
+}
+
+IMPLEMENT_MODULE(FGenericGraphEditor, GenericGraphEditor)
+
+#undef LOCTEXT_NAMESPACE
+
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphFactory.cpp b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphFactory.cpp
new file mode 100644
index 00000000..4c9fc7bb
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphFactory.cpp
@@ -0,0 +1,117 @@
+#include "GenericGraphFactory.h"
+#include "GenericGraph.h"
+
+#include "ClassViewerModule.h"
+#include "ClassViewerFilter.h"
+#include "Kismet2/KismetEditorUtilities.h"
+#include "Kismet2/SClassPickerDialog.h"
+
+#define LOCTEXT_NAMESPACE "GenericGraphFactory"
+
+class FAssetClassParentFilter : public IClassViewerFilter
+{
+public:
+	FAssetClassParentFilter()
+		: DisallowedClassFlags(CLASS_None), bDisallowBlueprintBase(false)
+	{}
+
+	/** All children of these classes will be included unless filtered out by another setting. */
+	TSet< const UClass* > AllowedChildrenOfClasses;
+
+	/** Disallowed class flags. */
+	EClassFlags DisallowedClassFlags;
+
+	/** Disallow blueprint base classes. */
+	bool bDisallowBlueprintBase;
+
+	virtual bool IsClassAllowed(const FClassViewerInitializationOptions& InInitOptions, const UClass* InClass, TSharedRef< FClassViewerFilterFuncs > InFilterFuncs) override
+	{
+		bool bAllowed= !InClass->HasAnyClassFlags(DisallowedClassFlags)
+			&& InFilterFuncs->IfInChildOfClassesSet(AllowedChildrenOfClasses, InClass) != EFilterReturn::Failed;
+
+		if (bAllowed && bDisallowBlueprintBase)
+		{
+			if (FKismetEditorUtilities::CanCreateBlueprintOfClass(InClass))
+			{
+				return false;
+			}
+		}
+
+		return bAllowed;
+	}
+
+	virtual bool IsUnloadedClassAllowed(const FClassViewerInitializationOptions& InInitOptions, const TSharedRef< const IUnloadedBlueprintData > InUnloadedClassData, TSharedRef< FClassViewerFilterFuncs > InFilterFuncs) override
+	{
+		if (bDisallowBlueprintBase)
+		{
+			return false;
+		}
+
+		return !InUnloadedClassData->HasAnyClassFlags(DisallowedClassFlags)
+			&& InFilterFuncs->IfInChildOfClassesSet(AllowedChildrenOfClasses, InUnloadedClassData) != EFilterReturn::Failed;
+	}
+};
+
+
+UGenericGraphFactory::UGenericGraphFactory()
+{
+	bCreateNew = true;
+	bEditAfterNew = true;
+	SupportedClass = UGenericGraph::StaticClass();
+}
+
+UGenericGraphFactory::~UGenericGraphFactory()
+{
+
+}
+
+bool UGenericGraphFactory::ConfigureProperties()
+{
+	// nullptr the GenericGraphClass so we can check for selection
+	GenericGraphClass = nullptr;
+
+	// Load the classviewer module to display a class picker
+	FClassViewerModule& ClassViewerModule = FModuleManager::LoadModuleChecked<FClassViewerModule>("ClassViewer");
+
+	// Fill in options
+	FClassViewerInitializationOptions Options;
+	Options.Mode = EClassViewerMode::ClassPicker;
+
+#if ENGINE_MAJOR_VERSION < 5
+	TSharedPtr<FAssetClassParentFilter> Filter = MakeShareable(new FAssetClassParentFilter);
+	Options.ClassFilter = Filter;
+#else // #if ENGINE_MAJOR_VERSION < 5
+	TSharedRef<FAssetClassParentFilter> Filter = MakeShareable(new FAssetClassParentFilter);
+	Options.ClassFilters.Add(Filter);
+#endif // #else // #if ENGINE_MAJOR_VERSION < 5
+
+	Filter->DisallowedClassFlags = CLASS_Abstract | CLASS_Deprecated | CLASS_NewerVersionExists | CLASS_HideDropDown;
+	Filter->AllowedChildrenOfClasses.Add(UGenericGraph::StaticClass());
+
+	const FText TitleText = LOCTEXT("CreateGenericGraphAssetOptions", "Pick Generic Graph Class");
+	UClass* ChosenClass = nullptr;
+	const bool bPressedOk = SClassPickerDialog::PickClass(TitleText, Options, ChosenClass, UGenericGraph::StaticClass());
+
+	if ( bPressedOk )
+	{
+		GenericGraphClass = ChosenClass;
+	}
+
+	return bPressedOk;
+}
+
+UObject* UGenericGraphFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn)
+{
+	if (GenericGraphClass != nullptr)
+	{
+		return NewObject<UGenericGraph>(InParent, GenericGraphClass, Name, Flags | RF_Transactional);
+	}
+	else
+	{
+		check(Class->IsChildOf(UGenericGraph::StaticClass()));
+		return NewObject<UObject>(InParent, Class, Name, Flags | RF_Transactional);
+	}
+
+}
+
+#undef LOCTEXT_NAMESPACE
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphNodeFactory.cpp b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphNodeFactory.cpp
new file mode 100644
index 00000000..e79dd2cf
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Private/GenericGraphNodeFactory.cpp
@@ -0,0 +1,20 @@
+#include "GenericGraphNodeFactory.h"
+#include <EdGraph/EdGraphNode.h>
+#include "GenericGraphAssetEditor/SEdNode_GenericGraphEdge.h"
+#include "GenericGraphAssetEditor/EdNode_GenericGraphNode.h"
+#include "GenericGraphAssetEditor/SEdNode_GenericGraphNode.h"
+#include "GenericGraphAssetEditor/EdNode_GenericGraphEdge.h"
+
+TSharedPtr<class SGraphNode> FGraphPanelNodeFactory_GenericGraph::CreateNode(UEdGraphNode* Node) const
+{
+	if (UEdNode_GenericGraphNode* EdNode_GraphNode = Cast<UEdNode_GenericGraphNode>(Node))
+	{
+		return SNew(SEdNode_GenericGraphNode, EdNode_GraphNode);
+	}
+	else if (UEdNode_GenericGraphEdge* EdNode_Edge = Cast<UEdNode_GenericGraphEdge>(Node))
+	{
+		return SNew(SEdNode_GenericGraphEdge, EdNode_Edge);
+	}
+	return nullptr;
+}
+
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/AssetTypeActions_GenericGraph.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/AssetTypeActions_GenericGraph.h
new file mode 100644
index 00000000..8d7ba935
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/AssetTypeActions_GenericGraph.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "AssetTypeActions_Base.h"
+
+class GENERICGRAPHEDITOR_API FAssetTypeActions_GenericGraph : public FAssetTypeActions_Base
+{
+public:
+	FAssetTypeActions_GenericGraph(EAssetTypeCategories::Type InAssetCategory);
+
+	virtual FText GetName() const override;
+	virtual FColor GetTypeColor() const override;
+	virtual UClass* GetSupportedClass() const override;
+	virtual void OpenAssetEditor(const TArray<UObject*>& InObjects, TSharedPtr<class IToolkitHost> EditWithinLevelEditor = TSharedPtr<IToolkitHost>()) override;
+	virtual uint32 GetCategories() override;
+
+private:
+	EAssetTypeCategories::Type MyAssetCategory;
+};
\ No newline at end of file
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/AutoLayout/AutoLayoutStrategy.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/AutoLayout/AutoLayoutStrategy.h
new file mode 100644
index 00000000..52a5efb3
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/AutoLayout/AutoLayoutStrategy.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "EdGraph/EdGraph.h"
+#include "GenericGraph.h"
+#include "GenericGraphAssetEditor/EdGraph_GenericGraph.h"
+#include "GenericGraphAssetEditor/EdNode_GenericGraphNode.h"
+#include "GenericGraphAssetEditor/EdNode_GenericGraphEdge.h"
+#include "GenericGraphAssetEditor/Settings_GenericGraphEditor.h"
+#include "AutoLayoutStrategy.generated.h"
+
+UCLASS(abstract)
+class GENERICGRAPHEDITOR_API UAutoLayoutStrategy : public UObject
+{
+	GENERATED_BODY()
+public:
+	UAutoLayoutStrategy();
+	virtual ~UAutoLayoutStrategy();
+
+	virtual void Layout(UEdGraph* G) {};
+
+	class UGenericGraphEditorSettings* Settings;
+
+protected:
+	int32 GetNodeWidth(UEdNode_GenericGraphNode* EdNode);
+
+	int32 GetNodeHeight(UEdNode_GenericGraphNode* EdNode);
+
+	FBox2D GetNodeBound(UEdGraphNode* EdNode);
+
+	FBox2D GetActualBounds(UGenericGraphNode* RootNode);
+
+	virtual void RandomLayoutOneTree(UGenericGraphNode* RootNode, const FBox2D& Bound);
+
+protected:
+	UGenericGraph* Graph;
+	UEdGraph_GenericGraph* EdGraph;
+	int32 MaxIteration;
+	int32 OptimalDistance;
+};
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/AutoLayout/ForceDirectedLayoutStrategy.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/AutoLayout/ForceDirectedLayoutStrategy.h
new file mode 100644
index 00000000..e5c40c95
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/AutoLayout/ForceDirectedLayoutStrategy.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "AutoLayoutStrategy.h"
+#include "ForceDirectedLayoutStrategy.generated.h"
+
+UCLASS()
+class GENERICGRAPHEDITOR_API UForceDirectedLayoutStrategy : public UAutoLayoutStrategy
+{
+	GENERATED_BODY()
+public:
+	UForceDirectedLayoutStrategy();
+	virtual ~UForceDirectedLayoutStrategy();
+
+	virtual void Layout(UEdGraph* EdGraph) override;
+
+protected:
+	virtual FBox2D LayoutOneTree(UGenericGraphNode* RootNode, const FBox2D& PreTreeBound);
+
+protected:
+	bool bRandomInit;
+	float InitTemperature;
+	float CoolDownRate;
+};
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/AutoLayout/TreeLayoutStrategy.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/AutoLayout/TreeLayoutStrategy.h
new file mode 100644
index 00000000..27c7ff42
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/AutoLayout/TreeLayoutStrategy.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "AutoLayoutStrategy.h"
+#include "TreeLayoutStrategy.generated.h"
+
+UCLASS()
+class GENERICGRAPHEDITOR_API UTreeLayoutStrategy : public UAutoLayoutStrategy
+{
+	GENERATED_BODY()
+public:
+	UTreeLayoutStrategy();
+	virtual ~UTreeLayoutStrategy();
+
+	virtual void Layout(UEdGraph* EdGraph) override;
+
+protected:
+	void InitPass(UGenericGraphNode* RootNode, const FVector2D& Anchor);
+	bool ResolveConflictPass(UGenericGraphNode* Node);
+
+	bool ResolveConflict(UGenericGraphNode* LRoot, UGenericGraphNode* RRoot);
+
+	void GetLeftContour(UGenericGraphNode* RootNode, int32 Level, TArray<UEdNode_GenericGraphNode*>& Contour);
+	void GetRightContour(UGenericGraphNode* RootNode, int32 Level, TArray<UEdNode_GenericGraphNode*>& Contour);
+	
+	void ShiftSubTree(UGenericGraphNode* RootNode, const FVector2D& Offset);
+
+	void UpdateParentNodePosition(UGenericGraphNode* RootNode);
+};
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/AssetEditorToolbar_GenericGraph.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/AssetEditorToolbar_GenericGraph.h
new file mode 100644
index 00000000..37e5d092
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/AssetEditorToolbar_GenericGraph.h
@@ -0,0 +1,24 @@
+
+#pragma once
+
+#include "CoreMinimal.h"
+
+class FAssetEditor_GenericGraph;
+class FExtender;
+class FToolBarBuilder;
+
+class GENERICGRAPHEDITOR_API FAssetEditorToolbar_GenericGraph : public TSharedFromThis<FAssetEditorToolbar_GenericGraph>
+{
+public:
+	FAssetEditorToolbar_GenericGraph(TSharedPtr<FAssetEditor_GenericGraph> InGenericGraphEditor)
+		: GenericGraphEditor(InGenericGraphEditor) {}
+
+	void AddGenericGraphToolbar(TSharedPtr<FExtender> Extender);
+
+private:
+	void FillGenericGraphToolbar(FToolBarBuilder& ToolbarBuilder);
+
+protected:
+	/** Pointer back to the blueprint editor tool that owns us */
+	TWeakPtr<FAssetEditor_GenericGraph> GenericGraphEditor;
+};
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/AssetEditor_GenericGraph.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/AssetEditor_GenericGraph.h
new file mode 100644
index 00000000..f1cc415b
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/AssetEditor_GenericGraph.h
@@ -0,0 +1,137 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "Settings_GenericGraphEditor.h"
+#include "GenericGraph.h"
+
+#if ENGINE_MAJOR_VERSION == 5
+#include "UObject/ObjectSaveContext.h"
+#endif // #if ENGINE_MAJOR_VERSION == 5
+
+class FGGAssetEditorToolbar;
+
+class GENERICGRAPHEDITOR_API FAssetEditor_GenericGraph : public FAssetEditorToolkit, public FNotifyHook, public FGCObject
+{
+public:
+	FAssetEditor_GenericGraph();
+	virtual ~FAssetEditor_GenericGraph();
+
+	void InitGenericGraphAssetEditor(const EToolkitMode::Type Mode, const TSharedPtr< IToolkitHost >& InitToolkitHost, UGenericGraph* Graph);
+
+	// IToolkit interface
+	virtual void RegisterTabSpawners(const TSharedRef<FTabManager>& TabManager) override;
+	virtual void UnregisterTabSpawners(const TSharedRef<FTabManager>& TabManager) override;
+	// End of IToolkit interface
+
+	// FAssetEditorToolkit
+	virtual FName GetToolkitFName() const override;
+	virtual FText GetBaseToolkitName() const override;
+	virtual FText GetToolkitName() const override;
+	virtual FText GetToolkitToolTipText() const override;
+	virtual FLinearColor GetWorldCentricTabColorScale() const override;
+	virtual FString GetWorldCentricTabPrefix() const override;
+	virtual FString GetDocumentationLink() const override;
+	virtual void SaveAsset_Execute() override;
+	// End of FAssetEditorToolkit
+
+	//Toolbar
+	void UpdateToolbar();
+	TSharedPtr<class FAssetEditorToolbar_GenericGraph> GetToolbarBuilder() { return ToolbarBuilder; }
+	void RegisterToolbarTab(const TSharedRef<class FTabManager>& TabManager);
+
+
+	// FSerializableObject interface
+	virtual void AddReferencedObjects(FReferenceCollector& Collector) override;
+	// End of FSerializableObject interface
+
+#if ENGINE_MAJOR_VERSION == 5
+	// FGCObject interface
+	virtual FString GetReferencerName() const
+	{
+		return TEXT("FAssetEditor_LTGenericGraph");
+	}
+	// ~FGCObject interface
+#endif // #if ENGINE_MAJOR_VERSION == 5
+
+	UGenericGraphEditorSettings* GetSettings() const;
+
+protected:
+	TSharedRef<SDockTab> SpawnTab_Viewport(const FSpawnTabArgs& Args);
+	TSharedRef<SDockTab> SpawnTab_Details(const FSpawnTabArgs& Args);
+	TSharedRef<SDockTab> SpawnTab_EditorSettings(const FSpawnTabArgs& Args);
+
+	void CreateInternalWidgets();
+	TSharedRef<SGraphEditor> CreateViewportWidget();
+
+
+	void BindCommands();
+
+	void CreateEdGraph();
+
+	void CreateCommandList();
+
+	TSharedPtr<SGraphEditor> GetCurrGraphEditor() const;
+
+	FGraphPanelSelectionSet GetSelectedNodes() const;
+
+	void RebuildGenericGraph();
+
+	// Delegates for graph editor commands
+	void SelectAllNodes();
+	bool CanSelectAllNodes();
+	void DeleteSelectedNodes();
+	bool CanDeleteNodes();
+	void DeleteSelectedDuplicatableNodes();
+	void CutSelectedNodes();
+	bool CanCutNodes();
+	void CopySelectedNodes();
+	bool CanCopyNodes();
+	void PasteNodes();
+	void PasteNodesHere(const FVector2D& Location);
+	bool CanPasteNodes();
+	void DuplicateNodes();
+	bool CanDuplicateNodes();
+
+	void GraphSettings();
+	bool CanGraphSettings() const;
+
+	void AutoArrange();
+	bool CanAutoArrange() const;
+
+	void OnRenameNode();
+	bool CanRenameNodes() const;
+
+	//////////////////////////////////////////////////////////////////////////
+	// graph editor event
+	void OnSelectedNodesChanged(const TSet<class UObject*>& NewSelection);
+
+	void OnNodeDoubleClicked(UEdGraphNode* Node);
+
+	void OnFinishedChangingProperties(const FPropertyChangedEvent& PropertyChangedEvent);
+
+#if ENGINE_MAJOR_VERSION < 5
+	void OnPackageSaved(const FString& PackageFileName, UObject* Outer);
+#else // #if ENGINE_MAJOR_VERSION < 5
+	void OnPackageSavedWithContext(const FString& PackageFileName, UPackage* Package, FObjectPostSaveContext ObjectSaveContext);
+#endif // #else // #if ENGINE_MAJOR_VERSION < 5
+
+protected:
+	UGenericGraphEditorSettings* GenricGraphEditorSettings;
+
+	UGenericGraph* EditingGraph;
+
+	//Toolbar
+	TSharedPtr<class FAssetEditorToolbar_GenericGraph> ToolbarBuilder;
+
+	/** Handle to the registered OnPackageSave delegate */
+	FDelegateHandle OnPackageSavedDelegateHandle;
+
+	TSharedPtr<SGraphEditor> ViewportWidget;
+	TSharedPtr<class IDetailsView> PropertyWidget;
+	TSharedPtr<class IDetailsView> EditorSettingsWidget;
+
+	/** The command list for this editor */
+	TSharedPtr<FUICommandList> GraphEditorCommands;
+};
+
+
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/AssetGraphSchema_GenericGraph.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/AssetGraphSchema_GenericGraph.h
new file mode 100644
index 00000000..faf74b9c
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/AssetGraphSchema_GenericGraph.h
@@ -0,0 +1,90 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "GenericGraph.h"
+#include "GenericGraphNode.h"
+#include "GenericGraphEdge.h"
+#include "AssetGraphSchema_GenericGraph.generated.h"
+
+class UEdNode_GenericGraphNode;
+class UEdNode_GenericGraphEdge;
+class UAutoLayoutStrategy;
+
+/** Action to add a node to the graph */
+USTRUCT()
+struct GENERICGRAPHEDITOR_API FAssetSchemaAction_GenericGraph_NewNode : public FEdGraphSchemaAction
+{
+	GENERATED_USTRUCT_BODY();
+
+public:
+	FAssetSchemaAction_GenericGraph_NewNode(): NodeTemplate(nullptr) {}
+
+	FAssetSchemaAction_GenericGraph_NewNode(const FText& InNodeCategory, const FText& InMenuDesc, const FText& InToolTip, const int32 InGrouping)
+		: FEdGraphSchemaAction(InNodeCategory, InMenuDesc, InToolTip, InGrouping), NodeTemplate(nullptr) {}
+
+	virtual UEdGraphNode* PerformAction(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2D Location, bool bSelectNewNode = true) override;
+	virtual void AddReferencedObjects(FReferenceCollector& Collector) override;
+
+	UEdNode_GenericGraphNode* NodeTemplate;
+};
+
+USTRUCT()
+struct GENERICGRAPHEDITOR_API FAssetSchemaAction_GenericGraph_NewEdge : public FEdGraphSchemaAction
+{
+	GENERATED_USTRUCT_BODY();
+
+public:
+	FAssetSchemaAction_GenericGraph_NewEdge(): NodeTemplate(nullptr){}
+
+	FAssetSchemaAction_GenericGraph_NewEdge(const FText& InNodeCategory, const FText& InMenuDesc, const FText& InToolTip, const int32 InGrouping)
+		: FEdGraphSchemaAction(InNodeCategory, InMenuDesc, InToolTip, InGrouping), NodeTemplate(nullptr) {}
+
+	virtual UEdGraphNode* PerformAction(class UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2D Location, bool bSelectNewNode = true) override;
+	virtual void AddReferencedObjects(FReferenceCollector& Collector) override;
+
+	UEdNode_GenericGraphEdge* NodeTemplate;
+};
+
+UCLASS(MinimalAPI)
+class UAssetGraphSchema_GenericGraph : public UEdGraphSchema
+{
+	GENERATED_BODY()
+
+public:
+	void GetBreakLinkToSubMenuActions(class UToolMenu* Menu, class UEdGraphPin* InGraphPin);
+
+	virtual EGraphType GetGraphType(const UEdGraph* TestEdGraph) const override;
+
+ 	virtual void GetGraphContextActions(FGraphContextMenuBuilder& ContextMenuBuilder) const override;
+
+	virtual void GetContextMenuActions(class UToolMenu* Menu, class UGraphNodeContextMenuContext* Context) const override;
+
+ 	virtual const FPinConnectionResponse CanCreateConnection(const UEdGraphPin* A, const UEdGraphPin* B) const override;
+
+	virtual bool TryCreateConnection(UEdGraphPin* A, UEdGraphPin* B) const override;
+	virtual bool CreateAutomaticConversionNodeAndConnections(UEdGraphPin* A, UEdGraphPin* B) const override;
+
+	virtual class FConnectionDrawingPolicy* CreateConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID, float InZoomFactor, const FSlateRect& InClippingRect, class FSlateWindowElementList& InDrawElements, class UEdGraph* InGraphObj) const override;
+
+ 	virtual FLinearColor GetPinTypeColor(const FEdGraphPinType& PinType) const override;
+
+ 	virtual void BreakNodeLinks(UEdGraphNode& TargetNode) const override;
+
+ 	virtual void BreakPinLinks(UEdGraphPin& TargetPin, bool bSendsNodeNotifcation) const override;
+
+	virtual void BreakSinglePinLink(UEdGraphPin* SourcePin, UEdGraphPin* TargetPin) const override;
+
+	virtual UEdGraphPin* DropPinOnNode(UEdGraphNode* InTargetNode, const FName& InSourcePinName, const FEdGraphPinType& InSourcePinType, EEdGraphPinDirection InSourcePinDirection) const override;
+
+	virtual bool SupportsDropPinOnNode(UEdGraphNode* InTargetNode, const FEdGraphPinType& InSourcePinType, EEdGraphPinDirection InSourcePinDirection, FText& OutErrorMessage) const override;
+
+	virtual bool IsCacheVisualizationOutOfDate(int32 InVisualizationCacheID) const override;
+
+	virtual int32 GetCurrentVisualizationCacheID() const override;
+
+	virtual void ForceVisualizationCacheClear() const override;
+
+private:
+	static int32 CurrentCacheRefreshID;
+};
+
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/Colors_GenericGraph.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/Colors_GenericGraph.h
new file mode 100644
index 00000000..5258d1a8
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/Colors_GenericGraph.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include "CoreMinimal.h"
+
+namespace GenericGraphColors
+{
+	namespace NodeBody
+	{
+		const FLinearColor Default(0.1f, 0.1f, 0.1f);
+		const FLinearColor Root(0.5f, 0.5f, 0.5f, 0.1f);
+		const FLinearColor Error(1.0f, 0.0f, 0.0f);
+	}
+
+	namespace NodeBorder
+	{
+		const FLinearColor Inactive(0.08f, 0.08f, 0.08f);
+		const FLinearColor Root(0.2f, 0.2f, 0.2f, 0.2f);
+		const FLinearColor Selected(1.00f, 0.08f, 0.08f);
+		const FLinearColor ActiveDebugging(1.0f, 1.0f, 0.0f);
+		const FLinearColor InactiveDebugging(0.4f, 0.4f, 0.0f);
+		const FLinearColor HighlightAbortRange0(0.0f, 0.22f, 0.4f);
+		const FLinearColor HighlightAbortRange1(0.0f, 0.4f, 0.22f);
+		const FLinearColor Disconnected(0.f, 0.f, 0.f);
+		const FLinearColor BrokenWithParent(1.f, 0.f, 1.f);
+		const FLinearColor QuickFind(0.f, 0.8f, 0.f);
+	}
+
+	namespace Pin
+	{
+		const FLinearColor Diff(0.9f, 0.2f, 0.15f);
+		const FLinearColor Hover(1.0f, 0.7f, 0.0f);
+		const FLinearColor Default(0.02f, 0.02f, 0.02f);
+		const FLinearColor SingleNode(0.02f, 0.02f, 0.02f);
+	}
+	
+	namespace Connection
+	{
+		const FLinearColor Default(1.0f, 1.0f, 1.0f);
+	}
+
+	namespace Action
+	{
+		const FLinearColor DragMarker(1.0f, 1.0f, 0.2f);
+	}
+}
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/ConnectionDrawingPolicy_GenericGraph.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/ConnectionDrawingPolicy_GenericGraph.h
new file mode 100644
index 00000000..e375e816
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/ConnectionDrawingPolicy_GenericGraph.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "ConnectionDrawingPolicy.h"
+
+class GENERICGRAPHEDITOR_API FConnectionDrawingPolicy_GenericGraph : public FConnectionDrawingPolicy
+{
+protected:
+	UEdGraph* GraphObj;
+	TMap<UEdGraphNode*, int32> NodeWidgetMap;
+
+public:
+	FConnectionDrawingPolicy_GenericGraph(int32 InBackLayerID, int32 InFrontLayerID, float ZoomFactor, const FSlateRect& InClippingRect, FSlateWindowElementList& InDrawElements, UEdGraph* InGraphObj);
+
+	// FConnectionDrawingPolicy interface 
+	virtual void DetermineWiringStyle(UEdGraphPin* OutputPin, UEdGraphPin* InputPin, /*inout*/ FConnectionParams& Params) override;
+	virtual void Draw(TMap<TSharedRef<SWidget>, FArrangedWidget>& PinGeometries, FArrangedChildren& ArrangedNodes) override;
+	virtual void DrawSplineWithArrow(const FGeometry& StartGeom, const FGeometry& EndGeom, const FConnectionParams& Params) override;
+	virtual void DrawSplineWithArrow(const FVector2D& StartPoint, const FVector2D& EndPoint, const FConnectionParams& Params) override;
+	virtual void DrawPreviewConnector(const FGeometry& PinGeometry, const FVector2D& StartPoint, const FVector2D& EndPoint, UEdGraphPin* Pin) override;
+	virtual FVector2D ComputeSplineTangent(const FVector2D& Start, const FVector2D& End) const override;
+	virtual void DetermineLinkGeometry(FArrangedChildren& ArrangedNodes, TSharedRef<SWidget>& OutputPinWidget, UEdGraphPin* OutputPin, UEdGraphPin* InputPin, FArrangedWidget*& StartWidgetGeometry, FArrangedWidget*& EndWidgetGeometry) override;
+	// End of FConnectionDrawingPolicy interface
+
+protected:
+	void Internal_DrawLineWithArrow(const FVector2D& StartAnchorPoint, const FVector2D& EndAnchorPoint, const FConnectionParams& Params);
+};
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/EdGraph_GenericGraph.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/EdGraph_GenericGraph.h
new file mode 100644
index 00000000..5cb92af3
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/EdGraph_GenericGraph.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "EdGraph/EdGraph.h"
+#include "EdGraph_GenericGraph.generated.h"
+
+class UGenericGraph;
+class UGenericGraphNode;
+class UGenericGraphEdge;
+class UEdNode_GenericGraphNode;
+class UEdNode_GenericGraphEdge;
+
+UCLASS()
+class GENERICGRAPHEDITOR_API UEdGraph_GenericGraph : public UEdGraph
+{
+	GENERATED_BODY()
+
+public:
+	UEdGraph_GenericGraph();
+	virtual ~UEdGraph_GenericGraph();
+
+	virtual void RebuildGenericGraph();
+
+	UGenericGraph* GetGenericGraph() const;
+
+	virtual bool Modify(bool bAlwaysMarkDirty = true) override;
+	virtual void PostEditUndo() override;
+
+	UPROPERTY(Transient)
+	TMap<UGenericGraphNode*, UEdNode_GenericGraphNode*> NodeMap;
+
+	UPROPERTY(Transient)
+	TMap<UGenericGraphEdge*, UEdNode_GenericGraphEdge*> EdgeMap;
+
+protected:
+	void Clear();
+
+	void SortNodes(UGenericGraphNode* RootNode);
+};
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/EdNode_GenericGraphEdge.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/EdNode_GenericGraphEdge.h
new file mode 100644
index 00000000..ac480d8f
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/EdNode_GenericGraphEdge.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "EdGraph/EdGraphNode.h"
+#include "EdNode_GenericGraphEdge.generated.h"
+
+class UGenericGraphNode;
+class UGenericGraphEdge;
+class UEdNode_GenericGraphNode;
+
+UCLASS(MinimalAPI)
+class UEdNode_GenericGraphEdge : public UEdGraphNode
+{
+	GENERATED_BODY()
+
+public:
+	UEdNode_GenericGraphEdge();
+
+	UPROPERTY()
+	class UEdGraph* Graph;
+
+	UPROPERTY(VisibleAnywhere, Instanced, Category = "GenericGraph")
+	UGenericGraphEdge* GenericGraphEdge;
+
+	void SetEdge(UGenericGraphEdge* Edge);
+
+	virtual void AllocateDefaultPins() override;
+
+	virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override;
+
+	virtual void PinConnectionListChanged(UEdGraphPin* Pin) override;
+
+	virtual void PrepareForCopying() override;
+
+	virtual UEdGraphPin* GetInputPin() const { return Pins[0]; }
+	virtual UEdGraphPin* GetOutputPin() const { return Pins[1]; }
+
+	void CreateConnections(UEdNode_GenericGraphNode* Start, UEdNode_GenericGraphNode* End);
+
+	UEdNode_GenericGraphNode* GetStartNode();
+	UEdNode_GenericGraphNode* GetEndNode();
+};
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/EdNode_GenericGraphNode.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/EdNode_GenericGraphNode.h
new file mode 100644
index 00000000..258a089c
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/EdNode_GenericGraphNode.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "EdGraph/EdGraphNode.h"
+#include "GenericGraphNode.h"
+#include "EdNode_GenericGraphNode.generated.h"
+
+class UEdNode_GenericGraphEdge;
+class UEdGraph_GenericGraph;
+class SEdNode_GenericGraphNode;
+
+UCLASS(MinimalAPI)
+class UEdNode_GenericGraphNode : public UEdGraphNode
+{
+	GENERATED_BODY()
+
+public:
+	UEdNode_GenericGraphNode();
+	virtual ~UEdNode_GenericGraphNode();
+
+	UPROPERTY(VisibleAnywhere, Instanced, Category = "GenericGraph")
+	UGenericGraphNode* GenericGraphNode;
+
+	void SetGenericGraphNode(UGenericGraphNode* InNode);
+	UEdGraph_GenericGraph* GetGenericGraphEdGraph();
+
+	SEdNode_GenericGraphNode* SEdNode;
+
+	virtual void AllocateDefaultPins() override;
+	virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override;
+	virtual void PrepareForCopying() override;
+	virtual void AutowireNewNode(UEdGraphPin* FromPin) override;
+
+	virtual FLinearColor GetBackgroundColor() const;
+	virtual UEdGraphPin* GetInputPin() const;
+	virtual UEdGraphPin* GetOutputPin() const;
+
+#if WITH_EDITOR
+	virtual void PostEditUndo() override;
+#endif
+
+};
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/EditorCommands_GenericGraph.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/EditorCommands_GenericGraph.h
new file mode 100644
index 00000000..ff6c5bd9
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/EditorCommands_GenericGraph.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "CoreMinimal.h"
+
+class GENERICGRAPHEDITOR_API FEditorCommands_GenericGraph : public TCommands<FEditorCommands_GenericGraph>
+{
+public:
+	/** Constructor */
+	FEditorCommands_GenericGraph()
+		: TCommands<FEditorCommands_GenericGraph>("GenericGraphEditor", NSLOCTEXT("Contexts", "GenericGraphEditor", "Generic Graph Editor"), NAME_None, FAppStyle::GetAppStyleSetName())
+	{
+	}
+	
+	TSharedPtr<FUICommandInfo> GraphSettings;
+	TSharedPtr<FUICommandInfo> AutoArrange;
+
+	virtual void RegisterCommands() override;
+};
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/GenericGraphDragConnection.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/GenericGraphDragConnection.h
new file mode 100644
index 00000000..bd0a91af
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/GenericGraphDragConnection.h
@@ -0,0 +1,52 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "Input/DragAndDrop.h"
+#include "Input/Reply.h"
+#include "Widgets/SWidget.h"
+#include "SGraphPin.h"
+#include "GraphEditorDragDropAction.h"
+
+class SGraphPanel;
+class UEdGraph;
+
+class FGenericGraphDragConnection : public FGraphEditorDragDropAction
+{
+public:
+	DRAG_DROP_OPERATOR_TYPE(FDragConnection, FGraphEditorDragDropAction)
+
+		typedef TArray<FGraphPinHandle> FDraggedPinTable;
+	static TSharedRef<FGenericGraphDragConnection> New(const TSharedRef<SGraphPanel>& InGraphPanel, const FDraggedPinTable& InStartingPins);
+
+	// FDragDropOperation interface
+	virtual void OnDrop(bool bDropWasHandled, const FPointerEvent& MouseEvent) override;
+	// End of FDragDropOperation interface
+
+	// FGraphEditorDragDropAction interface
+	virtual void HoverTargetChanged() override;
+	virtual FReply DroppedOnPin(FVector2D ScreenPosition, FVector2D GraphPosition) override;
+	virtual FReply DroppedOnNode(FVector2D ScreenPosition, FVector2D GraphPosition) override;
+	virtual FReply DroppedOnPanel(const TSharedRef< SWidget >& Panel, FVector2D ScreenPosition, FVector2D GraphPosition, UEdGraph& Graph) override;
+	virtual void OnDragged(const class FDragDropEvent& DragDropEvent) override;
+	// End of FGraphEditorDragDropAction interface
+
+	/*
+	 *	Function to check validity of graph pins in the StartPins list. This check helps to prevent processing graph pins which are outdated.
+	 */
+	virtual void ValidateGraphPinList(TArray<UEdGraphPin*>& OutValidPins);
+
+protected:
+	typedef FGraphEditorDragDropAction Super;
+
+	// Constructor: Make sure to call Construct() after factorying one of these
+	FGenericGraphDragConnection(const TSharedRef<SGraphPanel>& GraphPanel, const FDraggedPinTable& DraggedPins);
+
+protected:
+	TSharedPtr<SGraphPanel> GraphPanel;
+	FDraggedPinTable DraggingPins;
+
+	/** Offset information for the decorator widget */
+	FVector2D DecoratorAdjust;
+};
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/GenericGraphEditorStyle.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/GenericGraphEditorStyle.h
new file mode 100644
index 00000000..577312f3
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/GenericGraphEditorStyle.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "Styling/SlateStyle.h"
+
+class GENERICGRAPHEDITOR_API FGenericGraphEditorStyle
+{
+public:
+	static void Initialize();
+	static void Shutdown();
+
+	static const FName& GetStyleSetName();
+
+private:
+	static TSharedPtr<FSlateStyleSet> StyleSet;
+};
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/SEdNode_GenericGraphEdge.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/SEdNode_GenericGraphEdge.h
new file mode 100644
index 00000000..8505a5f6
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/SEdNode_GenericGraphEdge.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "Styling/SlateColor.h"
+#include "Widgets/DeclarativeSyntaxSupport.h"
+#include "Widgets/SWidget.h"
+#include "SNodePanel.h"
+#include "SGraphNode.h"
+
+class SToolTip;
+class UEdNode_GenericGraphEdge;
+
+class GENERICGRAPHEDITOR_API SEdNode_GenericGraphEdge : public SGraphNode
+{
+public:
+	SLATE_BEGIN_ARGS(SEdNode_GenericGraphEdge){}
+	SLATE_END_ARGS()
+
+	void Construct(const FArguments& InArgs, UEdNode_GenericGraphEdge* InNode);
+
+	virtual bool RequiresSecondPassLayout() const override;
+	virtual void PerformSecondPassLayout(const TMap< UObject*, TSharedRef<SNode> >& NodeToWidgetLookup) const override;
+
+	virtual void UpdateGraphNode() override;
+
+	// Calculate position for multiple nodes to be placed between a start and end point, by providing this nodes index and max expected nodes 
+	void PositionBetweenTwoNodesWithOffset(const FGeometry& StartGeom, const FGeometry& EndGeom, int32 NodeIndex, int32 MaxNodes) const;
+
+	void OnNameTextCommited(const FText& InText, ETextCommit::Type CommitInfo);
+
+protected:
+	FSlateColor GetEdgeColor() const;
+
+	const FSlateBrush* GetEdgeImage() const;
+
+	EVisibility GetEdgeImageVisibility() const;
+	EVisibility GetEdgeTitleVisbility() const;
+private:
+	TSharedPtr<STextEntryPopup> TextEntryWidget;
+};
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/SEdNode_GenericGraphNode.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/SEdNode_GenericGraphNode.h
new file mode 100644
index 00000000..1d4d9b99
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/SEdNode_GenericGraphNode.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "SGraphNode.h"
+
+class UEdNode_GenericGraphNode;
+
+class GENERICGRAPHEDITOR_API SEdNode_GenericGraphNode : public SGraphNode
+{
+public:
+	SLATE_BEGIN_ARGS(SEdNode_GenericGraphNode) {}
+	SLATE_END_ARGS()
+
+	void Construct(const FArguments& InArgs, UEdNode_GenericGraphNode* InNode);
+
+	virtual void UpdateGraphNode() override;
+	virtual void CreatePinWidgets() override;
+	virtual void AddPin(const TSharedRef<SGraphPin>& PinToAdd) override;
+	virtual bool IsNameReadOnly() const override;
+
+	void OnNameTextCommited(const FText& InText, ETextCommit::Type CommitInfo);
+
+	virtual FSlateColor GetBorderBackgroundColor() const;
+	virtual FSlateColor GetBackgroundColor() const;
+
+	virtual EVisibility GetDragOverMarkerVisibility() const;
+
+	virtual const FSlateBrush* GetNameIcon() const;
+
+protected:
+};
+
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/Settings_GenericGraphEditor.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/Settings_GenericGraphEditor.h
new file mode 100644
index 00000000..c1e39156
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphAssetEditor/Settings_GenericGraphEditor.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "Settings_GenericGraphEditor.generated.h"
+
+UENUM(BlueprintType)
+enum class EAutoLayoutStrategy : uint8
+{
+	Tree,
+	ForceDirected,
+};
+
+UCLASS()
+class GENERICGRAPHEDITOR_API UGenericGraphEditorSettings : public UObject
+{
+	GENERATED_BODY()
+
+public:
+	UGenericGraphEditorSettings();
+	virtual ~UGenericGraphEditorSettings();
+
+	UPROPERTY(EditDefaultsOnly, Category = "AutoArrange")
+	float OptimalDistance;
+
+	UPROPERTY(EditDefaultsOnly, AdvancedDisplay, Category = "AutoArrange")
+	EAutoLayoutStrategy AutoLayoutStrategy;
+
+	UPROPERTY(EditDefaultsOnly, AdvancedDisplay, Category = "AutoArrange")
+	int32 MaxIteration;
+
+	UPROPERTY(EditDefaultsOnly, AdvancedDisplay, Category = "AutoArrange")
+	bool bFirstPassOnly;
+
+	UPROPERTY(EditDefaultsOnly, AdvancedDisplay, Category = "AutoArrange")
+	bool bRandomInit;
+
+	UPROPERTY(EditDefaultsOnly, AdvancedDisplay, Category = "AutoArrange")
+	float InitTemperature;
+
+	UPROPERTY(EditDefaultsOnly, AdvancedDisplay, Category = "AutoArrange")
+	float CoolDownRate;
+};
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphEditor.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphEditor.h
new file mode 100644
index 00000000..f710fc2c
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphEditor.h
@@ -0,0 +1,23 @@
+#pragma once
+#include "Modules/ModuleManager.h"
+#include "GenericGraphEditorModule.h"
+#include <IAssetTools.h>
+#include <EdGraphUtilities.h>
+
+class FGenericGraphEditor : public IGenericGraphEditor
+{
+	/** IModuleInterface implementation */
+	virtual void StartupModule() override;
+	virtual void ShutdownModule() override;
+
+
+private:
+	void RegisterAssetTypeAction(IAssetTools& AssetTools, TSharedRef<IAssetTypeActions> Action);
+
+private:
+	TArray< TSharedPtr<IAssetTypeActions> > CreatedAssetTypeActions;
+
+	EAssetTypeCategories::Type GenericGraphAssetCategoryBit;
+
+	TSharedPtr<FGraphPanelNodeFactory> GraphPanelNodeFactory_GenericGraph;
+};
\ No newline at end of file
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphEditorModule.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphEditorModule.h
new file mode 100644
index 00000000..c042dc1f
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphEditorModule.h
@@ -0,0 +1,34 @@
+#include"Modules/ModuleManager.h"
+
+DECLARE_LOG_CATEGORY_EXTERN(GenericGraphEditor, Log, All);
+
+/**
+ * The public interface to this module
+ */
+class IGenericGraphEditor : public IModuleInterface
+{
+
+public:
+
+	/**
+	 * Singleton-like access to this module's interface.  This is just for convenience!
+	 * Beware of calling this during the shutdown phase, though.  Your module might have been unloaded already.
+	 *
+	 * @return Returns singleton instance, loading the module on demand if needed
+	 */
+	static IGenericGraphEditor& Get()
+	{
+		return FModuleManager::LoadModuleChecked< IGenericGraphEditor >("GenericGraphEditor");
+	}
+
+	/**
+	 * Checks to see if this module is loaded and ready.  It is only valid to call Get() if IsAvailable() returns true.
+	 *
+	 * @return True if the module is loaded and ready to use
+	 */
+	static bool IsAvailable()
+	{
+		return FModuleManager::Get().IsModuleLoaded("GenericGraphEditor");
+	}
+};
+
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphEditorPCH.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphEditorPCH.h
new file mode 100644
index 00000000..f0385f7d
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphEditorPCH.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "GenericGraph.h"
+#include "GenericGraphNode.h"
+#include "GenericGraphEdge.h"
+
+// You should place include statements to your module's private header files here.  You only need to
+// add includes for headers that are used in most of your module's source files though.
+#include "GenericGraphEditor.h"
+
+#define LOG_INFO(FMT, ...) UE_LOG(GenericGraphEditor, Display, (FMT), ##__VA_ARGS__)
+#define LOG_WARNING(FMT, ...) UE_LOG(GenericGraphEditor, Warning, (FMT), ##__VA_ARGS__)
+#define LOG_ERROR(FMT, ...) UE_LOG(GenericGraphEditor, Error, (FMT), ##__VA_ARGS__)
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphFactory.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphFactory.h
new file mode 100644
index 00000000..00cc44d4
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphFactory.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "Factories/Factory.h"
+#include "GenericGraph.h"
+#include "GenericGraphFactory.generated.h"
+
+UCLASS()
+class GENERICGRAPHEDITOR_API UGenericGraphFactory : public UFactory
+{
+	GENERATED_BODY()
+
+public:
+	UGenericGraphFactory();
+	virtual ~UGenericGraphFactory();
+
+	UPROPERTY(EditAnywhere, Category=DataAsset)
+	TSubclassOf<UGenericGraph> GenericGraphClass;
+
+	virtual bool ConfigureProperties() override;
+	virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override;
+};
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphNodeFactory.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphNodeFactory.h
new file mode 100644
index 00000000..5feb3345
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphEditor/Public/GenericGraphNodeFactory.h
@@ -0,0 +1,8 @@
+#pragma once
+#include <EdGraphUtilities.h>
+#include <EdGraph/EdGraphNode.h>
+
+class FGraphPanelNodeFactory_GenericGraph : public FGraphPanelNodeFactory
+{
+	virtual TSharedPtr<class SGraphNode> CreateNode(UEdGraphNode* Node) const override;
+};
\ No newline at end of file
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/GenericGraphRuntime.Build.cs b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/GenericGraphRuntime.Build.cs
new file mode 100644
index 00000000..e3d5c5d9
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/GenericGraphRuntime.Build.cs
@@ -0,0 +1,51 @@
+using UnrealBuildTool;
+
+public class GenericGraphRuntime : ModuleRules
+{
+	public GenericGraphRuntime(ReadOnlyTargetRules Target) : base(Target)
+    {
+		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
+		bLegacyPublicIncludePaths = false;
+		ShadowVariableWarningLevel = WarningLevel.Error;
+
+		PublicIncludePaths.AddRange(
+			new string[] {
+				// ... add public include paths required here ...
+			}
+			);
+
+		PrivateIncludePaths.AddRange(
+			new string[] {
+				"GenericGraphRuntime/Private",
+				// ... add other private include paths required here ...
+			}
+			);
+
+		PublicDependencyModuleNames.AddRange(
+			new string[]
+			{
+				"Core",
+				"CoreUObject",
+                "Engine",
+				// ... add other public dependencies that you statically link with here ...
+			}
+			);
+
+		PrivateDependencyModuleNames.AddRange(
+			new string[]
+			{
+				// ... add private dependencies that you statically link with here ...
+                "Slate",
+                "SlateCore",
+                "GameplayTags"
+            }
+			);
+
+		DynamicallyLoadedModuleNames.AddRange(
+			new string[]
+			{
+				// ... add any modules that your module loads dynamically here ...
+			}
+			);
+	}
+}
\ No newline at end of file
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Private/GenericGraph.cpp b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Private/GenericGraph.cpp
new file mode 100644
index 00000000..c2bbb302
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Private/GenericGraph.cpp
@@ -0,0 +1,136 @@
+#include "GenericGraph.h"
+#include "GenericGraphRuntimePCH.h"
+#include "Engine/Engine.h"
+
+#define LOCTEXT_NAMESPACE "GenericGraph"
+
+UGenericGraph::UGenericGraph()
+{
+	NodeType = UGenericGraphNode::StaticClass();
+	EdgeType = UGenericGraphEdge::StaticClass();
+
+	bEdgeEnabled = true;
+
+#if WITH_EDITORONLY_DATA
+	EdGraph = nullptr;
+
+	bCanRenameNode = true;
+#endif
+}
+
+UGenericGraph::~UGenericGraph()
+{
+
+}
+
+void UGenericGraph::Print(bool ToConsole /*= true*/, bool ToScreen /*= true*/)
+{
+	int Level = 0;
+	TArray<UGenericGraphNode*> CurrLevelNodes = RootNodes;
+	TArray<UGenericGraphNode*> NextLevelNodes;
+
+	while (CurrLevelNodes.Num() != 0)
+	{
+		for (int i = 0; i < CurrLevelNodes.Num(); ++i)
+		{
+			UGenericGraphNode* Node = CurrLevelNodes[i];
+			check(Node != nullptr);
+
+			FString Message = FString::Printf(TEXT("%s, Level %d"), *Node->GetDescription().ToString(), Level);
+
+			if (ToConsole)
+			{
+				LOG_INFO(TEXT("%s"), *Message);
+			}
+
+			if (ToScreen && GEngine != nullptr)
+			{
+				GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Blue, Message);
+			}
+
+			for (int j = 0; j < Node->ChildrenNodes.Num(); ++j)
+			{
+				NextLevelNodes.Add(Node->ChildrenNodes[j]);
+			}
+		}
+
+		CurrLevelNodes = NextLevelNodes;
+		NextLevelNodes.Reset();
+		++Level;
+	}
+}
+
+int UGenericGraph::GetLevelNum() const
+{
+	int Level = 0;
+	TArray<UGenericGraphNode*> CurrLevelNodes = RootNodes;
+	TArray<UGenericGraphNode*> NextLevelNodes;
+
+	while (CurrLevelNodes.Num() != 0)
+	{
+		for (int i = 0; i < CurrLevelNodes.Num(); ++i)
+		{
+			UGenericGraphNode* Node = CurrLevelNodes[i];
+			check(Node != nullptr);
+
+			for (int j = 0; j < Node->ChildrenNodes.Num(); ++j)
+			{
+				NextLevelNodes.Add(Node->ChildrenNodes[j]);
+			}
+		}
+
+		CurrLevelNodes = NextLevelNodes;
+		NextLevelNodes.Reset();
+		++Level;
+	}
+
+	return Level;
+}
+
+void UGenericGraph::GetNodesByLevel(int Level, TArray<UGenericGraphNode*>& Nodes)
+{
+	int CurrLEvel = 0;
+	TArray<UGenericGraphNode*> NextLevelNodes;
+
+	Nodes = RootNodes;
+
+	while (Nodes.Num() != 0)
+	{
+		if (CurrLEvel == Level)
+			break;
+
+		for (int i = 0; i < Nodes.Num(); ++i)
+		{
+			UGenericGraphNode* Node = Nodes[i];
+			check(Node != nullptr);
+
+			for (int j = 0; j < Node->ChildrenNodes.Num(); ++j)
+			{
+				NextLevelNodes.Add(Node->ChildrenNodes[j]);
+			}
+		}
+
+		Nodes = NextLevelNodes;
+		NextLevelNodes.Reset();
+		++CurrLEvel;
+	}
+}
+
+void UGenericGraph::ClearGraph()
+{
+	for (int i = 0; i < AllNodes.Num(); ++i)
+	{
+		UGenericGraphNode* Node = AllNodes[i];
+		if (Node)
+		{
+			Node->ParentNodes.Empty();
+			Node->ChildrenNodes.Empty();
+			Node->Edges.Empty();
+		}
+	}
+
+	AllNodes.Empty();
+	RootNodes.Empty();
+}
+
+#undef LOCTEXT_NAMESPACE
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Private/GenericGraphEdge.cpp b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Private/GenericGraphEdge.cpp
new file mode 100644
index 00000000..6d0118c7
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Private/GenericGraphEdge.cpp
@@ -0,0 +1,23 @@
+#include "GenericGraphEdge.h"
+
+UGenericGraphEdge::UGenericGraphEdge()
+{
+
+}
+
+UGenericGraphEdge::~UGenericGraphEdge()
+{
+
+}
+
+UGenericGraph* UGenericGraphEdge::GetGraph() const
+{
+	return Graph;
+}
+
+#if WITH_EDITOR
+void UGenericGraphEdge::SetNodeTitle(const FText& NewTitle)
+{
+	NodeTitle = NewTitle;
+}
+#endif // #if WITH_EDITOR
\ No newline at end of file
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Private/GenericGraphNode.cpp b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Private/GenericGraphNode.cpp
new file mode 100644
index 00000000..548cdc3b
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Private/GenericGraphNode.cpp
@@ -0,0 +1,90 @@
+#include "GenericGraphNode.h"
+#include "GenericGraph.h"
+
+#define LOCTEXT_NAMESPACE "GenericGraphNode"
+
+UGenericGraphNode::UGenericGraphNode()
+{
+#if WITH_EDITORONLY_DATA
+	CompatibleGraphType = UGenericGraph::StaticClass();
+
+	BackgroundColor = FLinearColor::Black;
+#endif
+}
+
+UGenericGraphNode::~UGenericGraphNode()
+{
+}
+
+UGenericGraphEdge* UGenericGraphNode::GetEdge(UGenericGraphNode* ChildNode)
+{
+	return Edges.Contains(ChildNode) ? Edges.FindChecked(ChildNode) : nullptr;
+}
+
+FText UGenericGraphNode::GetDescription_Implementation() const
+{
+	return LOCTEXT("NodeDesc", "Generic Graph Node");
+}
+
+#if WITH_EDITOR
+bool UGenericGraphNode::IsNameEditable() const
+{
+	return true;
+}
+
+FLinearColor UGenericGraphNode::GetBackgroundColor() const
+{
+	return BackgroundColor;
+}
+
+FText UGenericGraphNode::GetNodeTitle() const
+{
+	return NodeTitle.IsEmpty() ? GetDescription() : NodeTitle;
+}
+
+void UGenericGraphNode::SetNodeTitle(const FText& NewTitle)
+{
+	NodeTitle = NewTitle;
+}
+
+bool UGenericGraphNode::CanCreateConnection(UGenericGraphNode* Other, FText& ErrorMessage)
+{	
+	return true;
+}
+
+bool UGenericGraphNode::CanCreateConnectionTo(UGenericGraphNode* Other, int32 NumberOfChildrenNodes, FText& ErrorMessage)
+{
+	if (ChildrenLimitType == ENodeLimit::Limited && NumberOfChildrenNodes >= ChildrenLimit)
+	{
+		ErrorMessage = FText::FromString("Children limit exceeded");
+		return false;
+	}
+
+	return CanCreateConnection(Other, ErrorMessage);
+}
+
+bool UGenericGraphNode::CanCreateConnectionFrom(UGenericGraphNode* Other, int32 NumberOfParentNodes, FText& ErrorMessage)
+{
+	if (ParentLimitType == ENodeLimit::Limited && NumberOfParentNodes >= ParentLimit)
+	{
+		ErrorMessage = FText::FromString("Parent limit exceeded");
+		return false;
+	}
+
+	return true;
+}
+
+
+#endif
+
+bool UGenericGraphNode::IsLeafNode() const
+{
+	return ChildrenNodes.Num() == 0;
+}
+
+UGenericGraph* UGenericGraphNode::GetGraph() const
+{
+	return Graph;
+}
+
+#undef LOCTEXT_NAMESPACE
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Private/GenericGraphRuntime.cpp b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Private/GenericGraphRuntime.cpp
new file mode 100644
index 00000000..bfc33a53
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Private/GenericGraphRuntime.cpp
@@ -0,0 +1,29 @@
+#include "GenericGraphRuntimePCH.h"
+
+DEFINE_LOG_CATEGORY(GenericGraphRuntime)
+
+class FGenericGraphRuntime : public IGenericGraphRuntime
+{
+	/** IModuleInterface implementation */
+	virtual void StartupModule() override;
+	virtual void ShutdownModule() override;
+};
+
+IMPLEMENT_MODULE( FGenericGraphRuntime, GenericGraphRuntime )
+
+
+
+void FGenericGraphRuntime::StartupModule()
+{
+	// This code will execute after your module is loaded into memory (but after global variables are initialized, of course.)
+}
+
+
+void FGenericGraphRuntime::ShutdownModule()
+{
+	// This function may be called during shutdown to clean up your module.  For modules that support dynamic reloading,
+	// we call this function before unloading the module.
+}
+
+
+
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Private/GenericGraphRuntimePCH.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Private/GenericGraphRuntimePCH.h
new file mode 100644
index 00000000..18feed8f
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Private/GenericGraphRuntimePCH.h
@@ -0,0 +1,12 @@
+#pragma once
+
+// #include "CoreUObject.h"
+// #include "Engine.h"
+
+// You should place include statements to your module's private header files here.  You only need to
+// add includes for headers that are used in most of your module's source files though.
+#include "IGenericGraphRuntime.h"
+
+#define LOG_INFO(FMT, ...) UE_LOG(GenericGraphRuntime, Display, (FMT), ##__VA_ARGS__)
+#define LOG_WARNING(FMT, ...) UE_LOG(GenericGraphRuntime, Warning, (FMT), ##__VA_ARGS__)
+#define LOG_ERROR(FMT, ...) UE_LOG(GenericGraphRuntime, Error, (FMT), ##__VA_ARGS__)
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Public/GenericGraph.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Public/GenericGraph.h
new file mode 100644
index 00000000..1ac0d39d
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Public/GenericGraph.h
@@ -0,0 +1,60 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "GenericGraphNode.h"
+#include "GenericGraphEdge.h"
+#include "GameplayTagContainer.h"
+#include "GenericGraph.generated.h"
+
+UCLASS(Blueprintable)
+class GENERICGRAPHRUNTIME_API UGenericGraph : public UObject
+{
+	GENERATED_BODY()
+
+public:
+	UGenericGraph();
+	virtual ~UGenericGraph();
+
+	UPROPERTY(EditDefaultsOnly, Category = "GenericGraph")
+	FString Name;
+
+	UPROPERTY(EditDefaultsOnly, Category = "GenericGraph")
+	TSubclassOf<UGenericGraphNode> NodeType;
+
+	UPROPERTY(EditDefaultsOnly, Category = "GenericGraph")
+	TSubclassOf<UGenericGraphEdge> EdgeType;
+
+	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "GenericGraph")
+	FGameplayTagContainer GraphTags;
+
+	UPROPERTY(BlueprintReadOnly, Category = "GenericGraph")
+	TArray<UGenericGraphNode*> RootNodes;
+
+	UPROPERTY(BlueprintReadOnly, Category = "GenericGraph")
+	TArray<UGenericGraphNode*> AllNodes;
+
+	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "GenericGraph")
+	bool bEdgeEnabled;
+
+	UFUNCTION(BlueprintCallable, Category = "GenericGraph")
+	void Print(bool ToConsole = true, bool ToScreen = true);
+
+	UFUNCTION(BlueprintCallable, Category = "GenericGraph")
+	int GetLevelNum() const;
+
+	UFUNCTION(BlueprintCallable, Category = "GenericGraph")
+	void GetNodesByLevel(int Level, TArray<UGenericGraphNode*>& Nodes);
+
+	void ClearGraph();
+
+#if WITH_EDITORONLY_DATA
+	UPROPERTY()
+	class UEdGraph* EdGraph;
+
+	UPROPERTY(EditDefaultsOnly, Category = "GenericGraph_Editor")
+	bool bCanRenameNode;
+
+	UPROPERTY(EditDefaultsOnly, Category = "GenericGraph_Editor")
+	bool bCanBeCyclical;
+#endif
+};
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Public/GenericGraphEdge.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Public/GenericGraphEdge.h
new file mode 100644
index 00000000..3df297b4
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Public/GenericGraphEdge.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "GenericGraphNode.h"
+#include "GenericGraphEdge.generated.h"
+
+class UGenericGraph;
+
+UCLASS(Blueprintable)
+class GENERICGRAPHRUNTIME_API UGenericGraphEdge : public UObject
+{
+	GENERATED_BODY()
+
+public:
+	UGenericGraphEdge();
+	virtual ~UGenericGraphEdge();
+
+	UPROPERTY(VisibleAnywhere, Category = "GenericGraphNode")
+	UGenericGraph* Graph;
+
+	UPROPERTY(BlueprintReadOnly, Category = "GenericGraphEdge")
+	UGenericGraphNode* StartNode;
+
+	UPROPERTY(BlueprintReadOnly, Category = "GenericGraphEdge")
+	UGenericGraphNode* EndNode;
+
+	UFUNCTION(BlueprintPure, Category = "GenericGraphEdge")
+	UGenericGraph* GetGraph() const;
+
+#if WITH_EDITORONLY_DATA
+	UPROPERTY(EditDefaultsOnly, Category = "GenericGraphNode_Editor")
+	bool bShouldDrawTitle = false;
+
+	UPROPERTY(EditDefaultsOnly, Category = "GenericGraphNode_Editor")
+	FText NodeTitle;
+
+	UPROPERTY(EditDefaultsOnly, Category = "GenericGraphEdge")
+	FLinearColor EdgeColour = FLinearColor(0.9f, 0.9f, 0.9f, 1.0f);
+#endif
+
+#if WITH_EDITOR
+	virtual FText GetNodeTitle() const { return NodeTitle; }
+	FLinearColor GetEdgeColour() { return EdgeColour; }
+
+	virtual void SetNodeTitle(const FText& NewTitle);
+#endif
+	
+};
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Public/GenericGraphNode.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Public/GenericGraphNode.h
new file mode 100644
index 00000000..965d109e
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Public/GenericGraphNode.h
@@ -0,0 +1,94 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "Templates/SubclassOf.h"
+#include "GenericGraphNode.generated.h"
+
+class UGenericGraph;
+class UGenericGraphEdge;
+
+UENUM(BlueprintType)
+enum class ENodeLimit : uint8
+{
+	Unlimited,
+    Limited
+};
+
+
+UCLASS(Blueprintable)
+class GENERICGRAPHRUNTIME_API UGenericGraphNode : public UObject
+{
+	GENERATED_BODY()
+
+public:
+	UGenericGraphNode();
+	virtual ~UGenericGraphNode();
+
+	UPROPERTY(VisibleDefaultsOnly, Category = "GenericGraphNode")
+	UGenericGraph* Graph;
+
+	UPROPERTY(BlueprintReadOnly, Category = "GenericGraphNode")
+	TArray<UGenericGraphNode*> ParentNodes;
+
+	UPROPERTY(BlueprintReadOnly, Category = "GenericGraphNode")
+	TArray<UGenericGraphNode*> ChildrenNodes;
+
+	UPROPERTY(BlueprintReadOnly, Category = "GenericGraphNode")
+	TMap<UGenericGraphNode*, UGenericGraphEdge*> Edges;
+
+	UFUNCTION(BlueprintCallable, Category = "GenericGraphNode")
+	virtual UGenericGraphEdge* GetEdge(UGenericGraphNode* ChildNode);
+
+	UFUNCTION(BlueprintCallable, Category = "GenericGraphNode")
+	bool IsLeafNode() const;
+
+	UFUNCTION(BlueprintCallable, Category = "GenericGraphNode")
+	UGenericGraph* GetGraph() const;
+
+	UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "GenericGraphNode")
+	FText GetDescription() const;
+	virtual FText GetDescription_Implementation() const;
+
+	//////////////////////////////////////////////////////////////////////////
+#if WITH_EDITORONLY_DATA
+	UPROPERTY(EditDefaultsOnly, Category = "GenericGraphNode_Editor")
+	FText NodeTitle;
+
+	UPROPERTY(VisibleDefaultsOnly, Category = "GenericGraphNode_Editor")
+	TSubclassOf<UGenericGraph> CompatibleGraphType;
+
+	UPROPERTY(EditDefaultsOnly, Category = "GenericGraphNode_Editor")
+	FLinearColor BackgroundColor;
+
+	UPROPERTY(EditDefaultsOnly, Category = "GenericGraphNode_Editor")
+	FText ContextMenuName;
+
+	UPROPERTY(EditDefaultsOnly, Category = "GenericGraphNode_Editor")
+	ENodeLimit ParentLimitType;
+
+	UPROPERTY(EditDefaultsOnly, Category = "GenericGraphNode_Editor" ,meta = (ClampMin = "0",EditCondition = "ParentLimitType == ENodeLimit::Limited", EditConditionHides))
+	int32 ParentLimit;
+
+	UPROPERTY(EditDefaultsOnly, Category = "GenericGraphNode_Editor")
+	ENodeLimit ChildrenLimitType;
+
+	UPROPERTY(EditDefaultsOnly, Category = "GenericGraphNode_Editor" ,meta = (ClampMin = "0",EditCondition = "ChildrenLimitType == ENodeLimit::Limited", EditConditionHides))
+	int32 ChildrenLimit;
+	
+#endif
+
+#if WITH_EDITOR
+	virtual bool IsNameEditable() const;
+
+	virtual FLinearColor GetBackgroundColor() const;
+
+	virtual FText GetNodeTitle() const;
+
+	virtual void SetNodeTitle(const FText& NewTitle);
+
+	virtual bool CanCreateConnection(UGenericGraphNode* Other, FText& ErrorMessage);
+
+	virtual bool CanCreateConnectionTo(UGenericGraphNode* Other, int32 NumberOfChildrenNodes, FText& ErrorMessage);
+	virtual bool CanCreateConnectionFrom(UGenericGraphNode* Other, int32 NumberOfParentNodes, FText& ErrorMessage);
+#endif
+};
diff --git a/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Public/IGenericGraphRuntime.h b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Public/IGenericGraphRuntime.h
new file mode 100644
index 00000000..f978a2b6
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/Source/GenericGraphRuntime/Public/IGenericGraphRuntime.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include "Modules/ModuleManager.h"
+
+DECLARE_LOG_CATEGORY_EXTERN(GenericGraphRuntime, Log, All);
+
+/**
+ * The public interface to this module
+ */
+class IGenericGraphRuntime : public IModuleInterface
+{
+
+public:
+
+	/**
+	 * Singleton-like access to this module's interface.  This is just for convenience!
+	 * Beware of calling this during the shutdown phase, though.  Your module might have been unloaded already.
+	 *
+	 * @return Returns singleton instance, loading the module on demand if needed
+	 */
+	static IGenericGraphRuntime& Get()
+	{
+		return FModuleManager::LoadModuleChecked< IGenericGraphRuntime >("GenericGraphRuntime");
+	}
+
+	/**
+	 * Checks to see if this module is loaded and ready.  It is only valid to call Get() if IsAvailable() returns true.
+	 *
+	 * @return True if the module is loaded and ready to use
+	 */
+	static bool IsAvailable()
+	{
+		return FModuleManager::Get().IsModuleLoaded( "GenericGraphRuntime" );
+	}
+};
+
diff --git a/EndlessVendetta/Plugins/GenericGraph/docs/images/GenericGraph.png b/EndlessVendetta/Plugins/GenericGraph/docs/images/GenericGraph.png
new file mode 100644
index 00000000..0d899979
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/docs/images/GenericGraph.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:092185ad7a9989a69ba9543793326cf0f893fcc1a0895de65db3ca24ee7c970a
+size 89534
diff --git a/EndlessVendetta/Plugins/GenericGraph/docs/images/ability-graph.png b/EndlessVendetta/Plugins/GenericGraph/docs/images/ability-graph.png
new file mode 100644
index 00000000..b65adf2a
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/docs/images/ability-graph.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e97bb76a079e7e37c685cfa0f480c4028be755577939d8ae3d51be6e5571112c
+size 114519
diff --git a/EndlessVendetta/Plugins/GenericGraph/docs/images/dialogue/dialogue01.png b/EndlessVendetta/Plugins/GenericGraph/docs/images/dialogue/dialogue01.png
new file mode 100644
index 00000000..7fbb5326
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/docs/images/dialogue/dialogue01.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:95ab320c78c5ed1a79b78686a9e453bf459805b71ca6b855305f2ac328103d9e
+size 98959
diff --git a/EndlessVendetta/Plugins/GenericGraph/docs/images/dialogue/dialogue02.png b/EndlessVendetta/Plugins/GenericGraph/docs/images/dialogue/dialogue02.png
new file mode 100644
index 00000000..c03fde96
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/docs/images/dialogue/dialogue02.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:cbbb01dc0b5af841164b8baeeebfb5aa769cb0710482f6accd984d02e0586eb9
+size 94706
diff --git a/EndlessVendetta/Plugins/GenericGraph/docs/images/dialogue/dialogue03.png b/EndlessVendetta/Plugins/GenericGraph/docs/images/dialogue/dialogue03.png
new file mode 100644
index 00000000..ec53962e
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/docs/images/dialogue/dialogue03.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a51f6bd700c3346982c523d3c6e535cadb7ec8f0dc6c806bd5c481e961e8969c
+size 95655
diff --git a/EndlessVendetta/Plugins/GenericGraph/readme.rst b/EndlessVendetta/Plugins/GenericGraph/readme.rst
new file mode 100644
index 00000000..f76c40ba
--- /dev/null
+++ b/EndlessVendetta/Plugins/GenericGraph/readme.rst
@@ -0,0 +1,51 @@
+GenericGraphPlugin
+==================
+
+Generic graph data structure plugin for ue4
+
+.. image:: docs/images/GenericGraph.png
+
+Feature
+-------
+
+* Custom asset type
+* UE4 BehaviorTree-like asset editor
+* Extendable graph node type
+* Extendable graph edge type
+* Extendable graph type(new asset type with generic graph editor, C++ only)
+
+Usage
+-----
+
+* Ability system
+* Dialogue system
+* Quest system
+* Etc
+
+Install
+-------
+
+#. Clone this project to ${YourProject}/Plugins/
+#. Generate project file
+#. Compile
+
+Tutorial
+--------
+
+`Dialogue System`_ (WIP)
+
+Example
+-------
+
+Dialogue System and ability system: SRPGTemplate_
+
+.. image:: docs/images/dialogue/dialogue01.png
+
+.. image:: docs/images/dialogue/dialogue02.png
+
+.. image:: docs/images/dialogue/dialogue03.png
+
+.. image:: docs/images/ability-graph.png
+
+.. _Dialogue System: https://jinyuliao.github.io/blog/html/2017/12/15/ue4_dialogue_system_part1.html
+.. _SRPGTemplate: https://github.com/jinyuliao/SRPGTemplate