Jump to content

[CLEO]CarRec(plus ObjRec)


Shagg_E

Recommended Posts

Have you ever noticed random GTA physics? You can make car to jump on certain ramp in a certain coords in script, but it will fall every time a little randomly.

To prevent that problem in SA, Rockstar* made ".rrr" files(in carrec.img), which contains recorded "paths" of vehicles movements. It allowed to create scenes like this.

 

Now it's possible in Vice City, but not car records only...

 

 

"CarRec":

 

 

"CarRec" gives you ability to record car movements into ".cr" file for playback them later in your scripts or missions.

 

Installation:

 

Drop all files and "RECORDINGS" folder from "1. CarRec\CLEO\" into your Vice City's "CLEO" folder, if you has installed last version of CLEO library(http://cleo.li/).

 

How to use:

 

Activation/deactivation(while in car): C + 1

Then you can:

1) To record your vehicle's movements press R.

Press R again to stop recording.

2) To playback your last recording press P.

Press O to pause playback.

Hold I to rewind.

Press P again to stop playback.

 

You can also config "CarRec" in "CLEO\CarRec.ini":

MEMLIMIT:

Allocated memory limit for recording in bytes. Higher value - longer record. Too high values may cause slower working of script.

CLRTRWREC:

Clear traffic while recording: 1 - yes, 0 - no

CLRTRWPLA:

Clear traffic while playback: 1 - yes, 0 - no

HIDEZCNAM:

Hide zone/car names to prevent some bugs: 1 - yes, 0 - no

SHOWALLST:

Show all script's text: 1 - yes, 0 - no

 

Every time you making a record, script creates "carrec.cr" file in "CLEO\RECORDINGS\" folder.

If file already exists - "CarRec" will overwrite it.

Then you can rename this file and use it in your scripts and missions(read "3. For Scripters\How to[ENG].txt").

You can also see some examples of using that recordings in "2. Examples" folder:

1)1CarScene:

Scene with one recorded car.

Activation/deactivation: C + 2

2)2CarsScene:

Scene with two recorded cars.

Activation/deactivation: C + 3

3)10CarsScene:

Scene with ten recorded vehicles.

Activation/deactivation: C + 4

4)360Scene:

