Find C4D's directory without C4D



  • Hello PluginCafe :)

    I'm writing a standalone application which will be used for installing my C4D plugins.
    I need to find an appropriate way of finding plugins directory.

    Currently, I'm using a simple expression to define the preferences folder.
    Then I'm iterating through each file in the preferences folder and then creating plugins directory with os module.

    here is the code.

    import os
    from getpass import getuser as user
    
    def plugins_path(release_number):
        if os.name == 'nt': MAXON = r"C:\Users\{}\AppData\Roaming\MAXON".format(user()) #Windows
        if os.name != 'nt': MAXON = r"/Users/{}/Library/Preferences/MAXON".format(user()) #OSX
    
        plugins_path = ""
        for i in os.listdir(MAXON):
            if release_number.upper() in i.upper(): plugins_path = os.path.join(MAXON, i, "plugins")
    
        if os.path.exists(plugins_path): return plugins_path
    
    user_input = "R20"
    print(plugins_path(user_input))
    

    The problem is that some users are installing C4D in a custom directory and my code is very limited for this task.

    Is it possible to find an exact directory of C4D's plugins folder?



  • Hi @merkvilson thanks for reaching us,

    Here is a script to retrieves the Cinema 4D preference folder of a specific installation stored in temp folder working from R17 to R20.

    """
    Copyright: MAXON Computer GmbH
    Author: Maxime Adam
    
    Description:
        - Retrieves the path of the preference folder according to an installation path without the need to launch Cinema 4D.
    
    Note:
        - From Cinema 4D c4d.storage.GeGetC4DPath(c4d.C4D_PATH_STARTUPWRITE) can be called to retrieves the current installation path.
    
    Compatible:
        - Win / Mac
        - R17, R18, R19, R20
    """
    import os
    import platform
    
    
    def CRC(rawString):
        # Performs CRC 32 BIT on the input byte
        crc = 0xffffffff
    
        crc32tab_o32 = [
            0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb,
            0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24,
            0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b, 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384,
            0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b,
            0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35,
            0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa,
            0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a,
            0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595,
            0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957,
            0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198,
            0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38,
            0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7,
            0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789,
            0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46,
            0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6,
            0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829,
            0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93,
            0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c,
            0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc,
            0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033,
            0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d,
            0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982,
            0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622,
            0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed,
            0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f,
            0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0,
            0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540,
            0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f,
            0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1,
            0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e,
            0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e,
            0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351]
    
        for s in rawString:
            k = ord(s)
            crc = crc32tab_o32[(crc & 0xff) ^ (k & 0xff)] ^ (crc >> 8)
            k >>= 8
            crc = crc32tab_o32[(crc & 0xff) ^ (k & 0xff)] ^ (crc >> 8)
            k >>= 8
            crc = crc32tab_o32[(crc & 0xff) ^ (k & 0xff)] ^ (crc >> 8)
            k >>= 8
            crc = crc32tab_o32[(crc & 0xff) ^ (k & 0xff)] ^ (crc >> 8)
    
        return format(crc ^ 0xffffffff, 'x').upper()
    
    
    def GetTempFolder(instalDir):
        # Retrieves the temp folder
        tempFolder = None
        if platform.system() == "Windows":
            tempFolder = os.getenv('APPDATA')
        elif platform.system() == "Darwin":
            libPath = os.path.expanduser('~/Library')
            tempFolder = os.path.join(libPath, "Preferences")
    
        if not os.path.exists(tempFolder) or tempFolder is None:
            raise RuntimeError("Failed to retrieves appdata folder.")
    
        # Cleanups the input path
        instalDir = os.path.normpath(instalDir)
        instalDir = instalDir.replace('\\\\', '\\')
        parentDirLower = instalDir.lower()
    
        # Retrieves only the name of the last folder
        parentName = os.path.split(instalDir)[1]
        if not parentName:
            raise RuntimeError("Failed to retrieves parent Name folder")
    
        parentName = parentName.replace(':', '_')
    
        # Computes the crc of the dir in lowercase.
        crc = CRC(parentDirLower)
    
        # Builds the final path
        finalPath = os.path.join(tempFolder, "MAXON", parentName + "_" + crc)
    
        return finalPath
    
    
    def main():
        # Path must be in unicode, it can be retrieved from c4d with c4d.storage.GeGetStartupPath()
        winInstallationPath = unicode("C:\Program Files\MAXON\Cinema 4D R20")
        macInstallationPath = unicode("/Users/m_adam/Application/MAXON/Cinema 4D R20")
        print "Path:", GetTempFolder(winInstallationPath)
    
    
    if __name__ == '__main__':
        main()
    

    As a side note in R20 plugins can be installed everywhere as long as the path is set in the preferences.
    And finally, there is no reliable way to know where Cinema 4D is installed from outside of Cinema 4D.

    If you have any question, please let me know.
    Cheers,
    Maxime.



  • Thanks, Maxime!

    Can you tell me about Copyright and EULA? How can I use this code in my software?



  • @merkvilson, sorry this code is planned to be part of our github, so like any of our examples, they are under the Apache License.

    For more information see Apache License from our Github repository.
    Cheers,
    Maxime.



  • Thanks, Maxime! :)

    I tested the code, and it works.
    But this is not what I exactly wanted.

    As I mentioned, the problem is that some users are installing C4D in a custom directory and I can't find preferences path nor an actual installation path.

    I also tried os.walk() Method to find MAXON directory, but it has two significant problems.

    1. It's too slow
    2. there are several folders called MAXON

    The only thing that users can define is the release number, and I have to find it according to the string, for example, "R20".

    Here is how the installer works.

    alt text

    It works on most of the computers but some users already reported that it can't find their directory so they are forced to manually define it but most of them are defining global directory. If you remember, I had to remove symbolcache file and this is one of the reasons why I made this installer.



  • Unfortunately, Cinema 4D does not track this, and there is no way to know it currently since Cinema 4D is almost a portable application (you can copy/paste Cinema 4D folder to anywhere as long as dependencies have been installed once it will work).

    In any case, it's a request we already made to our development team, I'll push the topic again and will see 😉.
    Cheers,
    Maxime.



  • Thanks, Maxime! This script is still quite useful.
    Is it possible to use it in order to find C4D executable on Windows as well as on mac?

    Let's assume the directory is C:\Program Files\MAXON\Cinema 4D R20\ which contains several exe. How to define which one is the Cinema 4D itself?

    I tried this way but I guess there should be a better option

    
    def MAXON_P():
        if os.name == 'nt': MAXON = r"C:\Program Files\MAXON"
        if os.name != 'nt': MAXON = r"/Applications/MAXON"
        if os.path.exists(MAXON): return MAXON
        else: return ""
    
    def c4d_executable_path(ver):
    
        user_ver = ""
        versions = os.listdir(MAXON_P())
        for i in versions:
            if ver.upper() in i.upper() and "demo".upper() not in i.upper():
                user_ver = i
    
        c4d_folder = os.path.join(MAXON_P(), user_ver,)
        files = os.listdir(c4d_folder)
    
        for file in files:
            if os.name == 'nt' and "CINEMA 4D" in file.upper() and "exe" in file and len(file) < 18: ex = file
            if os.name != 'nt' and "CINEMA 4D" in file.upper() in file and len(file) < 18: ex = file
    
        return os.path.join(c4d_folder, ex)
    
    
    
    print c4d_executable_path("R20")
    


  • On Windows, you can use a little trick: To retrieve the currently used Cinema 4D installation, you can query the registry for the program associated with *.c4d files.
    This gives you only a single installation - probably the most current one.

    Is it possible to use it in order to find C4D executable on Windows as well as on mac?

    On Win+Mac, filenames must be unique. So, Cinema 4D.exe/app should be sufficient.



  • Thanks, buddy! :)
    But the problem is that the most current one is not a way to go.

    If the user installed the plugin for R16, then the installer should open R16 itself.

    I'm trying to find and open it by the name, but the name is always different. It can be Cinema 4D / Cinema 4D R16 / Cinema 4D R16 Demo / Cinema 4D Demo / etc.
    Well. This is considerably easier on windows since I can check if it exists by using os.path.exists() function, but I have no Idea how to do this on Mac.


Log in to reply