Adding custom properties.
diff --git a/Source/Actor.cpp b/Source/Actor.cpp
index d48191e..3b26234 100644
--- a/Source/Actor.cpp
+++ b/Source/Actor.cpp
@@ -3,6 +3,7 @@
 #include "ActorRootBone.hpp"
 #include "ActorIKTarget.hpp"
 #include "ActorEvent.hpp"
+#include "CustomProperty.hpp"
 #include "BinaryReader.hpp"
 #include "BlockReader.hpp"
 #include "Exceptions/OverflowException.hpp"
@@ -277,6 +278,15 @@
 			case BlockType::ActorEvent:
 				component = ActorEvent::read(this, componentBlock);
 				break;
+			case BlockType::CustomIntProperty:
+				component = CustomIntProperty::read(this, componentBlock);
+				break;
+			case BlockType::CustomFloatProperty:
+				component = CustomFloatProperty::read(this, componentBlock);
+				break;
+			case BlockType::CustomStringProperty:
+				component = CustomStringProperty::read(this, componentBlock);
+				break;
 			default:
 				// Not handled/expected block.
 				break;
diff --git a/Source/Actor.hpp b/Source/Actor.hpp
index dcd534d..1e728e6 100644
--- a/Source/Actor.hpp
+++ b/Source/Actor.hpp
@@ -24,9 +24,12 @@
 		Atlases = 9,
 		Atlas = 10,
 		ActorIKTarget = 11,
-		ActorEvent = 12
+		ActorEvent = 12,
+		CustomIntProperty = 13,
+		CustomFloatProperty = 14,
+		CustomStringProperty = 15
 	};
-	
+
 	class Actor
 	{
 		friend class ActorAnimationInstance;
diff --git a/Source/ActorComponent.cpp b/Source/ActorComponent.cpp
index 4a79b8c..096c3d5 100644
--- a/Source/ActorComponent.cpp
+++ b/Source/ActorComponent.cpp
@@ -1,5 +1,6 @@
 #include "ActorComponent.hpp"
 #include "ActorNode.hpp"
+#include "CustomProperty.hpp"
 #include "BlockReader.hpp"
 #include <algorithm>
 #include <cassert>
@@ -83,4 +84,55 @@
 	component->m_ParentIdx = reader->readUnsignedShort();
 
 	return component;
+}
+
+void ActorComponent::addCustomIntProperty(CustomIntProperty* property)
+{
+	m_CustomIntProperties.push_back(property);
+}
+
+void ActorComponent::addCustomFloatProperty(CustomFloatProperty* property)
+{
+	m_CustomFloatProperties.push_back(property);
+}
+
+void ActorComponent::addCustomStringProperty(CustomStringProperty* property)
+{
+	m_CustomStringProperties.push_back(property);
+}
+
+CustomIntProperty* ActorComponent::getCustomIntProperty(const std::string& name)
+{
+	for(CustomIntProperty* prop : m_CustomIntProperties)
+	{
+		if(prop->name() == name)
+		{
+			return prop;
+		}
+	}
+	return nullptr;
+}
+
+CustomFloatProperty* ActorComponent::getCustomFloatProperty(const std::string& name)
+{
+	for(CustomFloatProperty* prop : m_CustomFloatProperties)
+	{
+		if(prop->name() == name)
+		{
+			return prop;
+		}
+	}
+	return nullptr;
+}
+
+CustomStringProperty* ActorComponent::getCustomStringProperty(const std::string& name)
+{
+	for(CustomStringProperty* prop : m_CustomStringProperties)
+	{
+		if(prop->name() == name)
+		{
+			return prop;
+		}
+	}
+	return nullptr;
 }
\ No newline at end of file
diff --git a/Source/ActorComponent.hpp b/Source/ActorComponent.hpp
index 5786995..3e1c361 100644
--- a/Source/ActorComponent.hpp
+++ b/Source/ActorComponent.hpp
@@ -11,6 +11,9 @@
 	class Actor;
 	class ActorNode;
 	class BlockReader;
