C_BaseEntity *ClientClassFactory( boost::python::object cls_type, int entnum, int serialNum )
{
	C_BaseEntity *pResult = NULL;

	try	
	{
		// Spawn and initialize the entity
		boost::python::object inst = cls_type();
		pResult = boost::python::extract<C_BaseEntity *>( inst );
		if( !pResult ) {
			Warning("Invalid client entity\n" );
			return NULL;
		}

		pResult->SetPyInstance( inst );
		pResult->Init( entnum, serialNum );
	}
	catch(boost::python::error_already_set &)
	{
		Warning( "Failed to create python client side entity, falling back to base c++ class\n" );
		PyErr_Print();
	}

	return pResult;
}
IClientNetworkable *ClientClassFactory( int iType, boost::python::object cls_type, int entnum, int serialNum )
{
	try	
	{
		// Safety check. The base implementations must be match, otherwise it can result in incorrect behavior (crashes)
		int iNetworkType = boost::python::extract<int>(cls_type.attr("GetPyNetworkType")());
		if( iNetworkType != iType )
		{
			char buf[512];
			Q_snprintf( buf, sizeof(buf), "Network type does not match client %d != server %d", iNetworkType, iType );
			PyErr_SetString(PyExc_Exception, buf );
			throw boost::python::error_already_set(); 
		}

		// Spawn and initialize the entity
		boost::python::object inst = cls_type();
		C_BaseEntity *pRet = boost::python::extract<C_BaseEntity *>(inst);
		if( !pRet ) {
			Warning("Invalid client entity\n" );
			return NULL;
		}

		pRet->SetPyInstance( inst );
		pRet->Init( entnum, serialNum );
		return pRet;
	}
	catch(boost::python::error_already_set &)
	{
		Warning("Failed to create python client side entity, falling back to base c++ class\n");
		PyErr_Print();
		PyErr_Clear();
		
		// Call the correct fallback factory
		IClientNetworkable *pResult = NULL;
		switch( iType )
		{
		case PN_BASEENTITY:
			pResult = CALL_FALLBACK_FACTORY( C_BaseEntity, entnum, serialNum );
			break;
		case PN_BASEANIMATING:
			pResult = CALL_FALLBACK_FACTORY( C_BaseAnimating, entnum, serialNum );
			break;
		case PN_BASEANIMATINGOVERLAY:
			pResult = CALL_FALLBACK_FACTORY( C_BaseAnimatingOverlay, entnum, serialNum );
			break;
		case PN_BASEFLEX:
			pResult = CALL_FALLBACK_FACTORY( C_BaseFlex, entnum, serialNum );
			break;
		case PN_BASECOMBATCHARACTER:
			pResult = CALL_FALLBACK_FACTORY( C_BaseCombatCharacter, entnum, serialNum );
			break;
		case PN_BASEPLAYER:
			pResult = CALL_FALLBACK_FACTORY( C_BasePlayer, entnum, serialNum );
			break;
		case PN_BASEPROJECTILE:
			pResult = CALL_FALLBACK_FACTORY( C_BaseProjectile, entnum, serialNum );
			break;
		case PN_BASEGRENADE:
			pResult = CALL_FALLBACK_FACTORY( C_BaseGrenade, entnum, serialNum );
			break;
		case PN_BASECOMBATWEAPON:
			pResult = CALL_FALLBACK_FACTORY( C_BaseCombatWeapon, entnum, serialNum );
			break;
		case PN_BREAKABLEPROP:
			pResult = CALL_FALLBACK_FACTORY( C_BreakableProp, entnum, serialNum );
			break;
		case PN_BASETOGGLE:
			pResult = CALL_FALLBACK_FACTORY( C_BaseToggle, entnum, serialNum );
			break;
		case PN_BASETRIGGER:
			pResult = CALL_FALLBACK_FACTORY( C_BaseTrigger, entnum, serialNum );
			break;
		case PN_UNITBASE:
			pResult = CALL_FALLBACK_FACTORY( C_UnitBase, entnum, serialNum );
			break;
		case PN_SPRITE:
			pResult = CALL_FALLBACK_FACTORY( C_Sprite, entnum, serialNum );
			break;
		case PN_BEAM:
			pResult = CALL_FALLBACK_FACTORY( C_Beam, entnum, serialNum );
			break;
		case PN_HL2WARSPLAYER:
			pResult = CALL_FALLBACK_FACTORY( C_HL2WarsPlayer, entnum, serialNum );
			break;
		case PN_WARSWEAPON:
			pResult = CALL_FALLBACK_FACTORY( C_WarsWeapon, entnum, serialNum );
			break;
		case PN_FUNCUNIT:
			pResult = CALL_FALLBACK_FACTORY( C_FuncUnit, entnum, serialNum );
			break;
		default:
			Warning( "No default fallback for networktype %d. Warn a dev.\n", iType );
			pResult = CALL_FALLBACK_FACTORY( C_BaseEntity, entnum, serialNum );
			break;
		}
		return pResult;
	}
}