Scene with four recorded vehicles, one recorded object(detached infernus's wheel), effects and actors.

Activation/deactivation: C + 5

 

"ObjRec":

 

 

 

You can also to record objects movements using SCM functions from "3. For Scripters\SCM FUNCTIONS" (read more in "3. For Scripters\How to[ENG].txt").

 

You can see an example of using that in "360Scene", when one detached infernus's wheel moves exactly into helicopter's rear rotor every time you playback this scene.

 

 

.CR file structure:

 

 

Each recording contains in ".cr" file consists of "frames". Each frame has this structure(0x30 bytes per frame):

 

0x00 - INT32 - Timekey in ms

0x04 - INT16 - XYZ.right.x

0x06 - INT16 - XYZ.right.y

0x08 - INT16 - XYZ.right.z

0x0A - INT16 - XYZ.up.x

0x0C - INT16 - XYZ.up.y

0x0E - INT16 - XYZ.up.z

0x10 - FLOAT - XYZ.pos.x

0x14 - FLOAT - XYZ.pos.y

0x18 - FLOAT - XYZ.pos.z

0x1C - INT16 - x push

0x1E - INT16 - y push

0x20 - INT16 - z push

0x22 - INT16 - x turn speed

0x24 - INT16 - y turn speed

0x26 - INT16 - z turn speed

0x28 - INT8 - Steering Angle

0x29 - INT8 - Accelerator Pedal Power

0x2A - INT8 - Brake Pedal Power

0x2B - INT8 - Hand Brake Status

0x2C - INT8 - Horn Status

0x2D-0x30 - 3 bytes - Reserved

 

Recording and playback doesn't depends of FPS: they attached to game timer so it doesn't matter if you record on 60 FPS and playing this recording at 30 FPS or vice versa.

 

 

.OR file structure:

 

 

(0x28 bytes per frame):

 

0x00 - INT32 - Timekey in ms

0x04 - INT16 - XYZ.right.x

0x06 - INT16 - XYZ.right.y

0x08 - INT16 - XYZ.right.z

0x0A - INT16 - XYZ.up.x

0x0C - INT16 - XYZ.up.y

0x0E - INT16 - XYZ.up.z

0x10 - FLOAT - XYZ.pos.x

0x14 - FLOAT - XYZ.pos.y

0x18 - FLOAT - XYZ.pos.z

0x1C - INT16 - x push

0x1E - INT16 - y push

0x20 - INT16 - z push

0x22 - INT16 - x turn speed

0x24 - INT16 - y turn speed

0x26 - INT16 - z turn speed

 

 

Some Stuff:

 

 

 

You can free use, share and modify all files, included in archive.

 

by Shagg_E

 

Credits:

 

DK - "Core" of the script (binary files operations), support

xanser - Solving movement lags problem

spaceeinstein - Solving vehicle's horn problem

kenking - Solving wheel's detaching problem

=SpitFire= - Help and support

mfisto - Help

 

 

 

DOWNLOAD

(mirror download)

Edited by Shagg_E
Link to comment
Share on other sites

  • 2 weeks later...
  • 1 year later...

I installed the mod and it works perfectly but how can i make a playback with 2 cars or like these found in the examples folder i know you need to script but it would be easier if it was explained in a video for gta vc

Edited by JohnsonHu
Link to comment
Share on other sites

2 hours ago, JohnsonHu said:

I installed the mod and it works perfectly but how can i make a playback with 2 cars or like these found in the examples folder i know you need to script but it would be easier if it was explained in a video for gta vc

Just copy all SCM functions from "CarRec2CarsScene"(more relatable example, added in the end of this comment) or "CarRec10CarsScene"(more complex example with the economy of variables) to any place of your CLEO script or main.scm, then all you need to do is:

1) Load recording file before playback:

0AB1: call_scm_func @CARRECORD_READCR 1 file 1 store to 1@ // read file 1, store to CarAllocMemoryAddress(1@)

, where
"file 1" is just a number that will affect which file will be loaded by "CARRECORD_READCR" SCM function. Just look at this function and how it chooses the file depending on this number, and you will understand it.
1@ - can be replaced by any other variable. Must be unique for each vehicle.

 

2) Then you need to call this function every frame for playback:

0AB1: call_scm_func @CARRECORD_PLAYBACK 4 0@ 1@ 0 0 14@ // CarHandle, AllocMemoryAddress, SetFrame, ShowInfo, GetFrame

, where
0@ - vehicle's handle.
1@ - unique variable from previous loading function.
0 - first playback frame. Yes, you can start playback from any point of recording(for recordings synchronization).
0 - "show info text" trigger.
14@ - get current playback frame(for conditions).

Stop calling this function to stop playback.

 

3) Unload memory:

0AC9: free_allocated_memory 1@

1@ - unique variable from previous functions.

 

 

I know, it's not a very comfortable solution. That's why I working on new opcodes that will include a new way for creating and playback these and a few other types of recordings. But I don't think it will be finished in the coming months, unfortunately...

 

 

Here are the SCM functions from "CarRec2CarsScene":

Spoiler

//-----------------------------------------------------------------------------------------------------------------
//--------------------------------------------------SCM FUNCTIONS--------------------------------------------------

:IF1OR2KEYSPRESSEDANDTHENRELEASED
0006: 15@ = 0
8039:   NOT 0@ == 0
jf @IF1OR2KEYSPRESSEDANDTHENRELEASED_RETURN
0006: 14@ = 1 // keys number
0AB0: key_pressed 0@
jf @IF1OR2KEYSPRESSEDANDTHENRELEASED_RETURN
8039:   NOT 1@ == 0
jf @IF1OR2KEYSPRESSEDANDTHENRELEASED_CHECKWHENRELEASED
0006: 14@ = 2 // keys number
0AB0: key_pressed 1@
jf @IF1OR2KEYSPRESSEDANDTHENRELEASED_RETURN