+	class CustomIntProperty;
+	class CustomFloatProperty;
+	class CustomStringProperty;
 
 	enum class ComponentType
 	{
@@ -19,7 +22,10 @@
 		ActorRootBone = 4,
 		ActorImage = 5,
 		ActorIKTarget = 11,
-		ActorEvent = 12
+		ActorEvent = 12,
+		CustomIntProperty = 13,
+		CustomFloatProperty = 14,
+		CustomStringProperty = 15
 	};
 
 
@@ -30,6 +36,9 @@
 			std::string m_Name;
 			ActorNode* m_Parent;
 			Actor* m_Actor;
+			std::vector<CustomIntProperty*> m_CustomIntProperties;
+			std::vector<CustomFloatProperty*> m_CustomFloatProperties;
+			std::vector<CustomStringProperty*> m_CustomStringProperties;
 
 		private:
 			unsigned short m_ParentIdx;
@@ -54,6 +63,14 @@
 			virtual bool isNode() { return false; }
 
 			static ActorComponent* read(Actor* actor, BlockReader* reader, ActorComponent* component = NULL);
+
+			void addCustomIntProperty(CustomIntProperty* property);
+			void addCustomFloatProperty(CustomFloatProperty* property);
+			void addCustomStringProperty(CustomStringProperty* property);
+
+			CustomIntProperty* getCustomIntProperty(const std::string& name);
+			CustomFloatProperty* getCustomFloatProperty(const std::string& name);
+			CustomStringProperty* getCustomStringProperty(const std::string& name);
 	};
 }
 #endif
\ No newline at end of file
diff --git a/Source/Animation/KeyFrames/KeyFrameCustomProperty.cpp b/Source/Animation/KeyFrames/KeyFrameCustomProperty.cpp
new file mode 100644
index 0000000..4f4e8eb
--- /dev/null
+++ b/Source/Animation/KeyFrames/KeyFrameCustomProperty.cpp
@@ -0,0 +1,44 @@
+#include "KeyFrameCustomProperty.hpp"
+#include "../../BlockReader.hpp"
+#include "../../CustomProperty.hpp"
+#include <cmath>
+
+using namespace nima;
+
+void KeyFrameIntProperty::setValue(ActorComponent* component, float value, float mix)
+{
+	CustomIntProperty* property = reinterpret_cast<CustomIntProperty*>(component);
+	property->value((int)round(property->value() * (1.0f - mix) + value * mix));
+}
+
+void KeyFrameFloatProperty::setValue(ActorComponent* component, float value, float mix)
+{
+	CustomFloatProperty* property = reinterpret_cast<CustomFloatProperty*>(component);
+	property->value(property->value() * (1.0f - mix) + value * mix);
+}
+
+bool KeyFrameStringProperty::read(BlockReader* reader, ActorComponent* component)
+{
+	if(!Base::read(reader, component))
+	{
+		return false;
+	}
+	m_Value = reader->readString();
+	return true;
+}
+
+void KeyFrameStringProperty::setNext(KeyFrame* frame)
+{
+	// Intentionally blank, we do not interpolate.
+}
+
+void KeyFrameStringProperty::apply(ActorComponent* component, float mix)
+{
+	CustomStringProperty* property = reinterpret_cast<CustomStringProperty*>(component);
+	property->value(m_Value);
+}
+
+void KeyFrameStringProperty::applyInterpolation(ActorComponent* component, float time, KeyFrame* toFrame, float mix)
+{
+	apply(component, mix);
+}
\ No newline at end of file
diff --git a/Source/Animation/KeyFrames/KeyFrameCustomProperty.hpp b/Source/Animation/KeyFrames/KeyFrameCustomProperty.hpp
new file mode 100644
index 0000000..62b1f0d
--- /dev/null
+++ b/Source/Animation/KeyFrames/KeyFrameCustomProperty.hpp
@@ -0,0 +1,37 @@
+#ifndef _NIMA_KEYFRAMEINTPROPERTY_HPP_
+#define _NIMA_KEYFRAMEINTPROPERTY_HPP_
+
+#include "KeyFrameNumeric.hpp"
+#include <string>
+
+namespace nima
+{
+	class ActorComponent;
+
+	class KeyFrameIntProperty : public KeyFrameInt
+	{
+		protected:
+			void setValue(ActorComponent* component, float value, float mix) override;
+	};
+
+	class KeyFrameFloatProperty : public KeyFrameNumeric
+	{
+		protected:
+			void setValue(ActorComponent* component, float value, float mix) override;
+	};
+
+	class KeyFrameStringProperty : public KeyFrame
+	{
+		typedef KeyFrame Base;
+		private:
+			std::string m_Value;
+
+		public:	
+			bool read(BlockReader* reader, ActorComponent* component) override;
+			void setNext(KeyFrame* frame) override;
+			void apply(ActorComponent* component, float mix) override;
+			void applyInterpolation(ActorComponent* component, float time, KeyFrame* toFrame, float mix) override;
+	};
+}
+
+#endif
\ No newline at end of file
diff --git a/Source/Animation/KeyFrames/KeyFrameNumeric.cpp b/Source/Animation/KeyFrames/KeyFrameNumeric.cpp
index 4b61513..e02b4e2 100644
--- a/Source/Animation/KeyFrames/KeyFrameNumeric.cpp
+++ b/Source/Animation/KeyFrames/KeyFrameNumeric.cpp
@@ -68,4 +68,70 @@
 			// Unhandled interpolation...
 			break;
 	}
