Facepunch / garrysmod-requests

Feature requests for Garry's Mod
85 stars 24 forks source link

Lua access to vehicle params (control, operating, etc.) #453

Closed EstevanTH closed 8 years ago

EstevanTH commented 9 years ago

Hi Rubat and co,

As I'm in fond of vehicle modding and scripting, I would like something very special, which does not seem really easy to make.

I would like to have a read/write access to vehicles internal values contained in a few struct elements. They all are from mp/src/public/vphysics/vehicles.h. These are used as public properties of the IPhysicsVehicleController class so a set of Lua accessor functions / methods should be easy to make.

Especially I would need a read/write access to:

A read-only access may be useful for some data, I let you see.

Examples of features that could be allowed:

Thanks!

robotboy655 commented 9 years ago

I already have most of that done, just need to commit it.

As far as I am aware though, RPM and gears are fake in the engine, so you can't make use of it.

thegrb93 commented 9 years ago

This will be cool.

EstevanTH commented 9 years ago

I could not understand what makes them work but at least gears are really simulated. Each gear produces a different constant acceleration / torque value (depending on all transmission settings), which is then modified by physics parameters (drag, etc.).

My bus has advanced engine sounds based on clientside calculated RPM + gears. :stuck_out_tongue:

local D5 = 20 -- reference wheel radius (identical front & rear)
local F5 = 2*math.pi*D5 -- reference wheel circumference
local B2 = 552.9790039063 -- reference speed
local C5 = 3.2 -- reference gear ratio
local B5 = 4.5 -- reference axleratio
local E7 = B2*C5*B5/F5 -- reference RPM/a
local A5 = 3800 -- reference shiftuprpm
local ref = A5/E7 -- ref: constant ratio

local B10 = script_data["vehicle"]["axle"]["wheel"]["radius"]
local B12 = 2*math.pi*B10
local B11 = script_data["vehicle"]["axle2"]["wheel"]["radius"]
local B13 = 2*math.pi*B11
local B9 = script_data["vehicle"]["engine"]["axleratio"]
local fix = 0.5*B9*((1/B12)+(1/B13))
script_data["calculated"]["ratio"] = ref*fix

RPM = data["ratio"] * data["gears"][gear] * math.abs(speed) -- speed is in in/s
robotboy655 commented 9 years ago

@EstevanTH , I looked into the gears stuff, they only affect sounds and nothing else.

EstevanTH commented 9 years ago

I have not found where the gears affect the acceleration either. But I can prove that my formula works: it is based on precise acceleration and velocity measurements. But to be honest I have not found at all where the torque or the force is applied... Maybe it's because I do not understand the CFourWheelVehiclePhysics class well enough.

robotboy655 commented 9 years ago

Dude, even the variable itself is called m_SoundGears. Acceleration in Source vehicles is linear, as is the RPM.

RPM doesn't even work properly, for example TDM cars.

But I bet this can be rectified with Lua to some extent once I add the bindings in.

EstevanTH commented 9 years ago

Rubat, look into the Jeep vehicle script. You have the gears configured in the "engine" category, these are used for physics simulation. And you have the gears configured in the "vehicle_sounds" category, these are used for sound selection.