:IF1OR2KEYSPRESSEDANDTHENRELEASED_CHECKWHENRELEASED
wait 0
0AB0: key_pressed 0@
jf @IF1OR2KEYSPRESSEDANDTHENRELEASED_DONE
0019:   14@ > 1
jf @IF1OR2KEYSPRESSEDANDTHENRELEASED_CHECKWHENRELEASED
8AB0: NOT key_pressed 1@
jf @IF1OR2KEYSPRESSEDANDTHENRELEASED_CHECKWHENRELEASED

:IF1OR2KEYSPRESSEDANDTHENRELEASED_DONE
0006: 15@ = 1

:IF1OR2KEYSPRESSEDANDTHENRELEASED_RETURN 
0AB2: ret 1 15@

:CARRECORD_READCR
0039:   0@ == 1
jf @CARRECORD_READCR2
0AA7: call_function 0x48DF90 num_params 2 pop 2 "rb" "cleo\\recordings\\cr2css1.cr" 15@ // file = CFileMgr::Open("cleo\recordings\cr2css1.cr", "rb");
jump @CARRECORD_READCR_GO

:CARRECORD_READCR2
0AA7: call_function 0x48DF90 num_params 2 pop 2 "rb" "cleo\\recordings\\cr2css2.cr" 15@ // file = CFileMgr::Open("cleo\recordings\cr2css2.cr", "rb");

:CARRECORD_READCR_GO
// Get file size to 14@:
0AA5: call 0x48DEE0 num_params 3 pop 3 2 0 15@ // CFileMgr::Seek(file, 0, SEEK_END);
0AA7: call_function 0x652D50 num_params 1 pop 1 15@ 14@ // size = ftell(file);
// Go to beginning of the file:
0AA5: call 0x48DEE0 num_params 3 pop 3 0 0 15@ // CFileMgr::Seek(file, 0, SEEK_SET);
// Now start reading:
000A: 14@ += 0xFF // just some reserve
0AC8: 13@ = allocate_memory_size 14@
000E: 14@ -= 0xFF
0006: 12@ = 0x00
0085: 11@ = 13@
000A: 11@ += 0x04 // first 4 bytes is reserved for global timer
0A8C: write_memory 11@ size 4 value 14@ virtual_protect 1 // recording file size
000A: 11@ += 0x08 // next 4 bytes is reserved for current frame number

:CARRECORD_READCR_GO2
if
801D:   NOT 12@ > 14@
jf @CARRECORD_READCR_RETURN
0085: 10@ = 11@
005A: 10@ += 12@
0AA5: call 0x48DF50 num_params 3 pop 3 4 10@ 15@ // CFileMgr::Read(file, var_offset, 4);
000A: 12@ += 0x04    
jump @CARRECORD_READCR_GO2

:CARRECORD_READCR_RETURN
0AA5: call 0x48DEA0 num_params 1 pop 1 15@ // CFileMgr::Close(file);
0AB2: ret 1 13@

:CARRECORD_PLAYBACK
0085: 13@ = 3@
0085: 3@ = 1@
0A8D: 5@ = read_memory 3@ size 4 virtual_protect 1 // getting saved global timer
0085: 4@ = 1@
000A: 4@ += 0x04 
0A8D: 6@ = read_memory 4@ size 4 virtual_protect 1 // getting file size
000E: 6@ -= 0x60 // last few bytes of .cr file may be corrupted so we'll skip 2 frames to prevent some bugs
000A: 4@ += 0x04 
0A8D: 7@ = read_memory 4@ size 4 virtual_protect 1 // getting current frame number
8039:   NOT 2@ == 0 // if frame is predetermined
jf @CARRECORD_PLAYBACK_START
0085: 7@ = 2@
0A8C: write_memory 4@ size 4 value 7@ virtual_protect 1 // saving predetermined frame number
gosub @CARRECORD_PLAYBACK_GETCURRENTOFFSET
jump @CARRECORD_PLAYBACK_CHECKOFFSET

:CARRECORD_PLAYBACK_START
0039:   5@ == 0
jf @CARRECORD_PLAYBACK_CHECKOFFSET