+}
+
+KeyFrameInt::KeyFrameInt() : 
+	m_Value(0)
+{
+
+}
+
+int KeyFrameInt::value() const
+{
+	return m_Value;
+}
+
+bool KeyFrameInt::read(BlockReader* reader, ActorComponent* component)
+{
+	if(!Base::read(reader, component))
+	{
+		return false;
+	}
+
+	m_Value = reader->readInt();
+
+	return true;
+}
+
+void KeyFrameInt::apply(ActorComponent* component, float mix)
+{
+	this->setValue(component, m_Value, mix);
+}
+
+void KeyFrameInt::applyInterpolation(ActorComponent* component, float time, KeyFrame* toFrame, float mix)
+{
+	switch(m_InterpolationType)
+	{
+		case InterpolationType::Mirrored:
+		case InterpolationType::Asymmetric:
+		case InterpolationType::Disconnected:
+		{
+			ValueTimeCurveInterpolator* interpolator = reinterpret_cast<ValueTimeCurveInterpolator*>(m_Interpolator);
+			if(interpolator != nullptr)
+			{
+				float v = (float)interpolator->get((double)time);
+				setValue(component, v, mix);
+			}
+			break;
+		}
+
+		case InterpolationType::Hold:
+		{
+			setValue(component, m_Value, mix);
+			break;
+		}
+
+		case InterpolationType::Linear:
+		{
+			KeyFrameInt* to = reinterpret_cast<KeyFrameInt*>(toFrame);
+
+			float f = (time - m_Time)/(to->m_Time-m_Time);
+			setValue(component, m_Value * (1.0f-f) + to->m_Value * f, mix);
+			break;
+		}
+
+		default:
+			// Unhandled interpolation...
+			break;
+	}
 }
\ No newline at end of file
diff --git a/Source/Animation/KeyFrames/KeyFrameNumeric.hpp b/Source/Animation/KeyFrames/KeyFrameNumeric.hpp
index ee8d00a..a9f34cc 100644
--- a/Source/Animation/KeyFrames/KeyFrameNumeric.hpp
+++ b/Source/Animation/KeyFrames/KeyFrameNumeric.hpp
@@ -25,6 +25,24 @@
 		protected:
 			virtual void setValue(ActorComponent* component, float value, float mix) = 0;
 	};
+
+	class KeyFrameInt : public KeyFrameWithInterpolation
+	{
+		typedef KeyFrameWithInterpolation Base;
+		private:
+			int m_Value;
+
+		public:
+			KeyFrameInt();
+			int value() const;
+
+			bool read(BlockReader* reader, ActorComponent* component) override;
+			void apply(ActorComponent* component, float mix) override;
+			void applyInterpolation(ActorComponent* component, float time, KeyFrame* toFrame, float mix) override;
+			
+		protected:
+			virtual void setValue(ActorComponent* component, float value, float mix) = 0;
+	};
 }
 
 #endif
