12:50 All caps = constant variable. Lower case is local (in method or a parameter) and an '_' usually means private to module/class scope, and starts with a capital letter is public. so at glance of the code you know what are constants and/or what the scope of a variable is. Might be nerd-splaining here but I have watched this excellent video like 5 times now and I am translating it to C#. And I just thought I would point it out. :)
@boots33723 ай бұрын
I loved the entire tutorial aside from that part haha
@mihran7785 Жыл бұрын
Honestly, you're the best tutorial channel I've ever come across. thanks for everything
@lukky. Жыл бұрын
Thanks for the kind words ! :)
@santivalencia8813 Жыл бұрын
Try clear code he has nice tuts as well
@zarbon6319 Жыл бұрын
agreed , the only channel i found explaining of godot was clear
@Xavier_Legend9 күн бұрын
The voice is mesmerizing.
@Asonc1 Жыл бұрын
tip : can add this to close the project with ESC button instead of ALT+F4 / ALT+TAB, 1) add input "quit" in input_map and bind it to ESC 2)add this : func _input(): if Input.is_action_just_pressed("quit"): get_tree().quit()
@TheInfiniteAmo11 ай бұрын
You have no idea how insanely useful this is for workflow on a single monitor setup. Or maybe you do. Either way thanks.
@Asonc111 ай бұрын
@@TheInfiniteAmo np and good luck !
@gderuki10 ай бұрын
OR press F8 key when running project from Godot editor ;-)
@Asonc110 ай бұрын
or use hotkey system changer program to unbind ESC and bind F8 it to it with an algorithm that would change it back by reverse doing what it does when you click certain shortcut with admin approval before 2 am, also it requires you to fill 3 enctype php triple coded in 32Bytes passwords and they all need to match from randomly generated text while you sing opera live, but worry not, it will have subway surfer at the side bar
@banana_pancake110 ай бұрын
doesn't need to be _process(delta) function, it might be more optimised if it was in the func _input(event)
@AJMarraffa Жыл бұрын
This one tutorial contains stuff I had to dig for in lots of separate tutorials over a lot of time when making a character controller in Unity. So good! Thank you!!
@sealsharp Жыл бұрын
Helped me port my FpsController from Unity to Godot. Good work, sir!
@SunnyShuklathedoctor Жыл бұрын
I'm only halfway across and already I am very into this. You are a natural, love this.
@westingtyler1 Жыл бұрын
now due to the Unity to Godot exodus we need a good "Every Godot 4 Node Explained video."
@BINGUS-- Жыл бұрын
That would take like 1000 hours to finish If he tries to explain it Withall of its functions
@westingtyler1 Жыл бұрын
you can give an overview of anything in 30 seconds, just a brief one. 30 seconds per node would be super helpful for absolute beginniners. remember there's no such thing as a complicated topic, only a complicated explanation. the "topic explain in five levels of difficulty" videos is the style I'm thinking. - kingdergarten level. @@BINGUS--
@lukky. Жыл бұрын
That's a great idea!
@tabletopforgeuk Жыл бұрын
Lukky's got a video for every node. Pretty high level but helpful as a starter.
@SpazeDJ8 ай бұрын
So this is the comment resposible for the best youtube series on youtube
@WoyaThePug11 ай бұрын
This was a phenomenal tutorial. Kept simple, demonstrated good practices by showcasing frequent testing at each step of the way, and keeping code clean. Also, this taught me that you could drag nodes into the script to create references for them, and that is extremely life-changing! I am eager to watch more of your tutorials, thank you for this service!
@blake_bates9 ай бұрын
this is the best tutorial i could have come across, your teaching it exactly how teachers at my school would and explaining everything instead of cramming it into 10 minutes and editing it like a mr beast video. thank you
@spacecityryder6 ай бұрын
Mr Beast + coding = 😡
@fatmike5038 Жыл бұрын
I used this to make crouching toggle, you cannot put the bool swith in the same logical statement with a lerp running off the delta, because the lerp takes longer than the delta. var crouch: bool = false func _physics_process(delta): if Input.is_action_just_pressed("crouch") == true: if crouch == false: crouch = true else: crouch = false if crouch == true: head.position.y = lerp(head.position.y, 1.0, delta * lerpSpeed) currentSpeed = crouchingSpeed couch_collision.disabled = false standing_collision.disabled = true if crouch == false: head.position.y = lerp(head.position.y, 1.8, delta * lerpSpeed) currentSpeed = walkingSpeed couch_collision.disabled = true standing_collision.disabled = false
@Tenzalt Жыл бұрын
for the crouching logic i used a system similar to the sprint, i just made 2 consts for standing height, then crouching height and lerp the collision shape's height variable if i crouch or not, this, together with the raycast checking upwards, the crouching is adaptable to the surfaces of the map, for example if i let go the crouch button, my collision shape will grow untill reaching the celing above the player, its pretty smooth!
@Asonc1 Жыл бұрын
can you explain it more ? or show me the script :c i understand your idea ( pretty cool) but i am stuck at implementing it in the script
@s1ndrome117 Жыл бұрын
Implemented parkour mechanics like vaulting, wall running, tic-tac, sliding and mantling all by myself just from watching this part alone, that's how good the explanation was!
@markmisin Жыл бұрын
Thanks!
@lukky. Жыл бұрын
You're welcome! Thank you for the donation :)
@markmisin Жыл бұрын
@@lukky. My pleasure! I've become a lot smarter in 3D game development thanks to your tutorials.
@whowhowhowhat4 күн бұрын
Great tutorial. Only issue is that if you jump and spam crouch, you fall back down in a jittery-floaty sorta way. Also, when crouching under the block, if you jump, you will still clip through the block Edit: I found a solution to the clipping when jumping under the block. Where it says "if Input.is_action_just_pressed("ui_accept") and is_on_floor():". just add "and ! ray_cast_3d.is_colliding()" as an extra condition. This basically disables jumping when crouching under a block, preventing clipping through the block. 2nd Edit: Solution for jumping while spamming crouch causing jittery motion when falling back down For the if statement where it says "if Input.is_action_pressed("crouch"):" just under _physics_process(delta), add "and is_on_floor()". The program essentially thinks that the player is still on the floor if you try to crouch midair, causing it to switch collision shapes midair and for the player to fall down weirdly. Adding the extra condition stops this from happening.
@neikosar Жыл бұрын
There's another way to manage the collision shape when player is crouching, instead of having two collision shape, you can take only one and change its scale and position on y axis. Nice tutorial! It helped me a lot!
@adzee8711 Жыл бұрын
honestly your a life saver bro, i can understand everything your explaining witch helps me alot, especially since im currently developing a horror game for my school assignment, so this helps heaps and i cant wait for part 2 and 3 of this controller. Love the content bro keep it up
@carloszarate963 Жыл бұрын
A mi teniendo el mismo codigo ( menos por el sprint ) me glichea la colision, sabes porque?
@akaLuckyEye_G10 ай бұрын
The bobcat gets me everytime. 10/10 desktop background. Thanks for a great tutorial.
@Rizzie95 Жыл бұрын
I just had the itch the other day to learn how to make a game. Found Godot to be the most welcoming engine for a complete newbie like myself. Following this video just makes too much sense as the very first thing to do and learn. Thank you for the information I can now absorb.
@devanmauch7843 Жыл бұрын
I had an idea for future tutorials for newer users of godot to learn better, whenever you're doing something similar to what you previously did it might be beneficial to tell them to try it on their own so they can learn how their code works better. Like for instance when figuring out how to rotate the head horizontally it's a good opportunity to put your mind to work and remember it more concretely. in any case this tutorial was awesome and I hope to see more!
@carnage25145 ай бұрын
this tutorial is amazing, thank you sooo much, I have tried many tutorials for simple things in godot and none of them work as well as yours or are as well polished, thank you so much and keep it up
@XAHAK Жыл бұрын
big fan. ty for all the tutorials
@auxiliaryboxes Жыл бұрын
Well done, this is exactly the kind of video I wanted for prototyping an FPS with Godot. Clean, to the point, easy to follow.
@ToonLikeEpic11 ай бұрын
Most helpful tutorial for total beginners good work!
@_mickmccarthy Жыл бұрын
Awesome! I've just jumped back into game dev after a few months so this has appeared at a very opportune moment!
@manfriny_ Жыл бұрын
Top Demais!!!! Muito bom esse tutorial! Greetings from Brazil!
@ebrahimkheder9629 Жыл бұрын
The greatest channel for learning godot ,TNX 🔥🔥
@isaacyauk29667 ай бұрын
I just followed your video verbatim and I got the exact result shown! Thanks so much for making a clear and understandable video that didn't rush, but took it's time to explain EVERYTHING. You just earned yourself a sub sir! GOOD WORK!!!!
@joel2430 Жыл бұрын
Great tutorial! Very clean and easy to understand code. I would explain what is written in the Godot manual though: " CSG nodes are intended to be used for level prototyping. Creating CSG nodes has a significant CPU cost compared to creating a MeshInstance3D with a PrimitiveMesh. "
@bonddang9550 Жыл бұрын
Awesome! Can you show us footstep on different material when you walk on it next? Thank you!
@lukky. Жыл бұрын
I'll try and include it in part 3!
@Motaz4k Жыл бұрын
great work! loved the lerp stuff, it solved so many issues in my mind
@scotmcpherson Жыл бұрын
This is a great start to a 3d course, and I am looking forward to following the rest. Godot + GDScript is a bit different than Unity + C#. I have just one comment. By convention constants are typically ALLCAPS. It's a convention that is used so it's understood you are looking at a const value, and not looking at a variable and so that others that are reviewing your code are signaled that the value is a const. Sure you can go back to the header of the file where the values are cast and set, but this prevents it as a necessity. This convention is shared across most languages.
@ShVanesMusic Жыл бұрын
Very important detail about the convention
@akiftheafk Жыл бұрын
Great tutorial to understand basics of Godot. Thanks!
@lukabrasi001 Жыл бұрын
this is a really good tutorial, your narration is very good. one thing i'd do is change the raycast to a shapecast to avoid standing up halfway inside objects though
@gderuki10 ай бұрын
17:48 -- I have just discovered that by default you could exit any running game by pressing F8 (a hotkey for stopping debugging session/game, quite useful in scenarios when you don't want to implement a custom exit routine or pressing Alt + F4, etc.) P.S. worth mentioning it only works while running from inside the Godot editor.
@Theinvalidmusic Жыл бұрын
Couple of things I picked up on which may be useful to some people: - If you want to split your sprint function out and not have it inside your crouching behaviour, you can use boolean variables like 'is_crouching' to control whether sprinting is allowed, i.e. you can set 'is_crouching = true' when your character crouches, and then write if 'Input.is_action_pressed("sprint") and !is crouching:' when calling your sprinting code - If you don't want to use two separate colliders for crouching, you can modify your collider's height directly using collider.shape.height. The advantage with this is that the camera will follow the collider's relative height, and you can lerp between the two different heights for smooth transitions.
@uliveulearnandregret Жыл бұрын
to clarify on my issue more both of the if statements work fine however one of the speeds either crouch or sprint doesn't work if it's the 2nd if statement in physics process
@uliveulearnandregret Жыл бұрын
I have 2 is_action_pressed I came from roblox and generally the approach would be to have 2 different input action functions as I can interpret from your example
@@uliveulearnandregretthanks for the idea! Very well explained!
@jutraim2422 Жыл бұрын
add these to the beginning of the code: var IsSprinting: bool var IsCrouching: bool replace crouching and sprinting with: if Input.is_action_pressed("crouch"): IsCrouching = true current_speed = crouching_speed head.position.y = lerp(head.position.y,1.8 + crouching_depth,delta*lerp_speed) else: head.position.y = lerp(head.position.y,1.8,delta*lerp_speed) IsCrouching = false current_speed = walking_speed if Input.is_action_pressed("sprint") and !IsCrouching: IsSprinting = true current_speed = sprinting_speed elif IsCrouching: current_speed = crouching_speed else: IsSprinting = false current_speed = walking_speed I'm a beginner ^^ I managed to do it like this and it works for this project =) Please correct me if I did something redundant.
@ipherial2929 Жыл бұрын
One thing I have discovered for crouching that I use instead of using code to change the height is an animation player. It lets you adjust the height of anything on your player while also not cluttering your code as much since all you have to do is tell it to play one animation when crouch is pressed and another when it is released.
@cmcdonough22 ай бұрын
Very easy to digest, has a great pace, and is extremely informative. Thanks.
@DMG4yt Жыл бұрын
you're a legend man 🔥🔥🔥🔥
@trillius4 ай бұрын
THE BEST TUTORIAL!!!!! I LOVE THIS
@VasilisChatzikostas Жыл бұрын
Your video is amazing. You actually taught me so much and I am on the 31:00 min. Note I have 36+ hours in Godot as of writing this comment. I am not such a begineer. Well done with your video!
@lopsidedpolygon Жыл бұрын
Hey babe! Wake up! Lukky posted a new tutorial!!!! 💜🖤💜🖤
@dynstinn Жыл бұрын
Best tutorial i have found so far, after this i was able to tweak and make my own code in GD script. while crouching you can still jump which causes the camera to clip into the ground, i fixed it by adding another raycast check to see if there is anything above us, if yes then we wont jump while crouching.
@midnightmuni Жыл бұрын
Really helpful tutorial as always! Are there plans to cover ladder climbing or even ledge hanging in the future?
@lukky. Жыл бұрын
Going on the list for part 3! No promises tho there are alot of Request and I wanna keep the videos focused
@ge-fe-st Жыл бұрын
Thanks! Really useful and detailed guide. You have talent😊
@aqua3942 Жыл бұрын
I ran into a small bug with the raycast i haven't seen other comments mention, so I thought I'd share my solution incase anyone else needs it. When I set my RayCast3D node to the bottom of my player, it would detect the StaticBody3D that I had set as the scene's floor, basically locking the player into the crouched position after the crouch input was pressed. All I did to fix it was raise the raycast node's Y position by 0.1, and then shorten the raycast node's target position by 0.1 on the Y axis. So now the node is now off the ground, and still reaching the top of the player. Great tutorial btw, really appreciate it!
@lenawillis24848 ай бұрын
Lifesaver, 6 months later. Thank you!!
@Recals10 ай бұрын
nice tutorial ! I came for the mouse look and got by the way everything else i wanted, thank you !
@GPEART1 Жыл бұрын
This tutorial is WAY better than 2 other channels I tried doing the exact same kind of script, but both of theirs did not work, due to "path not found" errors and such, and no real explanation of half of the code. Thank You!
@Theinvalidmusic Жыл бұрын
Really great tutorial. Now to go and rip out my old extremely janky character controller and replace with this.
@ChristopherYabsley Жыл бұрын
Clean and concise. Thanks for making this series.
@TuncTurel Жыл бұрын
Thank you so much for this amazing tutorial! I followed it and wrote my C# version of your code and it works like a charm! I learned so much thanks to you.
@WrongNicholas5 ай бұрын
Really, really good tutorial. Keep up the good work, dude!
@steffensensa11 ай бұрын
Very good clean tutorial, straight to the point. Exactly what I was looking for. Thank you for taking the time to make this.
@pointblankeloquence957810 ай бұрын
Thank you so much! This is empowering :)
@niels5036 Жыл бұрын
Amazing, almost as relaxing as Bob Ross to watch!
@АртурАмбаров-ы1ю Жыл бұрын
thanks for the video, I think it's worth adding a ray_cast_3d check during the jump when the platform is overhead
@sean7221 Жыл бұрын
Well done! Thank you!
@itsakram09 ай бұрын
thank you for this tutorial, I just found your channel and i like it, keep up the hardwork
@gradman999 Жыл бұрын
Thanks for the tutorial!
@Pichotweb6 ай бұрын
Thanks for your time and effort to teach us! one tip when renaming variables is the Ctrl + D that will select all similar ocurrecies, like in other editors like VS Code!
@SiisKolkytEuroo Жыл бұрын
Nice video! The only detail I'm seeing that I would improve on, is that you're lerping the camera inside the physics_process function. You want to figure out a way to do it in process, so that the camera position updates on every frame (interpolates smoothly).
@TheRealKaiProton Жыл бұрын
Im 10mins in and loving this video, Im not new to Godot, or programming in general, but I am new to 3d, so I really appreciate the pace and explanation of this video..
@Seth_Makes_Sounds Жыл бұрын
Thanks dude. I doubt I'll ever finish a game, but this is a good starting point.
@devanmauch7843 Жыл бұрын
Lukky you make everything so simple keep it up!
@Afurai_ Жыл бұрын
After finishing this tutorial I have no idea why the sprint and crouch did not work for me initially (Godot 4.1.2 stable) but I figured out a solution; only changing some of the _physics_process(delta) code, I also fixed being able to spam crouch while underneath a surface, bugging out the crouching a bit if not fixed. I hope this helps anyone else having issues like I did! var canClick = true func _physics_process(delta): #Movement States #Crouching if Input.is_action_just_pressed("crouch") and canClick: currentSpeed = CROUCHING_SPEED head.position.y = lerp(head.position.y, 1.8 + crouchingDepth, delta * lerpSpeed) standing_collision_shape.disabled = true crouching_collision_shape.disabled = false canClick = false elif !ray_cast_3d.is_colliding(): #Standing if Input.is_action_just_released("crouch") and canClick: currentSpeed = WALKING_SPEED head.position.y = lerp(head.position.y, 1.8, delta * lerpSpeed) standing_collision_shape.disabled = false crouching_collision_shape.disabled = true canClick = false #Sprint / Walking if Input.is_action_just_pressed("sprint"): currentSpeed = SPRINTING_SPEED elif (Input.is_action_just_released("sprint")): currentSpeed = WALKING_SPEED canClick = true # Gravity
@Soacer03 ай бұрын
your problem might come from the "just_pressed" instead of is_action_pressed
@Th3BadThing Жыл бұрын
Dude, thank you heaps. I needed a refresher so bad and this was perfect.
Hi! Just wanted to say that this code has a small bug. By putting ray_cast_3d.is_colliding() on the elif, the player could get his head stuck in the ceiling if he is fast enough, since he can stop pressing the crouch button long enough for him to get down on the ground, but not fast enough for the lerp function to put his head down. No other side effect, since the speed is already set, but the head pòsition won't be properly set until the player exits the low ceiling, or presses again long enough the crouch button. This could be fixed by putting it in an or with the crouch press button
@fabianojeda3078 Жыл бұрын
Thanks brother, you are the very best
@nolew7 ай бұрын
12:37 if you press Ctrl + R a find and replace menu will pop up you can use to replace all instances of a string in the text editor
@traumwelt19757 ай бұрын
Thanks a lot for sharing your knowledge, i really like how you explain everything and test it step by step, that makes it easy to follow. oh and btw, you have a very nice voice ^^
@streider13475 ай бұрын
Here are a few improvements you might want to have. 1. a collision when you jump while crouching. # Handle jump. if Input.is_action_just_pressed(“ui_accept”) and is_on_floor() and !ray_cast_3d.is_colliding(): velocity.y = jump_velocity 2. if you should not crouch when jumping. # Crouching if Input.is_action_pressed(“crouch”)and is_on_floor():
@blondinchik4563 Жыл бұрын
Thanks for tutorial! It is very informative and without further ado!👍
@MTRFRK11 ай бұрын
Absolutetly fantastic tutorial
@loopatronic6 күн бұрын
you can kinda skip the creation of 2 different collision shapes by referencing the main collision shape and in the script where you enable/disable them, have a script part "col.shape = col.shape.height = the whole lerp function" and it should do the same thing but without needing to have 2 collision shapes
@bitbutter Жыл бұрын
great series, im helping my son learn using these
@samuellangford6126 Жыл бұрын
Thank you, your tutorial was the only one that worked.
@Source-bc1ph Жыл бұрын
To prevent crouching mid-air add this to your physics process function func _physics_process(delta): if Input.is_action_pressed("crouch") and velocity.y == 0:
@Asonc1 Жыл бұрын
i somehow made a spaghetti touch to the code and kept the crouching mid air possible but it doesnt drag you down made the crouching collision shape a bit higher to make jump crouching tech possible ( famous in Fps games like csgo/ valorant)
@adriwan194811 ай бұрын
Improved Version: func _physics_process(delta): if Input.is_action_pressed("crouch") and is_on_floor():
@gavinboyd531211 ай бұрын
At 7:17 when you enabled Triplanar under UV1, how does that magically align the texture to be layed out 1m X 1m? Does it have to do with the texture being 1024X1024 pixels? I've always wondered how devs layed out perfectly aligned grid textures over maps while developing them.
@ForgottenCorners5 ай бұрын
excellent video, thanks!
@silver_forest-k5i Жыл бұрын
Awesome tutorial, thank you!
@klause2s6 ай бұрын
*scooby doo confusion noise* alright, i tried this after trying like 4 other fps controllers, and not only did this one work perfectly, but it also immediately considered "forward" to the camera as opposed to the start of the model, as if like magic. i got a good feeling about this guy.
@savmass2 ай бұрын
Great Stuff! Subbed.
@noahsoffian4050 Жыл бұрын
Amazing tutorial. Thank you so much.
@funlabsdesignstudio8 ай бұрын
Thank You! Thank You! Thank You! Something I have always wanted to do and learn and because of your awesome video tutorials I am! Bless!
@Primal_Real4 ай бұрын
Thanks I just about to literally shoot myse- seasoned salad as nobody you know EXPLAINED MOVEMENT the most fundamental thing was barely talked about and I was tryna learn it so you know I could make a character move and understand how to but nobody did they just explained the bare bones basics or just the camera. TY so much you are the goat and I will forever be thankful to you.
@wassimelmabrak54567 ай бұрын
guys I have a problem, I can't seem to sprint as lukky did at 15:30 can someone help me troubleshoot the issue (btw I checked the value of each speed and the keys in the input map) later on I found the same problem with crouching, it doesn't last long -Edit: if you faced the same problem you should just replace the "is_action_just_pressed" with "is_action_pressed"
@clxakz4 сағат бұрын
i used collision shape scaling for the crouch: collision_shape.scale.y = lerp(collision_shape.scale.y, 0.5, delta * crouch_smoothing)
@thecube_godot3 ай бұрын
If the set_mouse_mode function does not appear in Godot 4.3, it is because it has been replaced. It would currently look like this: func _ready(): Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
@margarita2077cyber Жыл бұрын
Man, thank you. Really BIG thanks.
@lukky. Жыл бұрын
You're welcome :)
@margarita2077cyber Жыл бұрын
@@lukky. I've got a problem. Where can I contact you?
@yermekfun8203 Жыл бұрын
21:50 actually this "looking back" moment could be fun part of gameplay, like if main character would be some robot, with 360 look view)) so he can shoot enemies behind him, that would be non-stop action
@roccolucente61522 ай бұрын
22:50 if you are getting an 'invalid get index' error here; as of godot 4.2 this line should be "head.rotation_degrees.x = clamp(head.rotation_degrees.x, -89, 89)"
@asdfghjkl-jk6mu11 ай бұрын
Glad to see a fellow pallas cat enjoyer!
@legionsalt Жыл бұрын
22:02 I typed in the code, and it doesn't work at all. I've re-typed the code multiple times and restarted godot, what's going on? Everything works up until this point.
@triple0k9 күн бұрын
Tnx bro it was very helpful 💙
@asdfghjkl-jk6mu11 ай бұрын
Recommendation: Zoom into code as it's hard to see.
@xbelanch Жыл бұрын
Amazing and helpful tutorial. Just a tip: perhaps jump action needs to check if raycast top is not colliding. For example: try to jump under the plane and you'll get a glitchy situation
@Fatherlake Жыл бұрын
for the part under "# Handle Jump." just add another "and" and then the raycast collision check
@TheMarand Жыл бұрын
In player scrip go to Var crouching_depth set it to -0.5 or what ever how low you want to crouch and in crouching_collision_shape node in player scene make the height subtracted what ever your crouch_depth is crouch_depth = -0.5 your collision shape should be 1.5m Now the player can jump and bump is head! I think?
@tedTV_18 ай бұрын
god send of a tutorial, thank you 🙏
@4SIGMAMAN8 ай бұрын
you help me alot i put another code: func _physics_process(delta): if Input.is_action_just_pressed("mouse visable"): Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) mouse_sens = 0 and this: if Input.is_action_just_pressed("play"): Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) mouse_sens = 0.4 that puts them in physics_process function Add another INPUT called "mouse visable" and another INPUT called play
@cyberbruh5217 ай бұрын
13:40 quick tip press ctrl + r godot already has a tool to replace all words
@RobertShane5 ай бұрын
20:00 Instead of converting it to radians, which is multiplying the mouse_sense by pi/180 each frame, you could compute this directly by doing var mouse_sense = 0.006981317 which is 0.4 * pi/180. Not a huge performance gain, I know.