Solved Can a Render Token contain Special Characters?

Hi,

I want my custom render token to output a path fragment as for example root/name.

So, when I have the render path $MyRenderToken/myFile.png, I want it to be resolved to root/name/myFile.png. All my attempts resulted in the path delimters being replaced with the underscore character, resulting in a directory root_name instead of a pair of nested directories root/name.

Thanks!

[edited by @ferdinand]: This is an interesting question which might be relevant for more users, so I took the liberty to make this posting more accesible.

Original posting by @Dunhou:

I want custom my render token,just like this folder structure

_[root/prj name/version/cam/prj name.png]

the function is done

but it seems token can only generate a file name?

Is there any possible to define a folder structure with a short word?

$RNDR = root/prj name/version/cam/prj name.png

but not : root_prj name_versio_cam_prj name.png

PS : I know I can save a new.c4d file to do this, but Still need a esay way to difine this ,

Thanks!

Hello @dunhou,

Thank you for reaching out to us. Unfortunately, the answer is no, you cannot escape this. In the backend, the render path handling has a list of special characters (".", " ", "/", "?", "<", ">", "\\", ":", "*", "|", "(" ")") which will be replaced by the underscore character (_). As you can see, this list includes the path delimiters for both Windows and macOS. Among other things, this replacement logic is applied to the output of render token callback functions. There is nothing you can do to prevent this.

The only thing I could think of is to implement multiple tokens. So, let's say you want to depict a directory depth of up to 5. You would then have to implment the render tokens $a, $b, $c, $d, and $e and enter a render path as shown below:

$a/$b/$c/$d/$e/myFile.jpg

These tokens would have to analyze the path they are contained in and then output a desired folder structure, e.g., this:

a/b/c/d/e/myFile.jpg

You should also be able to produce shorter paths by for example let $c and $d return the empty string when some condition x is met. This would formally result in this output:

a/b///e/myFile.jpg

which is equivalent to

a/b/e/myFile.jpg

Cheers,
Ferdinand

MAXON SDK Specialist
developers.maxon.net

@ferdinand
Thanks for your repley. My personal solution is also use multiple custom tokens, but it is a bit painful QAQ.

I have to reg multiple tokens and define a string include token symol by a command buttom script. A little annoying problem-.- but better than input by hand😢

Thanks for your help

@ferdinand
I try to return a empty string when project name don't have a delimiter like
_vstring , but in output path doesn't work anymore. This token just as a string in output:
C4D File name : token.c4d / token_v2.c4d
MyToken : $root/$rprj(real prj name with out _v[version])/$vn(version name)/$rprj
expect path A :token_v2.c4d > $root/token/v2/token.png
expect path Btoken.c4d > $root/token/token.png
but when there is no version in prj name[B], It's output like this:
token.c4d > $root/token/$vn[just the token symbol as str]/token.png
And this is the $vnpart code :

import os
import c4d
import re
delimiter = "_v"
# Get version number
def GetVersion(filePath):
    versionList = re.findall(delimiter+"\d+",filePath)
    if len(versionList) == 0: # If no versions found
        return None, None
    rawVersion = re.compile(delimiter).split(versionList[len(versionList)-1])[1] # [string]
    version = int(rawVersion) #  [integer]
    return version, rawVersion

# Thoken : Project Version Name with _v  ($vn)
def GetProjectVersionName(data): # _v2 
    prjName = data[0].GetDocumentName()
    ver = GetVersion(prjName)[1] # rawVersion [string]     
    if ver == None: # if prj name have no delimiter component
        verStr = ""
        return verStr    # null string 
    else:
        verStr = delimiter + ver
        return verStr  # _v2

if __name__=="__main__":
    for registeredToken in c4d.modules.tokensystem.GetAllTokenEntries():
        if registeredToken.get("_token") in ["root", "rprj", "vn"]:
            exit() 
        c4d.plugins.RegisterToken("vn", "DH Project Version Name", "v001", GetProjectVersionName) 

Is there something wrong,please help me out.
Thank you

Hey @dunhou,

Your code is fine, my suggestion simply does not work. I suggested it because I could have sworn this worked before and we show something similar with returning an empty string in the C++ Docs for the TOKENHOOK documentation.

Not sure what happened there, if this was always intended to work like this, or if this is a regression. The render token functionality is however not that old, so it likely is intended.

The culprit is this:

// #entry is here a render token
String search = String("$" + entry.GetKey());
String value = CheckSpacialStrings(entry.GetValue()->GetString(const_cast<void*>(data)));
if (value.IsPopulated())
{
    // The replacement of the token is prepared here ...
}

So, when your token returns the empty string, it simply does not carry out the replacement. I am sorry that I have send you into the wrong direction. There is not really much left you can do, apart from ignoring the render token system altogether and implement this from scratch on your own.

Cheers,
Ferdinand

MAXON SDK Specialist
developers.maxon.net

@ferdinand
It's so sad , I'll try a script to define some output path token presets.
Hope it can work as expect.
Thanks for your answer

@ferdinand

A little update for this topic , my final solution for this problem is reg some tokens , and reg a plugin to analysis the project name and set token string depend on project name structure .

like a project name has a version sign like _v , than the output path set a $v for render . All the tokens can set by the analysis plugin . It is a bit stupid way but work well for a quickly set render path just one click.

Cheers🥂