:CARRECORD_PLAYBACK_RESTART
0006: 2@ = 0
01BD: 5@ = current_time_in_ms
0A8C: write_memory 3@ size 4 value 5@ virtual_protect 1 // saving current global timer
0006: 7@ = 0
0A8C: write_memory 4@ size 4 value 7@ virtual_protect 1 // saving zero frame
jump @CARRECORD_PLAYBACK_CHECKOFFSET

:CARRECORD_PLAYBACK_CHECKOFFSET
gosub @CARRECORD_PLAYBACK_GETCURRENTOFFSET
001D:   6@ > 11@
jf @CARRECORD_PLAYBACK_RESTART
0093: 15@ = integer 6@ to_float
0093: 9@ = integer 11@ to_float
0073: 9@ /= 15@
0013: 9@ *= 100.0
0092: 9@ = float 9@ to_integer // playback percent
// Check Time:
gosub @PLAYBACK_GETADDRESSBYOFFSET
0A8D: 14@ = read_memory 15@ size 4 virtual_protect 1
8039:   NOT 2@ == 0 // if frame is predetermined
jf @CARRECORD_PLAYBACK_CHECKTIME
01BD: 5@ = current_time_in_ms
0062: 5@ -= 14@
0A8C: write_memory 3@ size 4 value 5@ virtual_protect 1 // saving pause-mode global timer
0006: 8@ = 0
0085: 10@ = 14@
0016: 10@ /= 1000
jump @CARRECORD_PLAYBACK_APPLYVALUES

:CARRECORD_PLAYBACK_CHECKTIME
01BD: 8@ = current_time_in_ms
0062: 8@ -= 5@
0085: 10@ = 8@
0016: 10@ /= 1000
002D:   8@ >= 14@  // if there is recording for this time
jf @CARRECORD_PLAYBACK_RETURN // else nothing to do here

:CARRECORD_PLAYBACK_SKIPTIME
000A: 7@ += 1
gosub @CARRECORD_PLAYBACK_GETCURRENTOFFSET
001D:   6@ > 11@
jf @CARRECORD_PLAYBACK_RESTART
gosub @PLAYBACK_GETADDRESSBYOFFSET
0A8D: 14@ = read_memory 15@ size 4 virtual_protect 1
001D:   14@ > 8@
jf @CARRECORD_PLAYBACK_SKIPTIME
000E: 7@ -= 1

:CARRECORD_PLAYBACK_APPLYVALUES
gosub @CARRECORD_PLAYBACK_GETCURRENTOFFSET
gosub @PLAYBACK_GETADDRESSBYOFFSET
000A: 7@ += 1 
0A8C: write_memory 4@ size 4 value 7@ virtual_protect 1 // saving next frame number
000E: 7@ -= 1 // back to current frame number
000A: 15@ += 0x04
0085: 11@ = 13@
0A97: 14@ = car 0@ struct
// Playback Matrix:
0085: 13@ = 14@ 
000A: 13@ += 0x04 // right x 
gosub @PLAYBACK_APPLYROTVALUEFROMINT16 // playback right x
000A: 13@ += 0x04 // right y 
gosub @PLAYBACK_APPLYROTVALUEFROMINT16 // playback right y
000A: 13@ += 0x04 // right z 
gosub @PLAYBACK_APPLYROTVALUEFROMINT16 // playback right z
000A: 13@ += 0x08 // up x 
gosub @PLAYBACK_APPLYROTVALUEFROMINT16 // playback up x
000A: 13@ += 0x04 // up y
gosub @PLAYBACK_APPLYROTVALUEFROMINT16 // playback up y
000A: 13@ += 0x04 // up z
gosub @PLAYBACK_APPLYROTVALUEFROMINT16 // playback up z
000A: 13@ += 0x18 // position x 
gosub @PLAYBACK_APPLYVALUE // playback position x
000A: 13@ += 0x04 // position y
gosub @PLAYBACK_APPLYVALUE // playback position y
000A: 13@ += 0x04 // position z
gosub @PLAYBACK_APPLYVALUE // playback position z
// Playback Movement Speed:
if
0019:   8@ > 0
jf @CARRECORD_PLAYBACK_NOPUSH
0085: 13@ = 14@
000A: 13@ += 0x70 // x push
gosub @PLAYBACK_APPLYSPDVALUEFROMINT16 // playback x push
000A: 13@ += 0x04 // y push
gosub @PLAYBACK_APPLYSPDVALUEFROMINT16// playback y push
000A: 13@ += 0x04 // z push
gosub @PLAYBACK_APPLYSPDVALUEFROMINT16 // playback z push
// Playback Turn Speed:
000A: 13@ += 0x04 // x turn speed
gosub @PLAYBACK_APPLYSPDVALUEFROMINT16 // playback x turn speed
000A: 13@ += 0x04 // y turn speed
gosub @PLAYBACK_APPLYSPDVALUEFROMINT16 // playback y turn speed
000A: 13@ += 0x04 // z turn speed
gosub @PLAYBACK_APPLYSPDVALUEFROMINT16 // playback z turn speed
jump @CARRECORD_PLAYBACK_FINISH

