Solved How to understand symbols of some spcial case ?

Hello everyone,

Question

I get some strange words from sdk and never found what they means, how can I get some info more spcificly?

e.g. I try to check rendering states of my batch render ,when batch render come with a error then , alert me rather than waste all night time, some I think I can get a state list of render queue, when error happens , take an alert and never warning this element this time . but when I test the state , it seems RM_ERROR2 is the only one , I delete some texture to test a warning document , RM_ERROR still not worked , How can I get this symbols meaning ?

This problem also heppened when some undo or some symbols have a number ending

17091cc1-2e2b-488f-82fa-6a9eaa9aaf9c-image.png

by the way , I think GetEnableElement document is wrong ?

Cheers

Hello @dunhou,

Thank you for reaching out to us. I am not fully sure if I understand you correctly here. I wrote a small example script (see end of posting), and BatchRender.GetElementStatus does what I would expect it to do.

The problem here is the sparsely documented nature of RM_ERROR and RM_ERROR_2. Both statuses are of semi-private nature and are not really meant to convey anything else than that 'something' has gone wrong with a rendering. Internally, it is RM_ERROR which conveys most of the 'interesting' error cases.

case RM_ERROR2:
  switch (error)
  {
    case RM_ERR_OUTPUT: ...
    case RM_ERR_OUTPUTMULTI: ...
    case RM_ERR_TEXFAIL: ...
    default: ...
  }
case RM_ERROR:
{
  switch (error)
  {
    case (Int32)RENDERRESULT::OUTOFMEMORY: ...
    case (Int32)RENDERRESULT::ASSETMISSING: ...
    case (Int32)RENDERRESULT::SAVINGFAILED: ...
    case (Int32)RENDERRESULT::GICACHEMISSING: ...
    case (Int32)RENDERRESULT::NOMACHINE: ...
    case RM_ERR_DEL: ...
    case (Int32)RENDERRESULT::ERRORLOADINGPROJECT: ...
    case (Int32)RENDERRESULT::USERBREAK: ...
    default: ...
  }
}

But in the front-end, they are then lumped together, with both errors then having their combined meaning.

It is also important that not all statuses are conveyed in all contexts. The statues are meant to feed the render queue manager. So, when there is a problem with a job it will convey that before the queue is running. But once a job is queued in a running queue, it will not convey anymore missing textures, because in the logic of the render queue, it is now either "too late for that" or "intended by the user". So, when one wants to detect a problem with a job, one must also do that before running a queue. It might also be worth having a look at BatchRender.GetJsonJobs in addition to BatchRender.GetElementStatus, because the JSON data is more granular.

I agree that the short description for BatchRender.GetEnableElement is misleading a probably was copied from .EnableElement I will fix that in an upcoming release. Having a quick look at the C++ documentation, it also seems like the C++ and Python docs are not aligned.

Cheers,
Ferdinand

Result:

Before rendering:
----------------------------------------------------------------------------------------------------
Render job 0 (C:\Users\f_hoppe\Desktop\missing_texture.c4d) has the status: RM_ERROR2.
----------------------------------------------------------------------------------------------------
[{'added_to_queue': '01/03/2023, 13:47:14',
  'estimated_time': '',
  'filename': 'missing_texture.c4d',
  'frame': '00:00:00 ',
  'frames': [],
  'id': '0',
  'image': 'missing_texture.c4d',
  'image_path': 'missing_texture_rendering',
  'last_frame': '00:00:00 ',
  'log': '',
  'message': 'Error - Missing Files',
  'outputheight': '720',
  'outputwidth': '1280',
  'progress': '0',
  'render_started_on': '-',
  'render_time': '00:00:00 ',
  'status': 'Error',
  'total_frames': '1',
  'uuid': '19140F93-1025-4836-BDA0-8279BEB58999'}]

While rendering:
----------------------------------------------------------------------------------------------------
Render job 0 (C:\Users\f_hoppe\Desktop\missing_texture.c4d) has the status: RM_PROGRESS.
----------------------------------------------------------------------------------------------------
[{'added_to_queue': '01/03/2023, 13:47:14',
  'estimated_time': '00:00:00 ',
  'filename': 'missing_texture.c4d',
  'frame': '00:00:00 ',
  'frames': [],
  'id': '0',
  'image': 'missing_texture.c4d',
  'image_path': 'missing_texture_rendering',
  'last_frame': '00:00:00 ',
  'log': '---File Information---\r\n'
         'File Name : missing_texture.c4d\r\n'
         'File Path : C:\\Users\\f_hoppe\\Desktop\r\n'
         '---Render Data---\r\n'
         'Render Settings : My Render Setting\r\n'
         'Take : Main\r\n'
         'Camera : Default Camera\r\n'
         'Width : 1280\r\n'
         'Height : 720\r\n'
         'Film Aspect : 1.778\r\n'
         'Pixel Aspect : 1\r\n'
         'FPS : 30\r\n'
         'From : 0\r\n'
         'To : 0\r\n'
         'Step : 1\r\n'
         '---Save Information---\r\n'
         'Path : \r\n'
         'Depth : 8\r\n'
         'Format : PNG\r\n'
         '---Render Information---\r\n',
  'message': '',
  'outputheight': '720',
  'outputwidth': '1280',
  'progress': '0',
  'render_started_on': '01/03/2023, 13:47:15',
  'render_time': '00:00:00 ',
  'status': 'In Progress',
  'total_frames': '1',
  'uuid': '19140F93-1025-4836-BDA0-8279BEB58999'}]

Code:

"""Demonstrates the different contexts and methods to retrieve render queue job item information with.

Must be run as a Script Manager script. Should be run on a scene which is missing assets, e.g., a 
texture to have a meaningful output.
"""