\ No newline at end of file
diff --git a/Source/Animation/PropertyAnimation.cpp b/Source/Animation/PropertyAnimation.cpp
index 36fa085..e91c9bb 100644
--- a/Source/Animation/PropertyAnimation.cpp
+++ b/Source/Animation/PropertyAnimation.cpp
@@ -12,6 +12,7 @@
 #include "KeyFrames/KeyFrameVertexDeform.hpp"
 #include "KeyFrames/KeyFrameIKStrength.hpp"
 #include "KeyFrames/KeyFrameTrigger.hpp"
+#include "KeyFrames/KeyFrameCustomProperty.hpp"
 #include <cassert> 
 
 using namespace nima;
@@ -98,6 +99,15 @@
 			case PropertyType::Trigger:
 				frame = new KeyFrameTrigger();
 				break;
+			case PropertyType::IntProperty:
+				frame = new KeyFrameIntProperty();
+				break;
+			case PropertyType::FloatProperty:
+				frame = new KeyFrameFloatProperty();
+				break;
+			case PropertyType::StringProperty:
+				frame = new KeyFrameStringProperty();
+				break;
 			default:
 				// This will only happen if the code isn't handling a property type it should handle.
 				// Check the PropertyType enum and make sure Max is in the right place (and that you're not missing a case).
diff --git a/Source/Animation/PropertyAnimation.hpp b/Source/Animation/PropertyAnimation.hpp
index 8062544..eb93fbf 100644
--- a/Source/Animation/PropertyAnimation.hpp
+++ b/Source/Animation/PropertyAnimation.hpp
@@ -22,6 +22,9 @@
 		VertexDeform = 9,
 		IKStrength = 10,
 		Trigger = 11,
+		IntProperty = 12,
+		FloatProperty = 13,
+		StringProperty = 14,
 		Max
 	};
 