:CARRECORD_PLAYBACK_NOPUSH
0085: 13@ = 14@
000A: 13@ += 0x70 // x push
gosub @PLAYBACK_APPLYZERO // playback x push
000A: 13@ += 0x04 // y push
gosub @PLAYBACK_APPLYZERO // playback y push
000A: 13@ += 0x04 // z push
gosub @PLAYBACK_APPLYZERO // playback z push
// Playback Turn Speed:
000A: 13@ += 0x04 // x turn speed
gosub @PLAYBACK_APPLYZERO // playback x turn speed
000A: 13@ += 0x04 // y turn speed
gosub @PLAYBACK_APPLYZERO // playback y turn speed
000A: 13@ += 0x04 // z turn speed
gosub @PLAYBACK_APPLYZERO // playback z turn speed

:CARRECORD_PLAYBACK_FINISH
// Playback Extra Values:
000A: 13@ += 0x168 // steering angle (negative = wheels right; positive = wheels left)
0A8D: 12@ = read_memory 15@ size 1 virtual_protect 1
gosub @PLAYBACK_CHECKBYTEREADINGERROR
0093: 12@ = integer 12@ to_float
0017: 12@ /= 20.0
0A8C: write_memory 13@ size 4 value 12@ virtual_protect 1
000A: 15@ += 0x01
000A: 13@ += 0x04 // accelerator pedal power
0A8D: 12@ = read_memory 15@ size 1 virtual_protect 1
gosub @PLAYBACK_CHECKBYTEREADINGERROR
0093: 12@ = integer 12@ to_float
0017: 12@ /= 100.0
0A8C: write_memory 13@ size 4 value 12@ virtual_protect 1
000A: 15@ += 0x01
000A: 13@ += 0x04 // brake pedal power
0A8D: 12@ = read_memory 15@ size 1 virtual_protect 1
gosub @PLAYBACK_CHECKBYTEREADINGERROR
0093: 12@ = integer 12@ to_float
0017: 12@ /= 100.0
0A8C: write_memory 13@ size 4 value 12@ virtual_protect 1
000A: 15@ += 0x01
000A: 13@ += 0x05 // hand brake/heli weapon status (16 - off, 48 - on)
0A8D: 12@ = read_memory 15@ size 1 virtual_protect 1
0A8C: write_memory 13@ size 1 value 12@ virtual_protect 1
0019:   12@ > 16
jf @CARRECORD_PLAYBACK_FINISH2
if or
0137:   car 0@ model == 155 // hunter
0137:   car 0@ model == 177 // seaspar 
jf @CARRECORD_PLAYBACK_FINISH2
0541: fire_guns_on_vehicle 0@

:CARRECORD_PLAYBACK_FINISH2
000A: 15@ += 0x01
000A: 13@ += 0x4C // activate horn/siren
0A8D: 12@ = read_memory 15@ size 1 virtual_protect 1
0A8C: write_memory 13@ size 1 value 12@ virtual_protect 1

