Saving Undo information of the active tool

For one of the plugin’s that I’m scripting I would like to be able to save the Redo-information of the active tool.
I’ll make myself a little bit clearer:
An example: After a certain phase of painting a nose the Undocounter=22; then I go back, say 3 Undo’s, the Redocounter will then also be 3, implicating the last three polypaintactions 20,21,22 for the nose. Those three actions/informations I would like to be able to save for 3Redo-presses in a later phase, from another point of departure on the same Head/Nose mesh.

Greetings, EddyL

That’s not possible. The redos are dependent on the mesh being at a particular state. If you change that then they are lost. The method you use in your LayerPaint plugin of recording a zscript is a way around the problem but there could be all sorts of problems. For example, the user has only to move the model between record and playback for everything to be thrown out.

Hi Marcus,

Thx for your answer. It’s a real pity that the RedoSave will not work, because for example the LayerPaint could do without the ‘clumsy’ Play-button push.

  1. However, I tried to paint and move the mesh between Record and RePlay but here there is nothing like ‘everything to be thrown out’. So maybe I do not understand what you mean in your reply with this last sentence?

  2. Then, about LayerPaint, I really would like to be able to prevent the user to have to click ‘No’ after the zscript has started the Zscript:Record.

You already told me some threads earlier that I could say something like:
[IKeyPress, 13, [command]]
I use that one with succes in the plugin. So I ask you is there not a [IKeyPress, ?,[IPress,ZScript:Record]] possibility in which the ? stands for clicking ‘No’ in the annoying ZB dialogue or

[IKeyPress, <ArrowRight>, [IKeyPress,13,[IPress,ZScript:Record]]]

Greetings, EddyL

Hi Eddy,

I guess Marcus meant you will loose any Redo’s as soon as you perform an action that qualifies as an Undo.

The undo and redo stacks are not a list of zscript commands but rather state changes made to the canvas and certain elements of 3D tools (Repositioning a 3D tool is not a state change for example).

Hi TVEyes,

You wrote (in my email I could see this, not however in the thread self!? :confused: ):

As for automating a ‘no’ in a dialog window you can use the ascii equivalent of the Escape key, which is 27. 13 is the return key.

[IKeyPress, 27, [Ipress, ZScript:Record]] will press ‘no’ for you.

I gave this a try, but it really works as it should that is: as a Cancel , so the planned Recording is indeed cancelled! :frowning: Maybe there is another ascii number that gives in the choice-situation at hand (Yes,No,Cancel) the ‘No’?

First I already tried:
This code skipped the TAB and gave a Yes, which makes ZB reinitialyze; that surely not what I want.

Then I tried:
This did not work either, although - I’m happy with this unexpected consequence - it made the necessary pushing of the Play-button later on for some strange reason not necessary anymore?

So maybe another answer?
Greetings, Eddy

Dammit! I have been exposed by modern technology :wink:

I originally wrote about the ikeypress 27 but suddenly realised it would not work with the record button dialogue as it has three options, as you mentioned.

I do not think there is an immediate solution. Ikeypressing the escape and return keys do however work fine for most, if not all, the other dialogue windows.

This may sound a little stupid, but I noticed that whenever a Yes No dialog comes up, if you just press N, it takes it as a No. Perhaps the Ascii key for N might work…

Yes, indeed, I tried it out and it really works!!!:+1: :+1:

Now I can go on, thanks to all your help, bravo for this forum!

Greetings, EddyL

Well I never, that’s useful to know! Thanks for sharing Sean. :+1:

