Jump to content

Path recorder for a vehicle


Gordon_G

Recommended Posts

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

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

The frame rate is indeed a factor. Also the code runs on different place in the memory. The timing can be variable.

 

Link to comment

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 by Gordon_G
Link to comment
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

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 by Gordon_G
Link to comment

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 by MandaBraza
Link to comment
  • Moderators
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 by IIYAMA
Link to comment

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

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
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)

 

images?q=tbn:ANd9GcQ1dFq6KKouF91EIAXMDmA

 

 

 

giphy.gif

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

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
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...