diff --git a/r5dev/engine/host_state.cpp b/r5dev/engine/host_state.cpp
index b2496db6..56c2c27d 100644
--- a/r5dev/engine/host_state.cpp
+++ b/r5dev/engine/host_state.cpp
@@ -194,7 +194,7 @@ FORCEINLINE void CHostState::Setup(void)
 		NET_GenerateKey();
 	}
 	ResetLevelName();
-	KeyValues::Init();
+	KeyValues::Setup();
 }
 
 //-----------------------------------------------------------------------------
diff --git a/r5dev/vpc/keyvalues.cpp b/r5dev/vpc/keyvalues.cpp
index b49edfbe..0e7c12ed 100644
--- a/r5dev/vpc/keyvalues.cpp
+++ b/r5dev/vpc/keyvalues.cpp
@@ -6,32 +6,497 @@
 //=============================================================================//
 
 #include "core/stdafx.h"
+#include "tier1/strtools.h"
 #include "vpc/keyvalues.h"
+#include "vpc/kvleaktrace.h"
 #include "vstdlib/keyvaluessystem.h"
+#include "mathlib/color.h"
 #include "rtech/stryder/stryder.h"
 #include "engine/sys_dll2.h"
 
 //-----------------------------------------------------------------------------
-// Purpose: 
+// Purpose: Constructor
+// Input  : *pszSetName - 
+//-----------------------------------------------------------------------------
+KeyValues::KeyValues(const char* pszSetName)
+{
+	TRACK_KV_ADD(this, pszSetName);
+
+	Init();
+	SetName(pszSetName);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+// Input  : *pszSetName - 
+//			*pszFirstKey - 
+//			*pszFirstValue - 
+//-----------------------------------------------------------------------------
+KeyValues::KeyValues(const char* pszSsetName, const char* pszFirstKey, const char* pszFirstValue)
+{
+	TRACK_KV_ADD(this, pszSsetName);
+
+	Init();
+	SetName(pszSsetName);
+	SetString(pszFirstKey, pszFirstValue);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+// Input  : *pszSetName - 
+//			*pszFirstKey - 
+//			*pwszFirstValue - 
+//-----------------------------------------------------------------------------
+KeyValues::KeyValues(const char* pszSetName, const char* pszFirstKey, const wchar_t* pwszFirstValue)
+{
+	TRACK_KV_ADD(this, pszSetName);
+
+	Init();
+	SetName(pszSetName);
+	SetWString(pszFirstKey, pwszFirstValue);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+// Input  : *pszSetName - 
+//			*pszFirstKey - 
+//			iFirstValue - 
+//-----------------------------------------------------------------------------
+KeyValues::KeyValues(const char* pszSetName, const char* pszFirstKey, int iFirstValue)
+{
+	TRACK_KV_ADD(this, pszSetName);
+
+	Init();
+	SetName(pszSetName);
+	SetInt(pszFirstKey, iFirstValue);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+// Input  : *pszSetName - 
+//			*pszFirstKey - 
+//			*pszFirstValue - 
+//			*pszSecondKey - 
+//			*pszSecondValue - 
+//-----------------------------------------------------------------------------
+KeyValues::KeyValues(const char* pszSetName, const char* pszFirstKey, const char* pszFirstValue, const char* pszSecondKey, const char* pszSecondValue)
+{
+	TRACK_KV_ADD(this, pszSetName);
+
+	Init();
+	SetName(pszSetName);
+	SetString(pszFirstKey, pszFirstValue);
+	SetString(pszSecondKey, pszSecondValue);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+// Input  : *pszSetName - 
+//			*pszFirstKey - 
+//			iFirstValue - 
+//			*pszSecondKey - 
+//			iSecondValue - 
+//-----------------------------------------------------------------------------
+KeyValues::KeyValues(const char* pszSetName, const char* pszFirstKey, int iFirstValue, const char* pszSecondKey, int iSecondValue)
+{
+	TRACK_KV_ADD(this, pszSetName);
+
+	Init();
+	SetName(pszSetName);
+	SetInt(pszFirstKey, iFirstValue);
+	SetInt(pszSecondKey, iSecondValue);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+KeyValues::~KeyValues(void)
+{
+	TRACK_KV_REMOVE(this);
+
+	RemoveEverything();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Initialize member variables
 //-----------------------------------------------------------------------------
 void KeyValues::Init(void)
 {
-	std::thread t1(KeyValues::InitPlaylists); // Start thread to grab playlists.
-	t1.detach(); // Detach thread from current one.
+	m_iKeyName = 0;
+	m_iKeyNameCaseSensitive1 = 0;
+	m_iKeyNameCaseSensitive2 = 0;
+	m_iDataType = TYPE_NONE;
+
+	m_pSub = nullptr;
+	m_pPeer = nullptr;
+	m_pChain = nullptr;
+
+	m_sValue = nullptr;
+	m_wsValue = nullptr;
+	m_pValue = nullptr;
+
+	m_bHasEscapeSequences = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Clear out all subkeys, and the current value
+//-----------------------------------------------------------------------------
+void KeyValues::Clear(void)
+{
+	delete m_pSub;
+	m_pSub = nullptr;
+	m_iDataType = TYPE_NONE;
+}
+
+//-----------------------------------------------------------------------------
+// for backwards compat - we used to need this to force the free to run from the same DLL
+// as the alloc
+//-----------------------------------------------------------------------------
+void KeyValues::DeleteThis(void)
+{
+	delete this;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: remove everything
+//-----------------------------------------------------------------------------
+void KeyValues::RemoveEverything(void)
+{
+	KeyValues* dat;
+	KeyValues* datNext = nullptr;
+	for (dat = m_pSub; dat != nullptr; dat = datNext)
+	{
+		datNext = dat->m_pPeer;
+		dat->m_pPeer = nullptr;
+		delete dat;
+	}
+
+	for (dat = m_pPeer; dat && dat != this; dat = datNext)
+	{
+		datNext = dat->m_pPeer;
+		dat->m_pPeer = nullptr;
+		delete dat;
+	}
+
+	delete[] m_sValue;
+	m_sValue = nullptr;
+	delete[] m_wsValue;
+	m_wsValue = nullptr;
 }
 
 //-----------------------------------------------------------------------------
 // Purpose: Find a keyValue, create it if it is not found.
 //			Set bCreate to true to create the key if it doesn't already exist 
 //			(which ensures a valid pointer will be returned)
-// Input  : *pKeyName - 
+// Input  : *pszKeyName - 
 //			bCreate - 
 // Output : *KeyValues
 //-----------------------------------------------------------------------------
-KeyValues* KeyValues::FindKey(const char* keyName, bool bCreate)
+KeyValues* KeyValues::FindKey(const char* pszKeyName, bool bCreate)
 {
 	static auto func = reinterpret_cast<KeyValues * (__thiscall*)(KeyValues*, const char*, bool)>(KeyValues_FindKey);
-	return func(this, keyName, bCreate);
+	return func(this, pszKeyName, bCreate);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Locate last child.  Returns NULL if we have no children
+// Output : *KeyValues
+//-----------------------------------------------------------------------------
+KeyValues* KeyValues::FindLastSubKey(void) const
+{
+	// No children?
+	if (m_pSub == nullptr)
+		return nullptr;
+
+	// Scan for the last one
+	KeyValues* pLastChild = m_pSub;
+	while (pLastChild->m_pPeer)
+		pLastChild = pLastChild->m_pPeer;
+	return pLastChild;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Adds a subkey. Make sure the subkey isn't a child of some other keyvalues
+// Input  : *pSubKey - 
+//-----------------------------------------------------------------------------
+void KeyValues::AddSubKey(KeyValues* pSubkey)
+{
+	// Make sure the subkey isn't a child of some other keyvalues
+	Assert(pSubkey != nullptr);
+	Assert(pSubkey->m_pPeer == nullptr);
+
+	// add into subkey list
+	if (m_pSub == nullptr)
+	{
+		m_pSub = pSubkey;
+	}
+	else
+	{
+		KeyValues* pTempDat = m_pSub;
+		while (pTempDat->GetNextKey() != nullptr)
+		{
+			pTempDat = pTempDat->GetNextKey();
+		}
+
+		pTempDat->SetNextKey(pSubkey);
+	}
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove a subkey from the list
+// Input  : *pSubKey - 
+//-----------------------------------------------------------------------------
+void KeyValues::RemoveSubKey(KeyValues* pSubKey)
+{
+	if (!pSubKey)
+		return;
+
+	// check the list pointer
+	if (m_pSub == pSubKey)
+	{
+		m_pSub = pSubKey->m_pPeer;
+	}
+	else
+	{
+		// look through the list
+		KeyValues* kv = m_pSub;
+		while (kv->m_pPeer)
+		{
+			if (kv->m_pPeer == pSubKey)
+			{
+				kv->m_pPeer = pSubKey->m_pPeer;
+				break;
+			}
+
+			kv = kv->m_pPeer;
+		}
+	}
+
+	pSubKey->m_pPeer = nullptr;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Insert a subkey at index
+// Input  : nIndex - 
+//			*pSubKey - 
+//-----------------------------------------------------------------------------
+void KeyValues::InsertSubKey(int nIndex, KeyValues* pSubKey)
+{
+	// Sub key must be valid and not part of another chain
+	Assert(pSubKey && pSubKey->m_pPeer == nullptr);
+
+	if (nIndex == 0)
+	{
+		pSubKey->m_pPeer = m_pSub;
+		m_pSub = pSubKey;
+		return;
+	}
+	else
+	{
+		int nCurrentIndex = 0;
+		for (KeyValues* pIter = GetFirstSubKey(); pIter != nullptr; pIter = pIter->GetNextKey())
+		{
+			++nCurrentIndex;
+			if (nCurrentIndex == nIndex)
+			{
+				pSubKey->m_pPeer = pIter->m_pPeer;
+				pIter->m_pPeer = pSubKey;
+				return;
+			}
+		}
+		// Index is out of range if we get here
+		Assert(0);
+		return;
+	}
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Checks if key contains a subkey
+// Input  : *pSubKey - 
+// Output : true if contains, false otherwise
+//-----------------------------------------------------------------------------
+bool KeyValues::ContainsSubKey(KeyValues* pSubKey)
+{
+	for (KeyValues* pIter = GetFirstSubKey(); pIter != nullptr; pIter = pIter->GetNextKey())
+	{
+		if (pSubKey == pIter)
+		{
+			return true;
+		}
+	}
+	return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Swaps existing subkey with another
+// Input  : *pExistingSubkey - 
+//			*pNewSubKey - 
+//-----------------------------------------------------------------------------
+void KeyValues::SwapSubKey(KeyValues* pExistingSubkey, KeyValues* pNewSubKey)
+{
+	Assert(pExistingSubkey != nullptr && pNewSubKey != nullptr);
+
+	// Make sure the new sub key isn't a child of some other keyvalues
+	Assert(pNewSubKey->m_pPeer == nullptr);
+
+	// Check the list pointer
+	if (m_pSub == pExistingSubkey)
+	{
+		pNewSubKey->m_pPeer = pExistingSubkey->m_pPeer;
+		pExistingSubkey->m_pPeer = nullptr;
+		m_pSub = pNewSubKey;
+	}
+	else
+	{
+		// Look through the list
+		KeyValues* kv = m_pSub;
+		while (kv->m_pPeer)
+		{
+			if (kv->m_pPeer == pExistingSubkey)
+			{
+				pNewSubKey->m_pPeer = pExistingSubkey->m_pPeer;
+				pExistingSubkey->m_pPeer = nullptr;
+				kv->m_pPeer = pNewSubKey;
+				break;
+			}
+
+			kv = kv->m_pPeer;
+		}
+		// Existing sub key should always be found, otherwise it's a bug in the calling code.
+		Assert(kv->m_pPeer != nullptr);
+	}
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Elides subkey
+// Input  : *pSubKey - 
+//-----------------------------------------------------------------------------
+void KeyValues::ElideSubKey(KeyValues* pSubKey)
+{
+	// This pointer's "next" pointer needs to be fixed up when we elide the key
+	KeyValues** ppPointerToFix = &m_pSub;
+	for (KeyValues* pKeyIter = m_pSub; pKeyIter != nullptr; ppPointerToFix = &pKeyIter->m_pPeer, pKeyIter = pKeyIter->GetNextKey())
+	{
+		if (pKeyIter == pSubKey)
+		{
+			if (pSubKey->m_pSub == nullptr)
+			{
+				// No children, simply remove the key
+				*ppPointerToFix = pSubKey->m_pPeer;
+				delete pSubKey;
+			}
+			else
+			{
+				*ppPointerToFix = pSubKey->m_pSub;
+				// Attach the remainder of this chain to the last child of pSubKey
+				KeyValues* pChildIter = pSubKey->m_pSub;
+				while (pChildIter->m_pPeer != nullptr)
+				{
+					pChildIter = pChildIter->m_pPeer;
+				}
+				// Now points to the last child of pSubKey
+				pChildIter->m_pPeer = pSubKey->m_pPeer;
+				// Detach the node to be elided
+				pSubKey->m_pSub = nullptr;
+				pSubKey->m_pPeer = nullptr;
+				delete pSubKey;
+			}
+			return;
+		}
+	}
+	// Key not found; that's caller error.
+	Assert(0);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Check if a keyName has no value assigned to it.
+// Input  : *pszKeyName - 
+// Output : true on success, false otherwise
+//-----------------------------------------------------------------------------
+bool KeyValues::IsEmpty(const char* pszKeyName)
+{
+	KeyValues* pKey = FindKey(pszKeyName, false);
+	if (!pKey)
+		return true;
+
+	if (pKey->m_iDataType == TYPE_NONE && pKey->m_pSub == nullptr)
+		return true;
+
+	return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: gets the first true sub key
+// Output : *KeyValues
+//-----------------------------------------------------------------------------
+KeyValues* KeyValues::GetFirstTrueSubKey(void) const
+{
+	Assert(this, "Member function called on NULL KeyValues");
+	KeyValues* pRet = this ? m_pSub : nullptr;
+	while (pRet && pRet->m_iDataType != TYPE_NONE)
+		pRet = pRet->m_pPeer;
+
+	return pRet;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: gets the next true sub key
+// Output : *KeyValues
+//-----------------------------------------------------------------------------
+KeyValues* KeyValues::GetNextTrueSubKey(void) const
+{
+	Assert(this, "Member function called on NULL KeyValues");
+	KeyValues* pRet = this ? m_pPeer : nullptr;
+	while (pRet && pRet->m_iDataType != TYPE_NONE)
+		pRet = pRet->m_pPeer;
+
+	return pRet;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: gets the first value
+// Output : *KeyValues
+//-----------------------------------------------------------------------------
+KeyValues* KeyValues::GetFirstValue(void) const
+{
+	Assert(this, "Member function called on NULL KeyValues");
+	KeyValues* pRet = this ? m_pSub : nullptr;
+	while (pRet && pRet->m_iDataType == TYPE_NONE)
+		pRet = pRet->m_pPeer;
+
+	return pRet;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: gets the next value
+// Output : *KeyValues
+//-----------------------------------------------------------------------------
+KeyValues* KeyValues::GetNextValue(void) const
+{
+	Assert(this, "Member function called on NULL KeyValues");
+	KeyValues* pRet = this ? m_pPeer : nullptr;
+	while (pRet && pRet->m_iDataType == TYPE_NONE)
+		pRet = pRet->m_pPeer;
+
+	return pRet;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return the first subkey in the list
+//-----------------------------------------------------------------------------
+KeyValues* KeyValues::GetFirstSubKey() const
+{
+	Assert(this, "Member function called on NULL KeyValues");
+	return this ? m_pSub : nullptr;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return the next subkey
+//-----------------------------------------------------------------------------
+KeyValues* KeyValues::GetNextKey() const
+{
+	Assert(this, "Member function called on NULL KeyValues");
+	return this ? m_pPeer : nullptr;
 }
 
 //-----------------------------------------------------------------------------
@@ -40,70 +505,724 @@ KeyValues* KeyValues::FindKey(const char* keyName, bool bCreate)
 //-----------------------------------------------------------------------------
 const char* KeyValues::GetName(void) const
 {
-	return g_pKeyValuesSystem->GetStringForSymbol(MAKE_3_BYTES_FROM_1_AND_2(m_iKeyNameCaseSensitive, m_iKeyNameCaseSensitive2));
+	return KeyValuesSystem()->GetStringForSymbol(MAKE_3_BYTES_FROM_1_AND_2(m_iKeyNameCaseSensitive1, m_iKeyNameCaseSensitive2));
 }
 
 //-----------------------------------------------------------------------------
 // Purpose: Get the integer value of a keyName. Default value is returned
 //			if the keyName can't be found.
-// Input  : *pKeyName - 
+// Input  : *pszKeyName - 
 //			nDefaultValue - 
 // Output : int
 //-----------------------------------------------------------------------------
-int KeyValues::GetInt(const char* pKeyName, int nDefaultValue)
+int KeyValues::GetInt(const char* pszKeyName, int iDefaultValue)
 {
-	KeyValues* dat = FindKey(pKeyName, false);
-
-	if (!dat)
-		return nDefaultValue;
-
-	switch (dat->m_iDataType)
+	KeyValues* pKey = FindKey(pszKeyName, false);
+	if (pKey)
 	{
-	case TYPE_STRING:
-		return atoi(dat->m_sValue);
-	case TYPE_FLOAT:
-		return static_cast<int>(m_flValue);
-	case TYPE_WSTRING:
-		return _wtoi(dat->m_wsValue);
-	case TYPE_UINT64:
-		return 0;
-	default:
-		return dat->m_iValue;
+		switch (pKey->m_iDataType)
+		{
+		case TYPE_STRING:
+			return atoi(pKey->m_sValue);
+		case TYPE_WSTRING:
+			return _wtoi(pKey->m_wsValue);
+		case TYPE_FLOAT:
+			return static_cast<int>(pKey->m_flValue);
+		case TYPE_UINT64:
+			// can't convert, since it would lose data
+			Assert(0);
+			return 0;
+		case TYPE_INT:
+		case TYPE_PTR:
+		default:
+			return pKey->m_iValue;
+		};
 	}
+	return iDefaultValue;
+}
 
+//-----------------------------------------------------------------------------
+// Purpose: Get the integer value of a keyName. Default value is returned
+//			if the keyName can't be found.
+// Input  : *pszKeyName - 
+//			nDefaultValue - 
+// Output : uint64_t
+//-----------------------------------------------------------------------------
+uint64_t KeyValues::GetUint64(const char* pszKeyName, uint64_t nDefaultValue)
+{
+	KeyValues* pKey = FindKey(pszKeyName, false);
+	if (pKey)
+	{
+		switch (pKey->m_iDataType)
+		{
+		case TYPE_STRING:
+		{
+			uint64_t uiResult = 0ull;
+			sscanf(pKey->m_sValue, "%lld", &uiResult);
+			return uiResult;
+		}
+		case TYPE_WSTRING:
+		{
+			uint64_t uiResult = 0ull;
+			swscanf(pKey->m_wsValue, L"%lld", &uiResult);
+			return uiResult;
+		}
+		case TYPE_FLOAT:
+			return static_cast<int>(pKey->m_flValue);
+		case TYPE_UINT64:
+			return *reinterpret_cast<uint64_t*>(pKey->m_sValue);
+		case TYPE_PTR:
+			return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(pKey->m_pValue));
+		case TYPE_INT:
+		default:
+			return pKey->m_iValue;
+		};
+	}
 	return nDefaultValue;
 }
 
+//-----------------------------------------------------------------------------
+// Purpose: Get the pointer value of a keyName. Default value is returned
+//			if the keyName can't be found.
+// Input  : *pszKeyName - 
+//			pDefaultValue - 
+// Output : void*
+//-----------------------------------------------------------------------------
+void* KeyValues::GetPtr(const char* pszKeyName, void* pDefaultValue)
+{
+	KeyValues* pKey = FindKey(pszKeyName, false);
+	if (pKey)
+	{
+		switch (pKey->m_iDataType)
+		{
+		case TYPE_PTR:
+			return pKey->m_pValue;
+
+		case TYPE_WSTRING:
+		case TYPE_STRING:
+		case TYPE_FLOAT:
+		case TYPE_INT:
+		case TYPE_UINT64:
+		default:
+			return nullptr;
+		};
+	}
+	return pDefaultValue;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the float value of a keyName. Default value is returned
+//			if the keyName can't be found.
+// Input  : *pszKeyName - 
+//			flDefaultValue - 
+// Output : float
+//-----------------------------------------------------------------------------
+float KeyValues::GetFloat(const char* pszKeyName, float flDefaultValue)
+{
+	KeyValues* pKey = FindKey(pszKeyName, false);
+	if (pKey)
+	{
+		switch (pKey->m_iDataType)
+		{
+		case TYPE_STRING:
+			return static_cast<float>(atof(pKey->m_sValue));
+		case TYPE_WSTRING:
+			return static_cast<float>(_wtof(pKey->m_wsValue));		// no wtof
+		case TYPE_FLOAT:
+			return pKey->m_flValue;
+		case TYPE_INT:
+			return static_cast<float>(pKey->m_iValue);
+		case TYPE_UINT64:
+			return static_cast<float>((*(reinterpret_cast<uint64*>(pKey->m_sValue))));
+		case TYPE_PTR:
+		default:
+			return 0.0f;
+		};
+	}
+	return flDefaultValue;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the string pointer of a keyName. Default value is returned
+//			if the keyName can't be found.
+// // Input  : *pszKeyName - 
+//			pszDefaultValue - 
+// Output : const char*
+//-----------------------------------------------------------------------------
+const char* KeyValues::GetString(const char* pszKeyName, const char* pszDefaultValue)
+{
+	KeyValues* pKey = FindKey(pszKeyName, false);
+	if (pKey)
+	{
+		// convert the data to string form then return it
+		char buf[64];
+		switch (pKey->m_iDataType)
+		{
+		case TYPE_FLOAT:
+			snprintf(buf, sizeof(buf), "%f", pKey->m_flValue);
+			SetString(pszKeyName, buf);
+			break;
+		case TYPE_PTR:
+			snprintf(buf, sizeof(buf), "%lld", CastPtrToInt64(pKey->m_pValue));
+			SetString(pszKeyName, buf);
+			break;
+		case TYPE_INT:
+			snprintf(buf, sizeof(buf), "%d", pKey->m_iValue);
+			SetString(pszKeyName, buf);
+			break;
+		case TYPE_UINT64:
+			snprintf(buf, sizeof(buf), "%lld", *(reinterpret_cast<uint64*>(pKey->m_sValue)));
+			SetString(pszKeyName, buf);
+			break;
+		case TYPE_COLOR:
+			snprintf(buf, sizeof(buf), "%d %d %d %d", pKey->m_Color[0], pKey->m_Color[1], pKey->m_Color[2], pKey->m_Color[3]);
+			SetString(pszKeyName, buf);
+			break;
+
+		case TYPE_WSTRING:
+		{
+			// convert the string to char *, set it for future use, and return it
+			char wideBuf[512];
+			int result = V_UnicodeToUTF8(pKey->m_wsValue, wideBuf, 512);
+			if (result)
+			{
+				// note: this will copy wideBuf
+				SetString(pszKeyName, wideBuf);
+			}
+			else
+			{
+				return pszDefaultValue;
+			}
+			break;
+		}
+		case TYPE_STRING:
+			break;
+		default:
+			return pszDefaultValue;
+		};
+
+		return pKey->m_sValue;
+	}
+	return pszDefaultValue;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the wide string pointer of a keyName. Default value is returned
+//			if the keyName can't be found.
+// // Input  : *pszKeyName - 
+//			pwszDefaultValue - 
+// Output : const wchar_t*
+//-----------------------------------------------------------------------------
+const wchar_t* KeyValues::GetWString(const char* pszKeyName, const wchar_t* pwszDefaultValue)
+{
+	KeyValues* pKey = FindKey(pszKeyName, false);
+	if (pKey)
+	{
+		wchar_t wbuf[64];
+		switch (pKey->m_iDataType)
+		{
+		case TYPE_FLOAT:
+			swprintf(wbuf, Q_ARRAYSIZE(wbuf), L"%f", pKey->m_flValue);
+			SetWString(pszKeyName, wbuf);
+			break;
+		case TYPE_PTR:
+			swprintf(wbuf, Q_ARRAYSIZE(wbuf), L"%lld", static_cast<int64_t>(reinterpret_cast<size_t>(pKey->m_pValue)));
+			SetWString(pszKeyName, wbuf);
+			break;
+		case TYPE_INT:
+			swprintf(wbuf, Q_ARRAYSIZE(wbuf), L"%d", pKey->m_iValue);
+			SetWString(pszKeyName, wbuf);
+			break;
+		case TYPE_UINT64:
+		{
+			swprintf(wbuf, Q_ARRAYSIZE(wbuf), L"%lld", *(reinterpret_cast<uint64_t*>(pKey->m_sValue)));
+			SetWString(pszKeyName, wbuf);
+		}
+		break;
+		case TYPE_COLOR:
+			swprintf(wbuf, Q_ARRAYSIZE(wbuf), L"%d %d %d %d", pKey->m_Color[0], pKey->m_Color[1], pKey->m_Color[2], pKey->m_Color[3]);
+			SetWString(pszKeyName, wbuf);
+			break;
+
+		case TYPE_WSTRING:
+			break;
+		case TYPE_STRING:
+		{
+			size_t bufSize = strlen(pKey->m_sValue) + 1;
+			wchar_t* pWBuf = new wchar_t[bufSize];
+			int result = V_UTF8ToUnicode(pKey->m_sValue, pWBuf, static_cast<int>(bufSize * sizeof(wchar_t)));
+			if (result >= 0) // may be a zero length string
+			{
+				SetWString(pszKeyName, pWBuf);
+			}
+			else
+			{
+				delete[] pWBuf;
+				return pwszDefaultValue;
+			}
+			delete[] pWBuf;
+			break;
+		}
+		default:
+			return pwszDefaultValue;
+		};
+
+		return reinterpret_cast<const wchar_t*>(pKey->m_wsValue);
+	}
+	return pwszDefaultValue;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Gets a color
+// Input  : *pszKeyName - 
+//			&defaultColor - 
+// Output : Color
+//-----------------------------------------------------------------------------
+Color KeyValues::GetColor(const char* pszKeyName, const Color& defaultColor)
+{
+	Color color = defaultColor;
+	KeyValues* pKey = FindKey(pszKeyName, false);
+	if (pKey)
+	{
+		if (pKey->m_iDataType == TYPE_COLOR)
+		{
+			color[0] = pKey->m_Color[0];
+			color[1] = pKey->m_Color[1];
+			color[2] = pKey->m_Color[2];
+			color[3] = pKey->m_Color[3];
+		}
+		else if (pKey->m_iDataType == TYPE_FLOAT)
+		{
+			color[0] = static_cast<unsigned char>(pKey->m_flValue);
+		}
+		else if (pKey->m_iDataType == TYPE_INT)
+		{
+			color[0] = static_cast<unsigned char>(pKey->m_iValue);
+		}
+		else if (pKey->m_iDataType == TYPE_STRING)
+		{
+			// parse the colors out of the string
+			float a = 0, b = 0, c = 0, d = 0;
+			sscanf(pKey->m_sValue, "%f %f %f %f", &a, &b, &c, &d);
+			color[0] = static_cast<unsigned char>(a);
+			color[1] = static_cast<unsigned char>(b);
+			color[2] = static_cast<unsigned char>(c);
+			color[3] = static_cast<unsigned char>(d);
+		}
+	}
+	return color;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the data type of the value stored in a keyName
+// Input  : *pszKeyName - 
+//-----------------------------------------------------------------------------
+KeyValuesTypes_t KeyValues::GetDataType(const char* pszKeyName)
+{
+	KeyValues* pKey = FindKey(pszKeyName, false);
+	if (pKey)
+		return static_cast<KeyValuesTypes_t>(pKey->m_iDataType);
+
+	return TYPE_NONE;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the data type of the value stored in this keyName
+//-----------------------------------------------------------------------------
+KeyValuesTypes_t KeyValues::GetDataType(void) const
+{
+	return static_cast<KeyValuesTypes_t>(m_iDataType);
+}
+
 //-----------------------------------------------------------------------------
 // Purpose: Set the integer value of a keyName. 
-// Input  : *pKeyName - 
+// Input  : *pszKeyName - 
 //			iValue - 
 //-----------------------------------------------------------------------------
-void KeyValues::SetInt(const char* pKeyName, int iValue)
+void KeyValues::SetInt(const char* pszKeyName, int iValue)
 {
-	KeyValues* dat = FindKey(pKeyName, true);
-	if (dat)
+	KeyValues* pKey = FindKey(pszKeyName, true);
+	if (pKey)
 	{
-		dat->m_iValue = iValue;
-		dat->m_iDataType = TYPE_INT;
+		pKey->m_iValue = iValue;
+		pKey->m_iDataType = TYPE_INT;
+	}
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set the integer value of a keyName. 
+//-----------------------------------------------------------------------------
+void KeyValues::SetUint64(const char* pszKeyName, uint64_t nValue)
+{
+	KeyValues* pKey = FindKey(pszKeyName, true);
+
+	if (pKey)
+	{
+		// delete the old value
+		delete[] pKey->m_sValue;
+		// make sure we're not storing the WSTRING  - as we're converting over to STRING
+		delete[] pKey->m_wsValue;
+		pKey->m_wsValue = nullptr;
+
+		pKey->m_sValue = new char[sizeof(uint64_t)];
+		*(reinterpret_cast<uint64_t*>(pKey->m_sValue)) = nValue;
+		pKey->m_iDataType = TYPE_UINT64;
 	}
 }
 
 //-----------------------------------------------------------------------------
 // Purpose: Set the float value of a keyName. 
-// Input  : *pKeyName - 
+// Input  : *pszKeyName - 
 //			flValue - 
 //-----------------------------------------------------------------------------
-void KeyValues::SetFloat(const char* pKeyName, float flValue)
+void KeyValues::SetFloat(const char* pszKeyName, float flValue)
 {
-	KeyValues* dat = FindKey(pKeyName, true);
-	if (dat)
+	KeyValues* pKey = FindKey(pszKeyName, true);
+	if (pKey)
 	{
-		dat->m_flValue = flValue;
-		dat->m_iDataType = TYPE_FLOAT;
+		pKey->m_flValue = flValue;
+		pKey->m_iDataType = TYPE_FLOAT;
 	}
 }
 
+//-----------------------------------------------------------------------------
+// Purpose: Set the name value of a keyName. 
+// Input  : *pszSetName - 
+//-----------------------------------------------------------------------------
+void KeyValues::SetName(const char* pszSetName)
+{
+	HKeySymbol hCaseSensitiveKeyName = INVALID_KEY_SYMBOL, hCaseInsensitiveKeyName = INVALID_KEY_SYMBOL;
+	hCaseSensitiveKeyName = KeyValuesSystem()->GetSymbolForStringCaseSensitive(hCaseInsensitiveKeyName, pszSetName);
+
+	m_iKeyName = hCaseInsensitiveKeyName;
+	SPLIT_3_BYTES_INTO_1_AND_2(m_iKeyNameCaseSensitive1, m_iKeyNameCaseSensitive2, hCaseSensitiveKeyName);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set the pointer value of a keyName. 
+// Input  : *pszKeyName - 
+//			*pValue - 
+//-----------------------------------------------------------------------------
+void KeyValues::SetPtr(const char* pszKeyName, void* pValue)
+{
+	KeyValues* pKey = FindKey(pszKeyName, true);
+
+	if (pKey)
+	{
+		pKey->m_pValue = pValue;
+		pKey->m_iDataType = TYPE_PTR;
+	}
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set the string value (internal)
+// Input  : *pszValue - 
+//-----------------------------------------------------------------------------
+void KeyValues::SetStringValue(char const* pszValue)
+{
+	// delete the old value
+	delete[] m_sValue;
+	// make sure we're not storing the WSTRING  - as we're converting over to STRING
+	delete[] m_wsValue;
+	m_wsValue = nullptr;
+
+	if (!pszValue)
+	{
+		// ensure a valid value
+		pszValue = "";
+	}
+
+	// allocate memory for the new value and copy it in
+	size_t len = strlen(pszValue);
+	m_sValue = new char[len + 1];
+	memcpy(m_sValue, pszValue, len + 1);
+
+	m_iDataType = TYPE_STRING;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets this key's peer to the KeyValues passed in
+// Input  : *pDat - 
+//-----------------------------------------------------------------------------
+void KeyValues::SetNextKey(KeyValues* pDat)
+{
+	m_pPeer = pDat;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set the string value of a keyName. 
+// Input  : *pszKeyName - 
+//			*pszValue - 
+//-----------------------------------------------------------------------------
+void KeyValues::SetString(const char* pszKeyName, const char* pszValue)
+{
+	if (KeyValues* pKey = FindKey(pszKeyName, true))
+	{
+		pKey->SetStringValue(pszValue);
+	}
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set the string value of a keyName. 
+// Input  : *pszKeyName - 
+//			*pwszValue - 
+//-----------------------------------------------------------------------------
+void KeyValues::SetWString(const char* pszKeyName, const wchar_t* pwszValue)
+{
+	KeyValues* pKey = FindKey(pszKeyName, true);
+	if (pKey)
+	{
+		// delete the old value
+		delete[] pKey->m_wsValue;
+		// make sure we're not storing the STRING  - as we're converting over to WSTRING
+		delete[] pKey->m_sValue;
+		pKey->m_sValue = nullptr;
+
+		if (!pwszValue)
+		{
+			// ensure a valid value
+			pwszValue = L"";
+		}
+
+		// allocate memory for the new value and copy it in
+		size_t len = wcslen(pwszValue);
+		pKey->m_wsValue = new wchar_t[len + 1];
+		memcpy(pKey->m_wsValue, pwszValue, (len + 1) * sizeof(wchar_t));
+
+		pKey->m_iDataType = TYPE_WSTRING;
+	}
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets a color
+// Input  : *pszKeyName - 
+//			color - 
+//-----------------------------------------------------------------------------
+void KeyValues::SetColor(const char* pszKeyName, Color color)
+{
+	KeyValues* pKey = FindKey(pszKeyName, true);
+
+	if (pKey)
+	{
+		pKey->m_iDataType = TYPE_COLOR;
+		pKey->m_Color[0] = color[0];
+		pKey->m_Color[1] = color[1];
+		pKey->m_Color[2] = color[2];
+		pKey->m_Color[3] = color[3];
+	}
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: 
+// Input  : &src - 
+//-----------------------------------------------------------------------------
+void KeyValues::RecursiveCopyKeyValues(KeyValues& src)
+{
+	// garymcthack - need to check this code for possible buffer overruns.
+
+	m_iKeyName = src.m_iKeyName;
+	m_iKeyNameCaseSensitive1 = src.m_iKeyNameCaseSensitive1;
+	m_iKeyNameCaseSensitive2 = src.m_iKeyNameCaseSensitive2;
+
+	if (!src.m_pSub)
+	{
+		m_iDataType = src.m_iDataType;
+		char buf[256];
+		switch (src.m_iDataType)
+		{
+		case TYPE_NONE:
+			break;
+		case TYPE_STRING:
+			if (src.m_sValue)
+			{
+				size_t len = strlen(src.m_sValue) + 1;
+				m_sValue = new char[len];
+				strncpy(m_sValue, src.m_sValue, len);
+			}
+			break;
+		case TYPE_INT:
+		{
+			m_iValue = src.m_iValue;
+			snprintf(buf, sizeof(buf), "%d", m_iValue);
+			size_t len = strlen(buf) + 1;
+			m_sValue = new char[len];
+			strncpy(m_sValue, buf, len);
+		}
+		break;
+		case TYPE_FLOAT:
+		{
+			m_flValue = src.m_flValue;
+			snprintf(buf, sizeof(buf), "%f", m_flValue);
+			size_t len = strlen(buf) + 1;
+			m_sValue = new char[len];
+			strncpy(m_sValue, buf, len);
+		}
+		break;
+		case TYPE_PTR:
+		{
+			m_pValue = src.m_pValue;
+		}
+		break;
+		case TYPE_UINT64:
+		{
+			m_sValue = new char[sizeof(uint64_t)];
+			memcpy(m_sValue, src.m_sValue, sizeof(uint64_t));
+		}
+		break;
+		case TYPE_COLOR:
+		{
+			m_Color[0] = src.m_Color[0];
+			m_Color[1] = src.m_Color[1];
+			m_Color[2] = src.m_Color[2];
+			m_Color[3] = src.m_Color[3];
+		}
+		break;
+
+		default:
+		{
+			// do nothing . .what the heck is this?
+			Assert(0);
+		}
+		break;
+		}
+
+	}
+#if 0
+	KeyValues* pDst = this;
+	for (KeyValues* pSrc = src.m_pSub; pSrc; pSrc = pSrc->m_pPeer)
+	{
+		if (pSrc->m_pSub)
+		{
+			pDst->m_pSub = new KeyValues(pSrc->m_pSub->getName());
+			pDst->m_pSub->RecursiveCopyKeyValues(*pSrc->m_pSub);
+		}
+		else
+		{
+			// copy non-empty keys
+			if (pSrc->m_sValue && *(pSrc->m_sValue))
+			{
+				pDst->m_pPeer = new KeyValues(
+			}
+		}
+	}
+#endif
+
+	// Handle the immediate child
+	if (src.m_pSub)
+	{
+		m_pSub = new KeyValues(nullptr);
+		m_pSub->RecursiveCopyKeyValues(*src.m_pSub);
+	}
+
+	// Handle the immediate peer
+	if (src.m_pPeer)
+	{
+		m_pPeer = new KeyValues(nullptr);
+		m_pPeer->RecursiveCopyKeyValues(*src.m_pPeer);
+	}
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Make a new copy of all subkeys, add them all to the passed-in keyvalues
+// Input  : *pParent - 
+//-----------------------------------------------------------------------------
+void KeyValues::CopySubkeys(KeyValues* pParent) const
+{
+	// recursively copy subkeys
+	// Also maintain ordering....
+	KeyValues* pPrev = nullptr;
+	for (KeyValues* pSub = m_pSub; pSub != nullptr; pSub = pSub->m_pPeer)
+	{
+		// take a copy of the subkey
+		KeyValues* pKey = pSub->MakeCopy();
+
+		// add into subkey list
+		if (pPrev)
+		{
+			pPrev->m_pPeer = pKey;
+		}
+		else
+		{
+			pParent->m_pSub = pKey;
+		}
+		pKey->m_pPeer = nullptr;
+		pPrev = pKey;
+	}
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Makes a copy of the whole key-value pair set
+// Output : KeyValues*
+//-----------------------------------------------------------------------------
+KeyValues* KeyValues::MakeCopy(void) const
+{
+	KeyValues* pNewKeyValue = new KeyValues(GetName());
+
+	// copy data
+	pNewKeyValue->m_iDataType = m_iDataType;
+	switch (m_iDataType)
+	{
+	case TYPE_STRING:
+	{
+		if (m_sValue)
+		{
+			size_t len = strlen(m_sValue);
+			Assert(!pNewKeyValue->m_sValue);
+			pNewKeyValue->m_sValue = new char[len + 1];
+			memcpy(pNewKeyValue->m_sValue, m_sValue, len + 1);
+		}
+	}
+	break;
+	case TYPE_WSTRING:
+	{
+		if (m_wsValue)
+		{
+			size_t len = wcslen(m_wsValue);
+			pNewKeyValue->m_wsValue = new wchar_t[len + 1];
+			memcpy(pNewKeyValue->m_wsValue, m_wsValue, len + 1 * sizeof(wchar_t));
+		}
+	}
+	break;
+
+	case TYPE_INT:
+		pNewKeyValue->m_iValue = m_iValue;
+		break;
+
+	case TYPE_FLOAT:
+		pNewKeyValue->m_flValue = m_flValue;
+		break;
+
+	case TYPE_PTR:
+		pNewKeyValue->m_pValue = m_pValue;
+		break;
+
+	case TYPE_COLOR:
+		pNewKeyValue->m_Color[0] = m_Color[0];
+		pNewKeyValue->m_Color[1] = m_Color[1];
+		pNewKeyValue->m_Color[2] = m_Color[2];
+		pNewKeyValue->m_Color[3] = m_Color[3];
+		break;
+
+	case TYPE_UINT64:
+		pNewKeyValue->m_sValue = new char[sizeof(uint64_t)];
+		memcpy(pNewKeyValue->m_sValue, m_sValue, sizeof(uint64_t));
+		break;
+	};
+
+	// recursively copy subkeys
+	CopySubkeys(pNewKeyValue);
+	return pNewKeyValue;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: 
+//-----------------------------------------------------------------------------
+void KeyValues::Setup(void)
+{
+	std::thread t1(KeyValues::InitPlaylists); // Start thread to grab playlists.
+	t1.detach(); // Detach thread from current one.
+}
+
 //-----------------------------------------------------------------------------
 // Purpose: Initializes the playlist
 //-----------------------------------------------------------------------------
@@ -117,12 +1236,10 @@ void KeyValues::InitPlaylists(void)
 			if (pPlaylists)
 			{
 				g_vAllPlaylists.clear();
-				for (KeyValues* dat = pPlaylists->m_pSub; dat != nullptr; dat = dat->m_pPeer) // Parse through all sub keys.
+				for (KeyValues* pSubKey = pPlaylists->GetFirstTrueSubKey(); pSubKey != nullptr; pSubKey = pSubKey->GetNextTrueSubKey())
 				{
-					printf("%s\n", dat->GetName());
-					g_vAllPlaylists.push_back(dat->GetName()); // Get all playlists.
+					g_vAllPlaylists.push_back(pSubKey->GetName()); // Get all playlists.
 				}
-
 				break; // Break if playlist got filled.
 			}
 			std::this_thread::sleep_for(std::chrono::milliseconds(50));
@@ -145,14 +1262,14 @@ void KeyValues::InitFileSystem(void)
 			KeyValues* pSearchPaths = pFileSystemInfo->FindKey("SearchPaths", false);
 			if (pSearchPaths)
 			{
-				g_vAllSearchPaths.clear();
-				for (KeyValues* dat = pSearchPaths->m_pSub; dat != nullptr; dat = dat->m_pPeer) // Parse through all sub keys.
+				g_vGameInfoPaths.clear();
+				for (KeyValues* pSubKey = pSearchPaths->GetFirstValue(); pSubKey != nullptr; pSubKey = pSubKey->GetNextValue())
 				{
-					string svValue = dat->m_sValue;
+					string svValue = pSubKey->GetString();
 					StringReplace(svValue, GAMEINFOPATH_TOKEN, "");
 					StringReplace(svValue, BASESOURCEPATHS_TOKEN, "");
 
-					g_vAllSearchPaths.push_back(svValue); // Get all SearchPaths
+					g_vGameInfoPaths.push_back(svValue); // Get all SearchPaths
 				}
 			}
 		}
@@ -224,5 +1341,5 @@ void CKeyValueSystem_Detach()
 
 ///////////////////////////////////////////////////////////////////////////////
 inline KeyValues** g_pPlaylistKeyValues = nullptr; // Get the KeyValue for the playlist file.
-vector<string> g_vAllPlaylists   = { "<<null>>" };
-vector<string> g_vAllSearchPaths = { "\\" };
\ No newline at end of file
+vector<string> g_vAllPlaylists          = { "<<null>>" };
+vector<string> g_vGameInfoPaths         = { "\\" };
\ No newline at end of file
diff --git a/r5dev/vpc/keyvalues.h b/r5dev/vpc/keyvalues.h
index 757da62d..e5dbe3bd 100644
--- a/r5dev/vpc/keyvalues.h
+++ b/r5dev/vpc/keyvalues.h
@@ -1,9 +1,12 @@
 #pragma once
 #include "filesystem/filesystem.h"
+#include "mathlib/color.h"
 
 #define MAKE_3_BYTES_FROM_1_AND_2( x1, x2 ) (( (( uint16_t )x2) << 8 ) | (uint8_t)(x1))
+#define SPLIT_3_BYTES_INTO_1_AND_2( x1, x2, x3 ) do { x1 = (uint8)(x3); x2 = (uint16)( (x3) >> 8 ); } while( 0 )
+
 extern vector<string> g_vAllPlaylists;
-extern vector<string> g_vAllSearchPaths;
+extern vector<string> g_vGameInfoPaths;
 
 //---------------------------------------------------------------------------------
 // Purpose: Forward declarations
@@ -26,7 +29,7 @@ inline auto KeyValues_GetCurrentPlaylist = p_KeyValues_GetCurrentPlaylist.RCast<
 inline CMemory p_KeyValues_ReadKeyValuesFile;
 inline auto KeyValues_ReadKeyValuesFile = p_KeyValues_ReadKeyValuesFile.RCast<KeyValues* (*)(CFileSystem_Stdio* pFileSystem, const char* pFileName)>();
 
-enum KeyValuesTypes
+enum KeyValuesTypes_t : char
 {
 	TYPE_NONE              = 0x0,
 	TYPE_STRING            = 0x1,
@@ -41,36 +44,120 @@ enum KeyValuesTypes
 	TYPE_COMPILED_INT_1    = 0xA,
 	TYPE_NUMTYPES          = 0xB,
 };
+enum MergeKeyValuesOp_t
+{
+	MERGE_KV_ALL,
+	MERGE_KV_UPDATE,	// update values are copied into storage, adding new keys to storage or updating existing ones
+	MERGE_KV_DELETE,	// update values specify keys that get deleted from storage
+	MERGE_KV_BORROW,	// update values only update existing keys in storage, keys in update that do not exist in storage are discarded
+};
 
+
+//-----------------------------------------------------------------------------
+// Purpose: Simple recursive data access class
+//			Used in vgui for message parameters and resource files
+//			Destructor deletes all child KeyValues nodes
+//			Data is stored in key (string names) - (string/int/float)value pairs called nodes.
+//
+//	About KeyValues Text File Format:
+
+//	It has 3 control characters '{', '}' and '"'. Names and values may be quoted or
+//	not. The quote '"' character must not be used within name or values, only for
+//	quoting whole tokens. You may use escape sequences wile parsing and add within a
+//	quoted token a \" to add quotes within your name or token. When using Escape
+//	Sequence the parser must now that by setting KeyValues::UsesEscapeSequences( true ),
+//	which it's off by default. Non-quoted tokens ends with a whitespace, '{', '}' and '"'.
+//	So you may use '{' and '}' within quoted tokens, but not for non-quoted tokens.
+//  An open bracket '{' after a key name indicates a list of subkeys which is finished
+//  with a closing bracket '}'. Subkeys use the same definitions recursively.
+//  Whitespaces are space, return, newline and tabulator. Allowed Escape sequences
+//	are \n, \t, \\, \n and \". The number character '#' is used for macro purposes 
+//	(eg #include), don't use it as first character in key names.
+//-----------------------------------------------------------------------------
 class KeyValues
 {
 public:
-	static void Init(void);
-	KeyValues* FindKey(const char* pKeyName, bool bCreate);
-	const char* GetName(void) const;
-	int GetInt(const char* pKeyName, int nDefaultValue);
-	void SetInt(const char* pKeyName, int iValue);
-	void SetFloat(const char* keyName, float flValue);
+	// Constructors/destructors
+	KeyValues(const char* pszSetName);
+	KeyValues(const char* pszSetName, const char* pszFirstKey, const char* pszFirstValue);
+	KeyValues(const char* pszSetName, const char* pszFirstKey, const wchar_t* pwszFirstValue);
+	KeyValues(const char* pszSetName, const char* pszFirstKey, int iFirstValue);
+	KeyValues(const char* pszSetName, const char* pszFirstKey, const char* pszFirstValue, const char* pszSecondKey, const char* pszSecondValue);
+	KeyValues(const char* pszSetName, const char* pszFirstKey, int iFirstValue, const char* pszSecondKey, int iSecondValue);
+	~KeyValues(void);
 
+	void Init(void);
+	void Clear(void);
+	void DeleteThis(void);
+	void RemoveEverything();
+
+	KeyValues* FindKey(const char* pKeyName, bool bCreate = false);
+	KeyValues* FindLastSubKey(void) const;
+
+	void AddSubKey(KeyValues* pSubkey);
+	void RemoveSubKey(KeyValues* pSubKey);
+	void InsertSubKey(int nIndex, KeyValues* pSubKey);
+	bool ContainsSubKey(KeyValues* pSubKey);
+	void SwapSubKey(KeyValues* pExistingSubkey, KeyValues* pNewSubKey);
+	void ElideSubKey(KeyValues* pSubKey);
+
+	// Data access
+	bool IsEmpty(const char* pszKeyName);
+	KeyValues* GetFirstTrueSubKey(void) const;
+	KeyValues* GetNextTrueSubKey(void) const;
+	KeyValues* GetFirstValue(void) const;
+	KeyValues* GetNextValue(void) const;
+	KeyValues* GetFirstSubKey() const;
+	KeyValues* GetNextKey() const;
+	const char* GetName(void) const;
+	int GetInt(const char* pszKeyName, int iDefaultValue);
+	uint64_t GetUint64(const char* pszKeyName, uint64_t nDefaultValue);
+	void* GetPtr(const char* pszKeyName, void* pDefaultValue);
+	float GetFloat(const char* pszKeyName, float flDefaultValue);
+	const char* GetString(const char* pszKeyName = nullptr, const char* pszDefaultValue = "");
+	const wchar_t* GetWString(const char* pszKeyName = nullptr, const wchar_t* pwszDefaultValue = L"");
+	Color GetColor(const char* pszKeyName, const Color& defaultColor);
+	KeyValuesTypes_t GetDataType(const char* pszKeyName);
+	KeyValuesTypes_t GetDataType(void) const;
+
+	// Key writing
+	void SetInt(const char* pszKeyName, int iValue);
+	void SetUint64(const char* pszKeyName, uint64_t nValue);
+	void SetPtr(const char* pszKeyName, void* pValue);
+	void SetNextKey(KeyValues* pDat);
+	void SetName(const char* pszName);
+	void SetString(const char* pszKeyName, const char* pszValue);
+	void SetWString(const char* pszKeyName, const wchar_t* pwszValue);
+	void SetStringValue(char const* pszValue);
+	void SetColor(const char* pszKeyName, Color color);
+	void SetFloat(const char* pszKeyName, float flValue);
+
+	void RecursiveCopyKeyValues(KeyValues& src);
+	void CopySubkeys(KeyValues* pParent) const;
+	KeyValues* MakeCopy(void) const;
+
+	// Initialization
+	static void Setup(void);
 	static void InitPlaylists(void);
 	static void InitFileSystem(void);
 	static bool LoadPlaylist(const char* szPlaylist);
 	static KeyValues* ReadKeyValuesFile(CFileSystem_Stdio* pFileSystem, const char* pFileName);
 
 public:
-	uint32_t m_iKeyName              : 24;         // 0x0000
-	uint32_t m_iKeyNameCaseSensitive : 8;          // 0x0003
+	uint32_t m_iKeyName               : 24;        // 0x0000
+	uint32_t m_iKeyNameCaseSensitive1 : 8;         // 0x0003
 	char*            m_sValue;                     // 0x0008
 	wchar_t*         m_wsValue;                    // 0x0010
 	union                                          // 0x0018
 	{
-		int m_iValue;
-		float m_flValue;
-		void* m_pValue;
+		int           m_iValue;
+		float         m_flValue;
+		void*         m_pValue;
 		unsigned char m_Color[4];
 	};
 	char             m_szShortName[8];             // 0x0020
 	char             m_iDataType;                  // 0x0028
+	char             m_bHasEscapeSequences;        // 0x0029
 	uint16_t         m_iKeyNameCaseSensitive2;     // 0x002A
 	KeyValues*       m_pPeer;                      // 0x0030
 	KeyValues*       m_pSub;                       // 0x0038
diff --git a/r5dev/vpc/kvleaktrace.h b/r5dev/vpc/kvleaktrace.h
index 8ea3c8df..7e4ab83e 100644
--- a/r5dev/vpc/kvleaktrace.h
+++ b/r5dev/vpc/kvleaktrace.h
@@ -1,6 +1,6 @@
 #ifndef KVLEAKTRACE_H
 #define KVLEAKTRACE_H
-#include "tier1/utlvector.h"
+//#include "tier1/utlvector.h"
 
 #ifdef LEAKTRACK
 class CLeakTrack