If you are motivated, you can try something: use a vehicle with a well configured gearbox (my bus for instance). Modify the vehicle script to disable automatic transmission (no it's not a urban legend). And try to override the gear to 6. You should see that the bus does not have a correct acceleration while it does with the gear 1. Beware not to over-rev, otherwise the acceleration will get crazy (see the MaxRPM setting). You can do the same with the Jeep (the Jeep only has 5 gears).

If you measure the acceleration with my bus, you will see that it's very accurate. The HL2 Jeep only uses the gears 1 and 2 because the gearbox is not properly configured.

This code works well serverside but there may be noise that may be filtered. I tried it clientside and it adds a horrible big noise over the measurements (I think I failed).

local previous_velocity = 0.0
local previous_time = 0.0
hook.Add( "Tick", "vehicle_acceleration_measure", function()
    local veh = ents.FindByClass( "prop_vehicle*" )[1]
    if IsValid( veh ) then
        local velocity = veh:GetVelocity():Length()
        local current_time = CurTime()
        local acceleration = math.Round( ( ( velocity - previous_velocity ) / ( current_time - previous_time ) ) * 0.0254, 3 )
        local message = "Acceleration = "..acceleration.." m/s²"
        for _,ply in pairs( player.GetAll() ) do
            ply:ChatPrint( message )
        end
        previous_velocity = velocity
        previous_time = current_time
    end
end )

I am not at ease enough with the Source SDK for now so I can't give as many details as I want. But the proof is here, and there is no cheat in it.

robotboy655 commented 9 years ago

"Your bus" is not exactly helpful. Is it a workshop addon? Can you give me a link so I can take a closer look?

I tried messing around with gears in vehicle script for Jeep, and changing changing anything had no effect what so ever, not the auto/manual gearbox, not anything other than first gear had any effect.

EstevanTH commented 9 years ago

Okay. :disappointed: Good luck for attempts with my bus.

Workshop links, also available through an SVN repository (see in description): [MR] Temsa Opalin 9 [MR] Shared Textures & Scripts

handsomematt commented 9 years ago

Not sure what you have and haven't implemented robotboy655 but like I said in the other issue, these would be great to have:

Binding most of CFourWheelServerVehicle would be pretty neat so functions like:

IsVehicleUpright()
IsVehicleBodyInWater()
GetVehicleParams()
GetVehicleControlParams()
GetVehicleOperatingParams()
robotboy655 commented 9 years ago

No need to repeat the same things over and over again, I have a lot of vehicle stuff to be committed, but It will have to wait until we push the update.

robotboy655 commented 9 years ago

I guess the gears and RPM actually do work, but only if the vehicle script is correct, which they are surprisingly not for default HL2 vehicles.

The Vehicle.GetOperatingParams() on server returns the physics based RPM and gear.

EstevanTH commented 9 years ago

Hi Rubat, I'll give a try with operating parameters very soon. But for now I just figured out that there is no Vehicle:SetGear() method, so there still is no way to shift gears with manual gearboxes. Of course it only make sense if "autotransmission" is set to "0".

By the way, do the methods Vehicle:GetRPM(), Vehicle:IsBoosting(), Vehicle:GetSpeed(), Vehicle:GetSteering() point to the same parameters as in OperatingParams Structure?

robotboy655 commented 9 years ago

There's no manual gearbox, or any gearbox controls exposed to the engine, all of the vehicle physics are done in the vphysics.dll.

Internally those methods just call C++ vehicle functions with the same name.

EstevanTH commented 9 years ago

Okay so this means that the gear value from OperatingParams Structure only contains the result of the VPhysics gearbox processing, which is copied somewhere. So the only possible usage of "autotransmission" is preventing gears over 1, as defined in the Source SDK engine. :disappointed: So if I understand properly, attempting to replace the gear value(s) available in the engine will be ignored by the simulation, whether the gearbox is auto or manual. Thanks! :smiley:

EstevanTH commented 9 years ago

Unlike the RPM saved value (returned by Entity:GetSaveTable()), I can confirm that Vehicle:GetRPM() works fine and matches with the gear settings of my bus. The RPM saved value is highly buggy and it is clamped to 4095. The engine simulates the RPM in a weird way. I just tested the feature, and I could see negative values (transition between backward and forward). Also the reverse max speed limiter forces the RPM to 0 when it tries to brake the wheels (which does not work).

lua_run hook.Add('Think', 'rpm_test', function() local veh=ents.FindByClass('prop_vehicle*')[1] player.GetAll()[1]:ChatPrint(veh:GetRPM()) end)

Now let me check the gear.

lua_run hook.Add('Think', 'rpm_test', function() local veh_op=ents.FindByClass('prop_vehicle*')[1]:GetOperatingParams() player.GetAll()[1]:ChatPrint(veh_op.gear..' '..veh_op.RPM) end)

The gear is okay for both the Half-Life 2 Jeep and for my bus. The special part is that the gear that you would call naturally 1 is called 0 in the engine. Just do a +1 operation to get the real-life gear number. Of course a manual gearbox will always display 0 for the gear, but also for the RPM: it's 100% constant torque (I guess) based on axle ratio, 1st gear ratio and horsepower. The maximum of 4095 rpm displayed in the Source SDK does not matter, as I think it is only used to clamp the (useless) RPM saved value; but physics tests are required to get 100% sure of that.