Lethal Company Sim Cruiser (G25)
- 5 Devlogs
- 10 Total hours
A Lethal Company Mod that makes the Company Cruiser compatible with the Logitech G25 Sim Steering Wheel!
A Lethal Company Mod that makes the Company Cruiser compatible with the Logitech G25 Sim Steering Wheel!
After I got the steering working, I wanted to be able to use the G25’s shifter to change gears in the company cruiser. This required more expirimenting to figure out how the shifter is interpreted by unity’s input system.
It turns out that every position on the shifter is assigned a button, and that button is considered pressed when the shifter is in that gear. Below are the button assignements I found:
In 6 Gear Mode
I also took a look at how the player sets the cruiser’s gears, and it’s with a method called ShiftToGearAndSync(desiredGear). So when changing gears this is the method I need to call.
Getting the shifting working was pretty easy. First I created 2 new actions and bindings for the Drive and Reverse gears and bound then to the 3rd and 4th gears on the shifter. I chose those as it keep it centered and feels more natural.
Then I added some code into the same method we edited for the steering that:
So in our case, what IRL is neutral is park, forward (or 3rd) is drive and back (or 4th) is reverse.
Feels pretty epic when driving the cruiser!
The mod is basically done, but there are a few things we can still do:
Cheers!
Liam
Finished re-writing the cruiser’s steering!Not too much to say, but still a pretty big update: The cruiser’s steering wheel is now 1:1 with the physical G25 in multiple ways.
Originally the Company Cruiser was driven by holding down the A or D keys to steer. The wheel would gradually rotate in the direction you were holding and stop rotating but maintain the rotation on release. This logic obviously sucks when you want to use a sim wheel, because you want the CC’s wheel rotation to be a direct replica of the physical wheel’s rotation.
This means the logic had to be redone, therefore a rewrite of the cruiser’s GetVehicleInput() needed to be done.
Zeekerss original code for steering was this:
float num = __instance.steeringWheelTurnSpeed; __instance.steeringInput = Mathf.Clamp(__instance.steeringInput + __instance.moveInputVector.x * num * Time.deltaTime, -3f, 3f);
Modifing these lines was pretty straightforward:
num entirely as we done need the wheel’s turn speedTime.deltaTime as it’ll be directIn the end the code looked like this: __instance.steeringInput = Mathf.Clamp(__instance.moveInputVector.x * 3f, -3f, 3f);
We need to multiply by 3 as we want the max to be 3 but the input can only reach a max value of 1.
This new wheel logic worked great except one problem: The G25 would be at 90deg at it’s max but the game would show it at 225deg.
The solution to this was to adjust the anim’s clam values from +/- 1 to +/- 2.4.
Why? Because we need to remove 1.4f from the max value, and for some reason the anim needs us to add it onto 1 instead of remove ¯\_(ツ)_/¯
Going forward all that’s really left is using the G25’s shifter to change the cruiser’s gears from Park, Reverse and Drive!
Cheers,
Liam
Tried driving the company cruiser with the wheel, and a few things need to be done:
Published the input part of the mod onto Thunderstore tho to make testing easier.
I’ll make a more interesting update once I start working that out!
Cheers,
Liam
Finally finished the first and most cruicial part of the mod! The first step to this mod was to let Lethal Company’s input system receive bindings from the G25. Now this in theory should have been a fast and easy implementation. Here’s how it turned into a 4 hour journey:
I started off by writing the essential parts of the mod. This mod uses BenInEx and HarmonyLib to patch my custom code into Lethal Company, so I made the public BasicUnityPlugin class that applies all patches in the .GetExecutingAssembly(). This means that it’ll look at all the code in the built .dll and patch automatically instead of me specifying what classes I want to patch.
This is the center of attention when it comes to the input patching. This class needs to do 3 things:
By fiddling around with the input system in another project, I found the name of the wheel to be <HID::G25 Racing Wheel>. Knowing the device name, I was ready to start patching the new inputs into the input assets.
The class that we will be patching is the StartOfRound class as it handles a lot of the local player and game logic. First I found the local player through StartOfRound.Instance?.localPlayerController;, then found the player’s playerActions asset and assigned a var to that. Then I made a function that takes the InputActionAsset, finds the actions we want, such as the ‘move’ action, and applies a new binding to that action. For example, we can grab the ‘interact’ action with InputAction interact = actions.FindAction("Interact"); and give it a new binding specifically for the G25: jump.AddBinding("<HID::G25 Racing Wheel>/button7").WithInteraction("press");
Once I finished adding all the bindings to the right actions along with some null checks, I build the .dll and got to testing. Right off the bat nothing worked, but a quick change to what method we needed to patch… kind of fixed things?
Something weird was going on: the bindings I’d made to the look action were working, but none of the other were.
3 hour long story short, Zeekerss made his PlayerControllerB read from two different instances of one InputActionAsset, so the bindings and actions across the two were the same but each one was being referanced in different spots.
The camera worked right away because the line that read the camera’s input was:playerActions.Movement.Look.ReadValue<Vector2>() as opposed to all other controls read as such: InputSystem.actions.FindAction("Move").ReadValue<Vector2>();.
The InputActionAsset I was patching was the one created in the player’s Awake() method, playerActions, and not the second global one.The only reason I found for Zeekerss to make two is that the mouse was being read by the first because the look input is not one that can be rebound in the settings menu. All the controls pulled from the second asset are controls that can be rebound in settings, meaning that the second one was the player’s local input settings when the first was the default.
All that needed to be done for the G25 controls to be read for all the actions was to also patch InputSystem.actions’s asset. It took about 3 1/2 hours to figure this out, but at least it works now!
Going forward we need to:
Cheers!
Liam
Recently, and as summer’s been coming around, I’ve been playing more and more lethal company with the bros. Now I wouldn’t say we’re sweats or anything, but we’re pretty good and can get to 3000+ quotas without many resets. On thing that’s made that possible is the wonderful Company Cruiser! For anyone who’s driven the Company Cruiser before, you already know how hellish it can be. The gear changes, janky steering and funny physics make it truly an experience to manage.
I’ve been driving this thing for a while now and would like to think that I’m quite proficient, but looking around my room got me thinking:
What if I could use my Logitech steering wheel to drive the cruiser? Now of course the base game has no support for it and the input system used to drive the Cruiser is 1-0 based and not Vector based (W key accelerates at max when a pedal would be an axis), but having modded lethal before I was sure It’d be feasible. So I got cracking.
The Logitech G25 is a legacy wheel and is not supported in newer Logitech software. After much fiddling I figured out I needed to use a very old version of Logitech Gaming Software to get it to register properly on my computer.
To start I needed to learn how the wheel interacts in and gets registered by Unity, specifically Unity 2022.3.9f, the version Zeekerss used to build LC. I began by making a unity project in that version with the URP Template, as it already had a preconfigured controller using the new Input System. I also downloaded a unity project by Juandarn called SpaceVR that used the Logitech G25 to figure out how it configured the wheel in it’s input system. Here’s what I learnt:
As the goal is to be able to drive the CC with the G25, it was also time to start looking at how Zeekerss configured the Input system for LC. I did this by using an asset ripper to reverse engineer Zeekerss LC build and turn it back into a Unity Project. So now that I have LC’s source code, it turns out it’s pretty simple and all the controls under one Action Map, so in the end I’ll need to add the G25’s axis configurations to the Actions themselves. I don’t think it’ll be too hard but for that I’ll need to start on some research related to interacting with a player’s input system through an LC mod patch.
This will be quite the fun mod and journey, post a comment if you have any ideas or suggestions!
Cheers,
Liam