:CARRECORD_PLAYBACK_RETURN
0039:   11@ == 1
jf @CARRECORD_PLAYBACK_RETURN2
0AD1: show_formatted_text_highpriority "~p~PLAYBACK: %d sec. ~h~Frame: ~p~%d ~h~(~p~%d%% ~h~of full recording)" time 100 10@ 7@ 9@

:CARRECORD_PLAYBACK_RETURN2
0AB2: ret 1 7@

:CARRECORD_PLAYBACK_GETCURRENTOFFSET
0085: 11@ = 7@ // get current frame
0012: 11@ *= 0x30 // multiply on frame size
000A: 11@ += 0x0C // plus start offset - now we got current offset
return

:PLAYBACK_GETADDRESSBYOFFSET
0085: 15@ = 1@
005A: 15@ += 11@
return

:PLAYBACK_APPLYVALUE
0A8D: 12@ = read_memory 15@ size 4 virtual_protect 1
0A8C: write_memory 13@ size 4 value 12@ virtual_protect 1
000A: 15@ += 0x04
return

:PLAYBACK_APPLYROTVALUEFROMINT16
0A8D: 12@ = read_memory 15@ size 2 virtual_protect 1
0019:   12@ > 32767
jf @PLAYBACK_APPLYROTVALUEFROMINT16_RETURN
000E: 12@ -= 65536

:PLAYBACK_APPLYROTVALUEFROMINT16_RETURN
0093: 12@ = integer 12@ to_float
0017: 12@ /= 30000.0
0A8C: write_memory 13@ size 4 value 12@ virtual_protect 1
000A: 15@ += 0x02
return

:PLAYBACK_APPLYSPDVALUEFROMINT16
0A8D: 12@ = read_memory 15@ size 2 virtual_protect 1
0019:   12@ > 32767
jf @PLAYBACK_APPLYSPDVALUEFROMINT16_RETURN
000E: 12@ -= 65536

:PLAYBACK_APPLYSPDVALUEFROMINT16_RETURN
0093: 12@ = integer 12@ to_float
0017: 12@ /= 10000.0
0A8C: write_memory 13@ size 4 value 12@ virtual_protect 1
000A: 15@ += 0x02
return

:PLAYBACK_CHECKBYTEREADINGERROR
0019:   12@ > 127
jf @PLAYBACK_CHECKBYTEREADINGERROR_RETURN
000E: 12@ -= 256

:PLAYBACK_CHECKBYTEREADINGERROR_RETURN
return

:PLAYBACK_APPLYZERO
0A8C: write_memory 13@ size 4 value 0.0 virtual_protect 1
000A: 15@ += 0x02
return

 

 

 

 

Edited by Shagg_E
Link to comment
Share on other sites

So is it possible to use the exact same code for another recording but with different vehicles and actors?

Edited by JohnsonHu
Link to comment
Share on other sites

Yes. Every SCM function may be called countless times for different vehicles. "CarRec2CarsScene" is the finest and simplest example of that.

Link to comment
Share on other sites

Hello i just used this code example for my recordings (i recorded two banshees racing and when i load it 

The scene loads the actor loads but the game counts down from 3 to 1 and but it will crash after it counts to two and it keeps giving me :

 

Unhandled exeption

 

at address 00652d8b

 Why does it do that i dont know ?

 

 

Edited by JohnsonHu
Link to comment
Share on other sites

Check if you selected "As is" in Sanny Builder's "Tools/Options/Formats/Case converting/".
If you did it, and after recompiling you still has this problem - send me those files and your script(if you changed it) here or in PM, I'll check them.

Edited by Shagg_E
Link to comment
Share on other sites

It worked! 

The playback/recording worked fine and amazing but,it seem to be ending much shorter than what i recorded because the first recording is 50secs and the second is 60 secs but they end in the exact same time but shorter like 26 secs no matter how long i recored them

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • 1 User Currently Viewing
    0 members, 0 Anonymous, 1 Guest

×
×
  • Create New...

Important Information

By using GTAForums.com, you agree to our Terms of Use and Privacy Policy.