diff --git a/Source/CustomProperty.cpp b/Source/CustomProperty.cpp
new file mode 100644
index 0000000..15e4bfe
--- /dev/null
+++ b/Source/CustomProperty.cpp
@@ -0,0 +1,153 @@
+#include "CustomProperty.hpp"
+#include "BlockReader.hpp"
+using namespace nima;
+
+
+CustomIntProperty::CustomIntProperty() : ActorComponent(ComponentType::CustomIntProperty), m_Value(0)
+{
+
+}
+
+ActorComponent* CustomIntProperty::makeInstance(Actor* resetActor)
+{
+	CustomIntProperty* instanceProp = new CustomIntProperty();
+	instanceProp->copy(this, resetActor);
+	return instanceProp;
+}
+
+void CustomIntProperty::copy(CustomIntProperty* property, Actor* resetActor)
+{
+	Base::copy(property, resetActor);
+	m_Value = property->m_Value;
+}
+
+CustomIntProperty* CustomIntProperty::read(Actor* actor, BlockReader* reader, CustomIntProperty* property)
+{
+	if(property == nullptr)
+	{
+		property = new CustomIntProperty();
+	}
+	ActorComponent::read(actor, reader, property);
+	property->m_Value = reader->readInt();
+	return property;
+}
+
+void CustomIntProperty::resolveComponentIndices(ActorComponent** components)
+{
+	Base::resolveComponentIndices(components);
+
+	ActorComponent* parent = components[parentIdx()];
+	if(parent != nullptr)
+	{
+		parent->addCustomIntProperty(this);
+	}
+}
+
+int CustomIntProperty::value() const
+{
+	return m_Value;
+}
+
+void CustomIntProperty::value(int v)
+{
+	m_Value = v;
+}
+
+CustomFloatProperty::CustomFloatProperty() : ActorComponent(ComponentType::CustomFloatProperty), m_Value(0.0f)
+{
+
+}
+
+ActorComponent* CustomFloatProperty::makeInstance(Actor* resetActor)
+{
+	CustomFloatProperty* instanceProp = new CustomFloatProperty();
+	instanceProp->copy(this, resetActor);
+	return instanceProp;
+}
+
+void CustomFloatProperty::copy(CustomFloatProperty* property, Actor* resetActor)
+{
+	Base::copy(property, resetActor);
+	m_Value = property->m_Value;
+}
+
+CustomFloatProperty* CustomFloatProperty::read(Actor* actor, BlockReader* reader, CustomFloatProperty* property)
+{
+	if(property == nullptr)
+	{
+		property = new CustomFloatProperty();
+	}
+	ActorComponent::read(actor, reader, property);
+	property->m_Value = reader->readFloat();
+	return property;
+}
+
+void CustomFloatProperty::resolveComponentIndices(ActorComponent** components)
+{
+	Base::resolveComponentIndices(components);
+	ActorComponent* parent = components[parentIdx()];
+	if(parent != nullptr)
+	{
+		parent->addCustomFloatProperty(this);
+	}
+}
+
+float CustomFloatProperty::value() const
+{
+	return m_Value;
+}
+
+void CustomFloatProperty::value(float v)
+{
+	m_Value = v;
+}
+
+CustomStringProperty::CustomStringProperty() : ActorComponent(ComponentType::CustomStringProperty)
+{
+
+}
+
+ActorComponent* CustomStringProperty::makeInstance(Actor* resetActor)
+{
+	CustomStringProperty* instanceProp = new CustomStringProperty();
+	instanceProp->copy(this, resetActor);
+	return instanceProp;
+}
+
+void CustomStringProperty::copy(CustomStringProperty* property, Actor* resetActor)
+{
+	Base::copy(property, resetActor);
+	m_Value = property->m_Value;
+}
+
+CustomStringProperty* CustomStringProperty::read(Actor* actor, BlockReader* reader, CustomStringProperty* property)
+{
+	if(property == nullptr)
+	{
+		property = new CustomStringProperty();
+	}
+	ActorComponent::read(actor, reader, property);
+	property->m_Value = reader->readString();
+	return property;
+}
+
+void CustomStringProperty::resolveComponentIndices(ActorComponent** components)
+{
+	Base::resolveComponentIndices(components);
+
+	ActorComponent* parent = components[parentIdx()];
+	if(parent != nullptr)
+	{
+		parent->addCustomStringProperty(this);
+	}
+}
+
+const std::string& CustomStringProperty::value() const
+{
+	return m_Value;
+}
+
+void CustomStringProperty::value(const std::string& v)
+{
+	m_Value = v;
+}
\ No newline at end of file
diff --git a/Source/CustomProperty.hpp b/Source/CustomProperty.hpp
new file mode 100644
index 0000000..8d5c0b5
--- /dev/null
+++ b/Source/CustomProperty.hpp
@@ -0,0 +1,59 @@
+#ifndef _NIMA_CUSTOMPROPERTY_HPP_
+#define _NIMA_CUSTOMPROPERTY_HPP_
+
+#include <string>
+#include "ActorComponent.hpp"
+
+namespace nima
+{
+	class CustomIntProperty : public ActorComponent
+	{
+		typedef ActorComponent Base;
+		private:
+			int m_Value;
+			
+		public:
+			CustomIntProperty();
+			ActorComponent* makeInstance(Actor* resetActor) override;
+			void copy(CustomIntProperty* property, Actor* resetActor);
+			static CustomIntProperty* read(Actor* actor, BlockReader* reader, CustomIntProperty* property = NULL);
+
+			void resolveComponentIndices(ActorComponent** components) override;
+			int value() const;
+			void value(int v);
+
+	};
+	class CustomFloatProperty : public ActorComponent
+	{
+		typedef ActorComponent Base;
+		private:
+			float m_Value;
+			
+		public:
+			CustomFloatProperty();
+			ActorComponent* makeInstance(Actor* resetActor) override;
+			void copy(CustomFloatProperty* property, Actor* resetActor);
+			static CustomFloatProperty* read(Actor* actor, BlockReader* reader, CustomFloatProperty* property = NULL);
+
+			void resolveComponentIndices(ActorComponent** components) override;
+			float value() const;
+			void value(float v);
+	};
+	class CustomStringProperty : public ActorComponent
+	{
+		typedef ActorComponent Base;
+		private:
+			std::string m_Value;
+			
+		public:
+			CustomStringProperty();
+			ActorComponent* makeInstance(Actor* resetActor) override;
+			void copy(CustomStringProperty* property, Actor* resetActor);
+			static CustomStringProperty* read(Actor* actor, BlockReader* reader, CustomStringProperty* property = NULL);
+
+			void resolveComponentIndices(ActorComponent** components) override;
+			const std::string& value() const;
+			void value(const std::string& v);
+	};
+}
+#endif
\ No newline at end of file