One way around the ‘press Play’ problem may be to edit the recording in zscript. After saving the recording you would load it into memory and then replace the [IButton,“Play”,“Press to play this”, bit of code with a simple [If,1, . It would then play immediately it was loaded.

No problem, glad it worked! Now get back to work on that PaintLayer plugin! :stuck_out_tongue:

Hi Marcus,

I’m coming back to your advice about ‘Play’:
You stated:

One way around the ‘press Play’ problem may be to edit the recording in zscript. After saving the recording you would load it into memory and then replace the [IButton,“Play”,“Press to play this”, bit of code with a simple [If,1, . It would then play immediately it was loaded

I think I can use the idea but want to understand exactly what I’m doing:
So for instance during [ipress,zscript:record end] I save the recorded strokes, etc to a Paint#5.txt file.
Then, later, I can [IPress,zscript:load] this file back into memory.
But to rework this .txt-file I need to get it into a variable, for instance: #recordedstrokes.
1. With what code can I do that?
2. I suppose, that I can make all sorts of changes in this txtfile, drop sculptingactions, so to just keep the polypainting relevant stuff into the #recordedstrokes-variable?
3. What is the exact code for starting the replay after replacing the [IButton,“Play”,“Press to play this”, bit of code with a simple [If,1, ?

Greetings, EddyL


It would be a little more complicated. First you would end the recording and save it as Paint#5.txt (or whatever). Then you would create a memory block from the file using the MemCreateFromFile. Once the text file is in a memory block you can edit it using the other memory commands, StrFind and so on.
When you’ve finished you save the file again using MemSaveToFile, and then you can run the zscript recording by using FileNameSetNext and IPress,ZScript:Load.

The whole point about changing the button code to [If,1, is that, because ‘1’ is always ‘true’, the recording will play back immediately.

Another way of doing what you are after has occurred to me but I need to test it before suggesting it. If it works it will solve these problems and give a simpler solution. Due to work pressures, I probably shan’t be able to get back to you for a day or so. I’ll do a sample zscript to show you the memory block editing if needed!

Thanx, Marcus,

I’ll try my best and come back if I can’t make it work with the memoryblock-stuff.
Greetings, EddyL

Hi Marcus,

I tried the following script; helas, it did not work; I must be doing someting wrong:

" ",

//load MemBestand from file:
//now get #recorded from MemBestand:
////Now change #recorded :
[varset,#recorded,[strextract,#recorded,(p+4),lengte]] //from ‘,’ after ‘key."’
[varset,#recorded,[strmerge,“If,1”,#recorded]] //before ', ’ added

//#recorded save in MemBestand:
//save MemBestand in file:


[messageok,“Load Paint#0 with txt ON and this should be readable in the new ‘If,1,’-form”]

Maybe you can give me some comments; as from when you have some time again?

Greetings, EddyL


You’re making things more complicated than they need to be. The memory block doesn’t need to be created first, and, in this case, there’s no need for string variables.

Here is what you do:

//after saving the recording:
[MemCreateFromFile,EL_MemBestand,"ZBRUSH_ZStartup\ZPlugs\LayerPaintTemp\Paint#0.txt",123]//loads file into memory starting at offset 123
[MemWriteString,EL_MemBestand,"[If,1,",0,1]//edits start of file with no terminating zero
[MemSaveToFile,EL_MemBestand,"ZBRUSH_ZStartup\ZPlugs\LayerPaintTemp\Paint#0.txt",1]//saves memory to file (will overwrite if file already exists)
[MemDelete,EL_MemBestand]//delete the memory block

Because a zscript recording always starts with the same text we know that we can dispense with the first 123 characters. That’s why we load the file into memory from offset 123. That means that we can write our edit string and it will be in just the right place.

Note that this will only work if you are sure of the character offset. In other circumstances you would need to search the memory block for the necessary string.

Another thing to be aware of is that there should be no [IReset] at the start of the recording. If there is then the code can fail or get into awkward looping once the button code has been replaced with [If,1,. I mention this just as a warning, though for your plugin I know that you are making sure there is no [IReset].

When you’ve edited the recording, this is for when you want to play it back:

//later, when you want to play back the recording:

One thing to mention about memory blocks: it is a good idea to use a name which is as specific as possible. This is because other zscripts or plugins could access your memory block by mistake if the names happened to be the same. Good practice is to use your initials and a name specific to the zscript. For example, if your name is James Bond and the zscript is called ZCasino the memory block could be called JB_ZCasinoData.


Hi Marcus,

As you suggested, I put the following code into the LayerPaint-plugin:

[memcreatefromfile,el_membestand[strmerge,“ZBRUSH_ZStartup\ZPlugs\LayerPaintTemp\ “,bestand],123]//Paint#”,PaintNum,”.txt"],123]
[memsavetofile,el_membestand,[strmerge,“ZBRUSH_ZStartup\ZPlugs\LayerPaintTemp\ “,bestand],1]//Paint#”,PaintNum,”.txt"],1]
[FileNameSetNext,[strmerge,“ZBRUSH_ZStartup\ZPlugs\LayerPaintTemp\ “,bestand]]//Paint#”,PaintNum,”.txt"]]

Now, for some reason zb does NOT accept this code: arriving at ‘If,1,’ zb refuses the code.

Maybe you have some idea what’s going wrong?

BTW. You said a week ago that you were thinking about an alternative route for what I’m trying to do in this plugin. You were not sure yet wheter it would do the trick. I’m curious about your follow up.

Greetings, EddyL


Can you clarify the problem? Have you looked at the recorded zscript to see that it has been edited correctly? And will it play correctly if you load it using the ZScript:Load button?

Hi Marcus,

The load file only states: [If, 1,

So, what happened with the CanvasStrokes-information?

Greetings, EddyL


I can’t tell what is going wrong from code snippets. Is your zscript recording saving properly to the file name you specify? Comment out some of your code to track down the error if you can.