Gordon_G Posted October 23, 2018 Share Posted October 23, 2018 Hi, I've somehow tried to create a script that could record a player path and then play it by a ped So, everything works well, the returned JSON table is goodly played by the bot but the issue is that it's not always exactly the same way Sometimes, the vehicle will turn too early for example, sometimes it will turn too late local r_table = {} local startTick = 0 local pushedControls = {} -- {pushed control, forhowmuchtime, when it start to push} local recording = false local cs = { "fire", "aim_weapon", "next_weapon", "previous_weapon", "forwards", "backwards", "left", "right", "zoom_in", "zoom_out", "change_camera", "jump", "sprint", "look_behind", "crouch", "action", "walk", "conversation_yes", "conversation_no", "group_control_forwards", "group_control_back", "enter_exit", "vehicle_fire", "vehicle_secondary_fire", "vehicle_left", "vehicle_right", "steer_forward", "steer_back", "accelerate", "brake_reverse", "radio_next", "radio_previous", "radio_user_track_skip", "horn", "sub_mission", "handbrake", "vehicle_look_left", "vehicle_look_right", "vehicle_look_behind", "vehicle_mouse_look", "special_control_left", "special_control_right", "special_control_down", "special_control_up" } function isAControlAlreadyPushed( thecontrol ) -- check if a control is already pushed for k, v in pairs( pushedControls ) do if v[1] == thecontrol then return k end end return false end function readKeyPushed( ) for _, v in pairs( cs ) do -- for each control if getPedControlState( localPlayer, v ) then -- if the control is pressed if not isAControlAlreadyPushed( v ) then -- if the control wasn't already pressed table.insert( pushedControls, {v,getTickCount( )} ) -- insert the control in the pushedControls table end end end for key, v in pairs( pushedControls ) do -- for each line in pushedControls if not getPedControlState( localPlayer, v[1] ) then -- if the control isn't active anymore table.insert( r_table, {v[1],getTickCount()-v[2], v[2]-startTick} ) -- insert it in the table that will be returned like {controlName, pressedTime, startPressingDelay} table.remove( pushedControls, key ) -- remove it from de pushedControls table end end end function record( ) -- in order to start recording a path, you can try it by using /r if not recording then addEventHandler( "onClientPreRender", root, readKeyPushed ) recording = true startTick = getTickCount( ) local _elemToGetPosOf = localPlayer if isPedInVehicle( localPlayer ) then _elemToGetPosOf = getPedOccupiedVehicle( localPlayer ) end local x,y,z = getElementPosition( _elemToGetPosOf ) local rx, ry, rz = getElementRotation( _elemToGetPosOf ) positionTable = {x,y,z,rx,ry,rz} else removeEventHandler( "onClientPreRender", root, readKeyPushed ) recording = false setClipboard( toJSON(positionTable).." / "..toJSON(r_table) ) pushedControls = {} r_table = {} end end function toggleControlForTime( ped, control, time ) -- toggle a control for a certain time setPedControlState( ped, control, true ) setTimer( setPedControlState, time, 1, ped, control, false ) end function playRecord( pos, record, vehicle ) local ped = createPed( 0, 0, 0,0 ) if vehicle then theV = createVehicle( vehicle, unpack( pos ) ) warpPedIntoVehicle( ped, theV ) end for _, v in pairs( record ) do -- for each instruction in record table, we toggle the control for a certain time setTimer( toggleControlForTime, v[3], 1, ped, v[1], v[2] ) end setElementStreamable( ped, false ) setElementStreamable( theV, false ) -- because if elements aren't streamed in, they wont move return ped, theV end addCommandHandler("r",record ) playRecord( fromJSON( "[ [ 360.8201293945313, 2330.39404296875, 25.22904396057129, 359.6505126953125, 359.8719482421875, 128.6617431640625 ] ]" ), fromJSON( '[ [ [ "vehicle_left", 120, 578 ], [ "accelerate", 910, 419 ], [ "vehicle_left", 110, 1719 ], [ "accelerate", 1059, 1569 ], [ "accelerate", 492, 3069 ], [ "vehicle_right", 192, 3398 ], [ "vehicle_right", 250, 4179 ], [ "accelerate", 510, 4028 ], [ "vehicle_right", 230, 4979 ], [ "accelerate", 489, 4879 ], [ "vehicle_right", 179, 5449 ], [ "vehicle_right", 160, 6238 ], [ "accelerate", 740, 5989 ], [ "accelerate", 873, 7138 ], [ "vehicle_right", 89, 8309 ], [ "accelerate", 970, 8848 ], [ "accelerate", 800, 10539 ], [ "accelerate", 251, 12288 ], [ "vehicle_right", 120, 12719 ], [ "accelerate", 660, 13159 ], [ "accelerate", 199, 15180 ], [ "vehicle_right", 1011, 15618 ], [ "accelerate", 520, 16539 ], [ "vehicle_right", 630, 17229 ], [ "accelerate", 549, 17629 ], [ "vehicle_right", 301, 18428 ], [ "accelerate", 451, 18848 ], [ "accelerate", 929, 19769 ], [ "accelerate", 520, 21259 ], [ "vehicle_right", 188, 22580 ], [ "accelerate", 1069, 22839 ], [ "accelerate", 1389, 24709 ], [ "vehicle_right", 361, 26379 ], [ "accelerate", 462, 26778 ], [ "vehicle_right", 241, 27438 ], [ "accelerate", 1260, 27959 ], [ "vehicle_right", 709, 29869 ], [ "accelerate", 1010, 30518 ], [ "accelerate", 850, 32139 ], [ "accelerate", 751, 33488 ], [ "accelerate", 1013, 34579 ], [ "vehicle_right", 150, 36832 ], [ "accelerate", 960, 37241 ], [ "vehicle_left", 2119, 38762 ] ] ]' ), 470 ) -- here is a path I tried, again it's not 100% accurate, that's the prob I know it's a huge code, thanks for any help anyway Link to comment
MandaBraza Posted October 23, 2018 Share Posted October 23, 2018 (edited) Try to save the path into a XML using table.insert and onClientRender, should resolve. Edited October 23, 2018 by MandaBraza Link to comment
Gordon_G Posted October 23, 2018 Author Share Posted October 23, 2018 That's not actually the problem at all The path recording (when I use /r) seems really ok, the execution of the path is imprecise Link to comment
MandaBraza Posted October 23, 2018 Share Posted October 23, 2018 (edited) I tested your code, the car seems normal to me. I created a recorder sometime ago (the play record was made by my friend), and the car had the same delay problem. Maybe this is a problem from mta. Edited October 23, 2018 by MandaBraza Link to comment
Gordon_G Posted October 23, 2018 Author Share Posted October 23, 2018 Here is a video https://streamable.com/47oc2 I just added this at the end of my script : setTimer(playRecord, 3000, 5, fromJSON( "[ [ 360.8201293945313, 2330.39404296875, 25.22904396057129, 359.6505126953125, 359.8719482421875, 128.6617431640625 ] ]" ), fromJSON( '[ [ [ "vehicle_left", 120, 578 ], [ "accelerate", 910, 419 ], [ "vehicle_left", 110, 1719 ], [ "accelerate", 1059, 1569 ], [ "accelerate", 492, 3069 ], [ "vehicle_right", 192, 3398 ], [ "vehicle_right", 250, 4179 ], [ "accelerate", 510, 4028 ], [ "vehicle_right", 230, 4979 ], [ "accelerate", 489, 4879 ], [ "vehicle_right", 179, 5449 ], [ "vehicle_right", 160, 6238 ], [ "accelerate", 740, 5989 ], [ "accelerate", 873, 7138 ], [ "vehicle_right", 89, 8309 ], [ "accelerate", 970, 8848 ], [ "accelerate", 800, 10539 ], [ "accelerate", 251, 12288 ], [ "vehicle_right", 120, 12719 ], [ "accelerate", 660, 13159 ], [ "accelerate", 199, 15180 ], [ "vehicle_right", 1011, 15618 ], [ "accelerate", 520, 16539 ], [ "vehicle_right", 630, 17229 ], [ "accelerate", 549, 17629 ], [ "vehicle_right", 301, 18428 ], [ "accelerate", 451, 18848 ], [ "accelerate", 929, 19769 ], [ "accelerate", 520, 21259 ], [ "vehicle_right", 188, 22580 ], [ "accelerate", 1069, 22839 ], [ "accelerate", 1389, 24709 ], [ "vehicle_right", 361, 26379 ], [ "accelerate", 462, 26778 ], [ "vehicle_right", 241, 27438 ], [ "accelerate", 1260, 27959 ], [ "vehicle_right", 709, 29869 ], [ "accelerate", 1010, 30518 ], [ "accelerate", 850, 32139 ], [ "accelerate", 751, 33488 ], [ "accelerate", 1013, 34579 ], [ "vehicle_right", 150, 36832 ], [ "accelerate", 960, 37241 ], [ "vehicle_left", 2119, 38762 ] ] ]' ), 470 ) That's very strange Maybe it has something to do with the client's framerate ? I don't really know Link to comment
Moderators IIYAMA Posted October 23, 2018 Moderators Share Posted October 23, 2018 The frame rate is indeed a factor. Also the code runs on different place in the memory. The timing can be variable. You can smooth or force the key pressing a bit with: https://wiki.multitheftauto.com/wiki/SetPedAnalogControlState You can also use that to calculate the amount of steering from point to point. (that is if you want to go a level higher) Link to comment
Gordon_G Posted October 23, 2018 Author Share Posted October 23, 2018 Well, the analog control state could've help me if i was pressing my analog in different state during the record What do you mean by the amount of steering ? What function could I use ? Thanks for your help @IIYAMA Link to comment
Gordon_G Posted October 23, 2018 Author Share Posted October 23, 2018 (edited) I updated the code by removing all the setTimer to use a custom timer system made with onClientRender instead, here is the result : https://streamable.com/w0z77 As you can see, in the first time everything is good, but because i'm recording my fps drop suddenly and all the next cars's trajectory are wrong Also, when i'm trying it without recording (constantly 100fps) everything is good, trajectory is almost perfect for every vehicle So, the system is all good, the problem now is about the client perfomance, if he has a drop, the entire trajectory will be :O*d and that's a big issue Should I sync it serverside ? Would it be efficient ? Edited October 23, 2018 by Gordon_G Link to comment
MandaBraza Posted October 23, 2018 Share Posted October 23, 2018 Just now, Gordon_G said: I updated the code by removing all the setTimer to use a custom timer system made with onClientRender instead, here is the result : https://streamable.com/w0z77 As you can see, in the first time everything is good, but because i'm recording my fps drop suddenly and all the next cars's trajectory are wrong Also, when i'm trying it without recording (constantly 100fps) everything is good, trajectory is almost perfect for every vehicle So, the system is all good, the problem now is about the client perfomance, if he has a drop, the entire trajectory will be :O*d and that's a big issue Should I sync it serverside ? Would it be efficient ? Show the updated code, maybe can i integrate him with part of my code and solve this. I'm still think we can solve that using XML. Link to comment
Gordon_G Posted October 23, 2018 Author Share Posted October 23, 2018 (edited) XML has nothing to do with it, really It's just a way to store the JSON, that's not the actual problem, the actual problem is about syncing in my opinion local r_table = {} local startTick = 0 local pushedControls = {} -- {pushed control, forhowmuchtime, when it start to push} local recording = false local cs = { "fire", "aim_weapon", "next_weapon", "previous_weapon", "forwards", "backwards", "left", "right", "zoom_in", "zoom_out", "change_camera", "jump", "sprint", "look_behind", "crouch", "action", "walk", "conversation_yes", "conversation_no", "group_control_forwards", "group_control_back", "enter_exit", "vehicle_fire", "vehicle_secondary_fire", "vehicle_left", "vehicle_right", "steer_forward", "steer_back", "accelerate", "brake_reverse", "radio_next", "radio_previous", "radio_user_track_skip", "horn", "sub_mission", "handbrake", "vehicle_look_left", "vehicle_look_right", "vehicle_look_behind", "vehicle_mouse_look", "special_control_left", "special_control_right", "special_control_down", "special_control_up" } local controlPlayingOrder = { } -- {ped,control, whenItStop(tick)} local eventPlaying = false local customTimer_ = { event = false, timers = {}, } function customTimerEvent( ) for k, v in pairs( customTimer_.timers ) do if getTickCount( ) >= v[1] then v[2](unpack( v[3] )) table.remove( customTimer_.timers, k ) end end if #customTimer_.timers == 0 then removeEventHandler( "onClientRender", root, customTimerEvent ) customTimer_.event = false end end function customTimer( time, func, ... ) table.insert( customTimer_.timers, { getTickCount( )+time, func, {...} } ) if not customTimer_.event then addEventHandler( "onClientRender", root, customTimerEvent ) customTimer_.event = true end end function isAControlAlreadyPushed( thecontrol ) for k, v in pairs( pushedControls ) do if v[1] == thecontrol then return k end end return false end function readKeyPushed( ) for _, v in pairs( cs ) do if getPedControlState( localPlayer, v ) then if not isAControlAlreadyPushed( v ) then table.insert( pushedControls, {v,getTickCount( )} ) end end end for key, v in pairs( pushedControls ) do if not getPedControlState( localPlayer, v[1] ) then table.insert( r_table, {v[1],getTickCount()-v[2], v[2]-startTick} ) table.remove( pushedControls, key ) end end end function record( ) if not recording then addEventHandler( "onClientRender", root, readKeyPushed ) recording = true startTick = getTickCount( ) local _elemToGetPosOf = localPlayer if isPedInVehicle( localPlayer ) then _elemToGetPosOf = getPedOccupiedVehicle( localPlayer ) end local x,y,z = getElementPosition( _elemToGetPosOf ) local rx, ry, rz = getElementRotation( _elemToGetPosOf ) positionTable = {x,y,z,rx,ry,rz} else removeEventHandler( "onClientRender", root, readKeyPushed ) recording = false iprint( r_table ) setClipboard( toJSON(positionTable).." / "..toJSON(r_table) ) pushedControls = {} r_table = {} end end function toggleControlForTime( ped, control, time ) setPedControlState( ped, control, true ) customTimer( time, setPedControlState, ped, control, false ) end function playRecord( pos, record, vehicle ) local ped = createPed( 0, 0, 0,0 ) if vehicle then theV = createVehicle( vehicle, unpack( pos ) ) warpPedIntoVehicle( ped, theV ) end for _, v in pairs( record ) do customTimer( v[3], toggleControlForTime, ped, v[1], v[2] ) end setElementStreamable( ped, false ) setElementStreamable( theV, false ) return ped, theV end addCommandHandler("r",record ) setTimer(playRecord,2000,20,fromJSON("[ [ 186.5562286376953, 2413.163818359375, 16.26820373535156, 0.4193115234375, 0.012939453125, 317.32275390625 ] ]"), fromJSON('[ [ [ "accelerate", 1748, 588 ], [ "vehicle_right", 1261, 2875 ], [ "vehicle_right", 100, 4346 ], [ "accelerate", 921, 3655 ], [ "accelerate", 90, 4655 ], [ "accelerate", 449, 4966 ], [ "vehicle_left", 1419, 5686 ], [ "accelerate", 1269, 6966 ], [ "vehicle_left", 1710, 8765 ], [ "accelerate", 1711, 10075 ], [ "vehicle_right", 2101, 12025 ] ] ]'),470) Edited October 23, 2018 by Gordon_G Link to comment
MandaBraza Posted October 24, 2018 Share Posted October 24, 2018 (edited) I really dont know what is happening with your code. I tried to adapt but nothing works. Here mine version: Spoiler local fileName = "path.xml" local tagName = "root" local childName = "vehicle" local playrec = PlayRec.create() controlTable = {"accelerate", "brake_reverse", "handbrake", "vehicle_secondary_fire", "vehicle_left", "vehicle_right"} local savePos = {} function record() local vehicle = getPedOccupiedVehicle(localPlayer) local x, y, z = getElementPosition(vehicle) local rx, ry, rz = getElementRotation(vehicle) local model = getElementModel(vehicle) idk = { model = model, x = x, y = y, z = z, rx = rx, ry = ry, rz = rz } for i, state in ipairs (controlTable) do local b = getPedControlState(state) idk[state] = (b and '1' or '0') end table.insert(savePos, idk) end function alo() local loadFile = xmlLoadFile("path.xml", "root") if not (loadFile) then loadFile = xmlCreateFile("path.xml", "root") end for i, v in ipairs(savePos) do local createChild = xmlCreateChild(loadFile, "vehicle") xmlNodeSetAttribute(createChild, "model", v.model) xmlNodeSetAttribute(createChild, "x", v.x) xmlNodeSetAttribute(createChild, "y", v.y) xmlNodeSetAttribute(createChild, "z", v.z) xmlNodeSetAttribute(createChild, "rx", v.rx) xmlNodeSetAttribute(createChild, "ry", v.ry) xmlNodeSetAttribute(createChild, "rz", v.rz) for i, state in ipairs (controlTable) do xmlNodeSetAttribute(createChild, state, v[state]) end end xmlSaveFile(loadFile) xmlUnloadFile(loadFile) end addCommandHandler("rsave", alo) addCommandHandler("rec", function() outputChatBox("recording") addEventHandler("onClientRender", root, record) end) addCommandHandler("rs", function() outputChatBox("record stoped") removeEventHandler("onClientRender", root, record) end) addCommandHandler("play", function() if not (playrec:load("path.xml")) then outputChatBox("error to load rec") else outputChatBox("loading rec") end playrec:start() end) Spoiler PlayRec = {} PlayRec.__index = PlayRec PlayRec.controlTable = {"accelerate", "brake_reverse", "handbrake", "vehicle_secondary_fire", "vehicle_left", "vehicle_right"} function PlayRec.create() local a = {} setmetatable(a, PlayRec) a.playing = false a.currentRow = 1 a.recordInfo = {} a.lastInfo = {} a.loop = true return a end function PlayRec:load(file) if not (file) then return false end local pathNode = xmlLoadFile(file) if(pathNode) then local vehicleNode = xmlFindChild(pathNode, "vehicle", 0 ) if(vehicleNode) then local i = 1 local recordInfo = {} while vehicleNode do local model = tonumber(xmlNodeGetAttribute(vehicleNode, "model")) local pos = {tonumber(xmlNodeGetAttribute(vehicleNode, "x")), tonumber(xmlNodeGetAttribute(vehicleNode, "y")), tonumber(xmlNodeGetAttribute(vehicleNode, "z"))} local rot = {tonumber(xmlNodeGetAttribute(vehicleNode, "rx")), tonumber(xmlNodeGetAttribute(vehicleNode, "ry")), tonumber(xmlNodeGetAttribute(vehicleNode, "rz"))} local keys = {} for i, key in ipairs (PlayRec.controlTable) do if (tostring(xmlNodeGetAttribute(vehicleNode, key))) then keys[key] = tonumber(xmlNodeGetAttribute(vehicleNode, key)) end end table.insert(recordInfo, {model, pos, rot, keys}) vehicleNode = xmlFindChild(pathNode, "vehicle", i) i = i + 1 end self.recordInfo = recordInfo return true end end return false end function PlayRec:start(data) if not (self.vehicle) then self.ped = createPed(0, 0, 0, 0) self.vehicle = createVehicle(411, 0, 0, 0) warpPedIntoVehicle(self.ped, self.vehicle) end self.startTick = getTickCount() self.updateFunction = function () self.time = (getTickCount() - self.startTick) self:update() end self.keys = {} self.playing = true addEventHandler("onClientPreRender", root, self.updateFunction) end function PlayRec:stop() removeEventHandler("onClientPreRender", root, self.updateFunction) self.playing = false self.currentRow = 1 self.recordInfo = {} self.loop = true destroyElement(self.vehicle) destroyElement(self.ped) end function PlayRec:update() local offX, offY, offZ = 0,0,0 local r = self.recordInfo[self.currentRow] local x,y,z = r[2][1] or 0, r[2][2] or 0, r[2][3] or 0 local rx, ry, rz = r[3][1] or 0, r[3][2] or 0, r[3][3] or 0 local vx, vy, vz = r[4][1] or 0, r[4][2] or 0, r[4][3] or 0 setElementPosition(self.vehicle, x + offX,y + offY, z + offZ, false) setElementRotation(self.vehicle, rx, ry, rz, "default", true) if (r[1]) then setElementModel(self.vehicle, r[1]) end if (self.currentRow == #self.recordInfo) then self.currentRow = 1 else self.currentRow = self.currentRow + 1 end end function PlayRec:isPlaying() return self.playing end Edited October 24, 2018 by MandaBraza Link to comment
Moderators IIYAMA Posted October 24, 2018 Moderators Share Posted October 24, 2018 (edited) 8 hours ago, Gordon_G said: Well, the analog control state could've help me if i was pressing my analog in different state during the record What do you mean by the amount of steering ? What function could I use ? Thanks for your help @IIYAMA If you look carefully in the video to the first few cars that driving past, you can clearly see that the wheels are steering with 100% to the left and the right. Which makes it look very unnatural. With the set analog function, you can also steer 30% to the right or the left. But remember: controlstates are an indirect method to control an ped or car. They do not adjust the orientation of elementen, they are actions to behave like it. The outcome can be entirely different depending on a lot of factors. One last thing: from 0 t/m 100 steering cost time. Edited October 24, 2018 by IIYAMA Link to comment
Gordon_G Posted October 24, 2018 Author Share Posted October 24, 2018 Yeah, of course controlstates are not 100% trustable and that's the problem Maybe should I attach the vehicle to an object that is moving with moveObject but keep the control states in order to look realistic ? That's a good question Quote One last thing: from 0 t/m 100 steering cost time. I didn't understand this sentence to be honest Link to comment
Gordon_G Posted October 24, 2018 Author Share Posted October 24, 2018 I updated the code in order to correct the path if it gones wrong Here is the experiment in 50 fps : https://streamable.com/06nwn Here is the experiment in ~80 fps : https://streamable.com/c0vq0 new code : local r_table = {} local r2_table = {} -- contains positions local startTick = 0 local pushedControls = {} -- {pushed control, forhowmuchtime, when it start to push} local recording = false local cs = { "fire", "aim_weapon", "next_weapon", "previous_weapon", "forwards", "backwards", "left", "right", "zoom_in", "zoom_out", "change_camera", "jump", "sprint", "look_behind", "crouch", "action", "walk", "conversation_yes", "conversation_no", "group_control_forwards", "group_control_back", "enter_exit", "vehicle_fire", "vehicle_secondary_fire", "vehicle_left", "vehicle_right", "steer_forward", "steer_back", "accelerate", "brake_reverse", "radio_next", "radio_previous", "radio_user_track_skip", "horn", "sub_mission", "handbrake", "vehicle_look_left", "vehicle_look_right", "vehicle_look_behind", "vehicle_mouse_look", "special_control_left", "special_control_right", "special_control_down", "special_control_up" } local eventPlaying = false local customTimer_ = { event = false, timers = {}, } function customTimerEvent( ) for k, v in pairs( customTimer_.timers ) do if getTickCount( ) >= v[1] then v[2](unpack( v[3] )) table.remove( customTimer_.timers, k ) end end if #customTimer_.timers == 0 then removeEventHandler( "onClientRender", root, customTimerEvent ) customTimer_.event = false end end function customTimer( time, func, ... ) table.insert( customTimer_.timers, { getTickCount( )+time, func, {...} } ) if not customTimer_.event then addEventHandler( "onClientRender", root, customTimerEvent ) customTimer_.event = true end end function table.contains( t, d ) for k, v in pairs( t ) do if v == d then return k end end return false end function isAControlAlreadyPushed( thecontrol ) for k, v in pairs( pushedControls ) do if v[1] == thecontrol then return k end end return false end function isPedInPosition( ped, position ) if isElement( ped ) then local x,y,z = getElementPosition( ped ) local rot = getPedRotation( ped ) local x1,y1,z1,rot1 = unpack( position ) if not (getDistanceBetweenPoints3D( x,y,z,x1,y1,z1 ) <= 1.5) then if isPedInVehicle( ped ) then --destroyElement( getPedOccupiedVehicle( ped ) ) setElementPosition( getPedOccupiedVehicle( ped ), x1,y1,z1 ) setElementRotation( getPedOccupiedVehicle( ped ), 0,0,rot1 ) end --destroyElement( ped ) iprint( "Ped set to the good position (dist:".. getDistanceBetweenPoints3D( x,y,z,x1,y1,z1 )..")" ) --setElementPosition( localPlayer, x1,y1,z1 ) end end end function readKeyPushed( ) for _, v in pairs( cs ) do if getPedControlState( localPlayer, v ) then if not isAControlAlreadyPushed( v ) then table.insert( pushedControls, {v,getTickCount( )} ) end end end for key, v in pairs( pushedControls ) do if not getPedControlState( localPlayer, v[1] ) then table.insert( r_table, {v[1],getTickCount()-v[2], v[2]-startTick} ) local x,y,z = getElementPosition( localPlayer ) table.insert( r2_table, {x,y,z,getPedRotation( localPlayer ),getTickCount( )-startTick} ) table.remove( pushedControls, key ) end end end function record( ) if not recording then addEventHandler( "onClientRender", root, readKeyPushed ) recording = true startTick = getTickCount( ) local _elemToGetPosOf = localPlayer if isPedInVehicle( localPlayer ) then _elemToGetPosOf = getPedOccupiedVehicle( localPlayer ) end local x,y,z = getElementPosition( _elemToGetPosOf ) local rx, ry, rz = getElementRotation( _elemToGetPosOf ) positionTable = {x,y,z,rx,ry,rz} else removeEventHandler( "onClientRender", root, readKeyPushed ) recording = false setClipboard( "fromJSON('"..toJSON(positionTable).."'),fromJSON('"..toJSON(r_table).."'),fromJSON('"..toJSON(r2_table).."')" ) pushedControls = {} r_table = {} end end function toggleControlForTime( ped, control, time ) if isElement( ped ) then setPedControlState( ped, control, true ) customTimer( time, setPedControlState, ped, control, false ) end end function playRecord( pos, record, positions, vehicle ) local ped = createPed( 0, 0, 0,0 ) if vehicle then theV = createVehicle( vehicle, unpack( pos ) ) warpPedIntoVehicle( ped, theV ) end for _, v in pairs( record ) do customTimer( v[3], toggleControlForTime, ped, v[1], v[2] ) end for _, v in pairs( positions ) do customTimer( v[5], isPedInPosition, ped, {v[1],v[2],v[3],v[4]} ) end setElementStreamable( ped, false ) setElementStreamable( theV, false ) return ped, theV end addCommandHandler("r",record ) playRecord( fromJSON('[ [ -796.2457275390625, 1579.151977539063, 26.79252433776855, 359.9898681640625, 0.088134765625, 90.22314453125 ] ]'),fromJSON('[ [ [ "vehicle_right", 1309, 1319 ], [ "vehicle_right", 100, 2859 ], [ "vehicle_right", 80, 3159 ], [ "accelerate", 2489, 889 ], [ "vehicle_left", 270, 3929 ], [ "accelerate", 650, 3728 ], [ "vehicle_left", 781, 4218 ], [ "vehicle_left", 211, 5068 ], [ "vehicle_left", 280, 5388 ], [ "vehicle_left", 120, 5838 ], [ "accelerate", 1430, 4618 ], [ "vehicle_right", 131, 6318 ], [ "accelerate", 339, 6409 ], [ "accelerate", 501, 7228 ], [ "accelerate", 69, 7879 ], [ "vehicle_right", 841, 7588 ], [ "vehicle_left", 59, 9039 ], [ "vehicle_right", 79, 9399 ], [ "vehicle_right", 81, 10428 ], [ "accelerate", 2750, 8229 ], [ "vehicle_left", 70, 11799 ], [ "vehicle_left", 320, 12879 ], [ "vehicle_left", 151, 13418 ], [ "accelerate", 2400, 11199 ], [ "vehicle_left", 920, 13679 ], [ "vehicle_left", 60, 14789 ], [ "vehicle_left", 80, 15078 ], [ "vehicle_right", 91, 15668 ], [ "vehicle_right", 70, 16308 ], [ "vehicle_right", 129, 16749 ], [ "vehicle_right", 130, 17308 ], [ "vehicle_right", 119, 17579 ], [ "vehicle_right", 160, 18039 ], [ "vehicle_right", 100, 18338 ], [ "vehicle_right", 100, 18589 ], [ "vehicle_right", 120, 18888 ], [ "vehicle_right", 131, 19468 ], [ "vehicle_right", 150, 19719 ], [ "vehicle_right", 69, 20029 ], [ "accelerate", 6250, 14068 ], [ "accelerate", 629, 20699 ], [ "brake_reverse", 410, 22009 ], [ "vehicle_right", 110, 22888 ], [ "vehicle_right", 230, 23438 ], [ "vehicle_right", 359, 23799 ], [ "vehicle_right", 340, 24278 ], [ "vehicle_right", 110, 24798 ], [ "accelerate", 2539, 22629 ], [ "accelerate", 660, 25619 ], [ "accelerate", 600, 26479 ], [ "vehicle_left", 2100, 25479 ], [ "accelerate", 359, 27519 ], [ "accelerate", 329, 28369 ], [ "vehicle_left", 1081, 27698 ], [ "accelerate", 160, 29069 ], [ "vehicle_left", 419, 28840 ], [ "brake_reverse", 401, 29498 ], [ "vehicle_left", 201, 29708 ] ] ]'),fromJSON('[ [ [ -805.332763671875, 1586.018920898438, 26.63676834106445, 17.76824951171875, 2628 ], [ -805.7278442382813, 1590.235595703125, 26.65402030944824, 6.111785888671875, 2959 ], [ -805.9424438476563, 1594.342529296875, 26.64418029785156, 2.92852783203125, 3239 ], [ -805.977294921875, 1596.57177734375, 26.64223480224609, 1.303558349609375, 3378 ], [ -806.4583740234375, 1607.8291015625, 26.65570831298828, 6.170013427734375, 4199 ], [ -807.1010131835938, 1610.39599609375, 26.65960502624512, 13.30154418945313, 4378 ], [ -811.9795532226563, 1616.3564453125, 26.65828323364258, 51.98773193359375, 4999 ], [ -815.5377197265625, 1617.900268554688, 26.65497398376465, 67.28717041015625, 5279 ], [ -821.5682373046875, 1619.058227539063, 26.65280342102051, 82.38897705078125, 5668 ], [ -826.6240844726563, 1619.147216796875, 26.65061950683594, 89.57000732421875, 5958 ], [ -828.2620849609375, 1619.061767578125, 26.65007781982422, 91.87484741210938, 6048 ], [ -834.685791015625, 1618.864135742188, 26.64398574829102, 90.49261474609375, 6449 ], [ -839.3173217773438, 1619.13330078125, 26.65044975280762, 87.17523193359375, 6748 ], [ -851.8325805664063, 1619.816772460938, 26.63486480712891, 85.52615356445313, 7729 ], [ -854.6199340820313, 1620.459716796875, 26.63213920593262, 77.11703491210938, 7948 ], [ -858.570068359375, 1623.577392578125, 26.63924980163574, 44.42379760742188, 8429 ], [ -863.0845336914063, 1630.6728515625, 26.65344047546387, 33.3341064453125, 9098 ], [ -866.5885620117188, 1635.771850585938, 26.6611270904541, 34.11697387695313, 9478 ], [ -877.727783203125, 1653.282958984375, 26.71584129333496, 31.97711181640625, 10509 ], [ -883.3809814453125, 1662.869750976563, 26.78210639953613, 30.56112670898438, 10979 ], [ -893.9291381835938, 1680.693359375, 26.9169807434082, 30.95782470703125, 11869 ], [ -913.4273681640625, 1710.665649414063, 27.07010078430176, 39.35479736328125, 13199 ], [ -920.779541015625, 1718.41162109375, 27.35814666748047, 45.32049560546875, 13569 ], [ -921.4205932617188, 1719.004516601563, 27.39833068847656, 46.22787475585938, 13599 ], [ -943.166259765625, 1729.1845703125, 29.11658668518066, 85.14321899414063, 14599 ], [ -949.1246337890625, 1729.225708007813, 29.44645118713379, 89.859375, 14849 ], [ -956.7573852539063, 1729.057495117188, 29.7934455871582, 91.652587890625, 15158 ], [ -972.1607055664063, 1728.269897460938, 30.27086639404297, 92.42922973632813, 15759 ], [ -989.0933837890625, 1727.961791992188, 30.54391288757324, 90.70236206054688, 16378 ], [ -1003.445617675781, 1728.112548828125, 30.66239166259766, 88.289306640625, 16878 ], [ -1020.304504394531, 1729.227294921875, 30.72439575195313, 85.0517578125, 17438 ], [ -1028.371704101563, 1730.229614257813, 30.74590301513672, 81.92257690429688, 17698 ], [ -1044.19140625, 1733.105224609375, 30.91395950317383, 78.12490844726563, 18199 ], [ -1051.878662109375, 1735.0224609375, 31.01696968078613, 75.20703125, 18438 ], [ -1059.918823242188, 1737.432373046875, 31.22837257385254, 72.75799560546875, 18689 ], [ -1070.129638671875, 1740.948852539063, 31.47385025024414, 69.90228271484375, 19008 ], [ -1088.964111328125, 1748.553833007813, 32.16135025024414, 66.6500244140625, 19599 ], [ -1097.473266601563, 1752.637573242188, 32.54501724243164, 63.03485107421875, 19869 ], [ -1104.526733398438, 1756.55078125, 33.07957077026367, 60.58380126953125, 20098 ], [ -1111.20263671875, 1760.481689453125, 33.70774078369141, 59.54116821289063, 20318 ], [ -1137.177734375, 1775.804321289063, 37.64555740356445, 59.4051513671875, 21328 ], [ -1157.318969726563, 1787.602783203125, 39.48288726806641, 58.85409545898438, 22419 ], [ -1161.880249023438, 1790.397583007813, 39.76374435424805, 58.04330444335938, 22998 ], [ -1168.527954101563, 1795.216674804688, 39.73713302612305, 51.62118530273438, 23668 ], [ -1173.45458984375, 1801.013427734375, 39.86912155151367, 35.18539428710938, 24158 ], [ -1176.539184570313, 1808.35400390625, 40.42601776123047, 16.12677001953125, 24618 ], [ -1177.422119140625, 1813.42236328125, 40.66091918945313, 9.2940673828125, 24908 ], [ -1177.903686523438, 1818.196411132813, 40.86849212646484, 6.352996826171875, 25168 ], [ -1183.175048828125, 1832.953247070313, 41.28326416015625, 41.78341674804688, 26279 ], [ -1192.722534179688, 1835.13525390625, 41.39749908447266, 95.81304931640625, 27079 ], [ -1197.140258789063, 1832.212524414063, 41.41450500488281, 132.6832885742188, 27579 ], [ -1198.770751953125, 1829.544555664063, 41.4027214050293, 146.880859375, 27878 ], [ -1198.45166015625, 1823.58056640625, 41.40799713134766, 197.0721893310547, 28698 ], [ -1198.13232421875, 1823.118774414063, 41.41462326049805, 202.3166656494141, 28779 ], [ -1196.57421875, 1821.475341796875, 41.40635681152344, 220.3708801269531, 29229 ], [ -1196.4541015625, 1821.397216796875, 41.40636444091797, 221.7097320556641, 29259 ], [ -1196.094970703125, 1821.056884765625, 41.40655899047852, 223.3982086181641, 29899 ], [ -1196.120727539063, 1821.076293945313, 41.4063720703125, 223.1853790283203, 29909 ] ] ]'), 516 ) Link to comment
Moderators IIYAMA Posted October 24, 2018 Moderators Share Posted October 24, 2018 6 hours ago, Gordon_G said: I didn't understand this sentence to be honest In the real world it cost time to steer from 0° to 45° degrees right? If they didn't apply the same principle in gta san, where ever you were to turn right/left your car would simply rollover. (Just like a dog would do, when he has to earn his candy) So they decided to do this if you were to press your left arrow. This wheel animation is time as well as fps related. Link to comment
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now