import c4d
import os
import pprint

"""Translates render queue error symbols to their symbol string.
"""
RM_STATUS_SYMBOLS: dict[int, str] = {
    c4d.RM_PROGRESS: "RM_PROGRESS",
    c4d.RM_FINISHED: "RM_FINISHED",
    c4d.RM_STOPPED: "RM_STOPPED",
    c4d.RM_ERROR: "RM_ERROR",
    c4d.RM_ERROR2: "RM_ERROR2",
    c4d.RM_PAUSED: "RM_PAUSED",
    c4d.RM_QUEUE: "RM_QUEUE",
    c4d.RM_NONE: "RM_NONE",
}

doc: c4d.documents.BaseDocument # The active document.

def GetBatchRenderJobStatusesString(batchRender: c4d.documents.BatchRender) -> str:
    """Returns a pretty formatted string for all currently enqueued batch render jobs.

    This will include disabled jobs.
    """
    result: list[str] = []
    for index in range(batchRender.GetElementCount()):
        result.append(f"Render job {index} ({batchRender.GetElement(index)}) has the status: "
                      f"{RM_STATUS_SYMBOLS[batchRender.GetElementStatus(index)]}.")

    return "\n".join(result)


def main() -> None:
    """Runs the example.
    """
    # Get the document path and the batch renderer.
    path: str = os.path.join(doc.GetDocumentPath(), doc.GetDocumentName())
    if not os.path.exists(path):
        c4d.gui.MessageDialog("Please save the document first.")
        return

    batchRender: c4d.documents.BatchRender = c4d.documents.GetBatchRender()
    if batchRender.IsRendering():
        c4d.gui.MessageDialog("Batch renderer is already rendering.")
        return

    # Put the new job in front of the queue.
    batchRender.AddFile(path, 0)

    # When #doc contains an #RENDERRESULT::ASSETMISSING error, it will bubble up as an #RM_ERROR here.
    print ("Before rendering:")
    print("-" * 100)
    print(GetBatchRenderJobStatusesString(batchRender))
    print("-" * 100)
    pprint.pprint(batchRender.GetJsonJobs())

    # Start the rendering.
    batchRender.SetRendering(c4d.BR_START)

    # But it will not here since in the logic of the render queue, it is "too late" to worry about
    # that once the rendering is running.
    print ("\nWhile rendering:")
    print("-" * 100)
    print(GetBatchRenderJobStatusesString(batchRender))
    print("-" * 100)
    pprint.pprint(batchRender.GetJsonJobs())

    
if __name__ == '__main__':
    main()

MAXON SDK Specialist
developers.maxon.net

@ferdinand Thanks for that!

I think BatchRender.GetJsonJobs do a great job but a little pitty that the velue of the json is not use an "int" , so when I want to support Chinese users , it returns 'status': '在队列&#x4e2d like this , so I think it a little bit limitation for not a native English users.

And the RM_ERROR and RM_ERROR2 code shows most I want , I belive a lot of symbols has teh same XXXX and XXXX2 situation,but most document didn't have any infomations .

And a little questions with "Batch Render" but not the symbol, I don't sure should I post in another topic:

When I use IsRendering to spy the render queue ,if A and B is switch rendering status ( aka , A is finishing , and B is just starting ).this few time would break the while and return a bad value not I want. How can I fix this?

batchRender: BatchRender = c4d.documents.GetBatchRender()
while batchRender.IsRendering():
    c4d.StatusSetText(f"Rendering....")    
    time.sleep(5)

Cheers~

Hello @dunhou,

it returns 'status': 在队列&#x4e2d like this , so I think it a little bit limitation for not a native English users.

status is the HTML-encoded Unicode string for the characters '在队列中'. &# is how Unicode is encoded in HTML, and xNNNN is the Unicode and ; is the delimiter. You can either decode them manually using str and bytes or just use the handy html.unescape.

import html

status: str = "在队列&#x4e2d"
print (html.unescape(status))

82cbd235-fbc9-473c-8368-94e5aa3711ae-image.png

And the RM_ERROR and RM_ERROR2 code shows most I want , I belive a lot of symbols has teh same XXXX and XXXX2 situation,but most document didn't have any infomations.

Yes, we are aware. We fix them when we are pushed onto errors, but cannot just fix them all at once. You must understand that Cinema 4D has code which is up to two decades old, so documentation can get out of whack over time.

When I use IsRendering to spy the render queue ,if A and B is switch rendering status ( aka , A is finishing , and B is just starting ).this few time would break the while and return a bad value not I want. How can I fix this?

I assume you are talking here about the case that you have a render queue with two jobs A and B. And it seems to be the case that there is a brief moment when A has already finished B has not yet started, where batchRender.IsRendering() returns False, although there is still an upcoming rendering.

Your solution with time.sleep seems sort of fine, but error prone for cases where initializing the new rendering takes more than five seconds. I would simply write something which checks if there are still pending jobs (c4d.RM_QUEUE) in the queue in addition to checking if the batch renderer is actively rendering.

Cheers,
Ferdinand

MAXON SDK Specialist
developers.maxon.net

@ferdinand Thanks for your help.

I did search on web and find the Unicode string, and Chinese characters is so much complicated ,when most user use Chinese for the GUI language, Maybe sometime the translation of the world "在队列中" witch means "in the queue" in English has changed ( I belive now Chinese translation is response to IHDT so it won't randomly changed). That is not a big problem but maybe a little "uniform" with the "ID"😊

And the "brief moment" is I don't sure why does it happend. In another word ,I think the initializing render process can be also called "rendering" . so it is a bit of counterintuitive for me , maybe I should add an additional check to make sure the spying will not break while the brief.

Cheers~