Create a TYPERACER clone using Node.js, Socket.io, Next.js, Shadcn-ui, Turborepo and more!

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video we are going to build a typ racer clone typ racer is an application where people can invite their friends and they can test the speeds of typing and they can compete with each other and see who types the fastest among them so in this video we are going to build something very similar to that where you can invite your friends and you will have a leaderboard where you can see how many words have been typed by you and your fellow mates in just one minute so the Technologies we are going to use here are nodejs socket IO which is a websocket library for nodejs and we are also going to use nextjs for the front end so we are going to use the next year sap Rus so don't worry you are eating some latest stuff so yeah before we proceed I want to give a disclaimer this video is not going to copy typ racer from start to finish we are not going to copy the UI we are not going to copy all of the concepts that typ racer has we are not going to copy all of the features instead we are going to focus on the core parts of typing battles between your friends so if you're looking for something like a complete type rer clone with all of the U and stuff unfortunately my friend this is not the video for you you can hop off but you if if you want to learn some technologies like websockets and stuff you are in for a treat so yeah let's get into the demo all right so this is the game it says typing battle I'm not using typ presser a lot here because I don't want people to think that this is a complete typ presser clone but yeah you can create a game or you can join a game so we do not already have a game so we are going to create a game and now you are prompted to enter your name this will be your nickname during your game so I'm going to call myself aava and now I'm going to join the game now I will be alone here the leaderboard is completely empty it's just me and now how do I invite my friend so the invite code you can find it here so you might be asking like why have you not added a copy button for the invite because I have a few things that I want you to do I I don't want you to just copy entire thing there are few improvements that this app needs and I'm pretty sure you should be able to do it if you follow along and if you are able to build this yourself so I have copied the invite now I can go to Local Host 3,000 here and I can paste the invite code and I can call myself Noob Master 123 if you know you know I'm going to join the game perfect now we have two players it says waiting for player to join but this is not the host the aara account is the host so I can start the game here now if I start the game I'm going to be presented with this huge box and I have to type along so I can say they were lost without the mop I guess so whatever and here I can just say they were lost not list okay so if you type something other other thing like if I type list it won't count and anything other than that will will also not count so if I just like everything needs to be correct or else like even the next word you type won't be counted so this is how this works and uh this will run for 1 minute we do not have a timer here but you can always add that and that's one of the things I want to add and this one because people usually just follow all the Clones blindly and did not add anything for themselves like if you add the small quality of life changes you already have entire framework you just need to add some small quality of life changes to make sure that this is a complete um game so yeah uh I'm I I'm pretty sure 1 minute should be anyways done for till now I'm not sure what's happening oh yeah so it says game finished now we have the final leader boards this is the new master account we are at second if we check our account the leaderboard is the same we have one so like if there are more people the leaderboard will be adjusted automatically so if Noob Master gain more points he will be at the first position and AA will be below no master so yeah in AA account I can even start the game again so that will reset the leaderboards and we will be back to zero and the game will be started at both sides so yeah this is the basic just of how the game works uh there are a lot of quality of life changes uh you can add um there are a lot of things you can add like just a copy button or even like a timer a lot of things you can work on so let's forget that now we are going to just work on the actual application we are going to work on the server we are going to work on the client we're going to put everything together and then yeah we're going to clone this exactly so yeah let's get started before we move on I have one favor to ask hit the like button and hit the Subscribe button that does a lot for this Channel and yeah I'll wait for 5 seconds do it wait I don't think you have done it yet so why don't you just do it another 5 Seconds yeah anyways like I'm pretty sure you must have done it know if if not then we have a problem here anyways so we are in our terminal first of all we need to create a monor repo why are we using a monor repo uh nothing's nothing specific reason only the performance is good and a lot I'm getting a lot of request from my YouTube subscribers that hey build a new video on Toro and make an actual project with it so yeah here we go to create a Toro I'm going to use pnpx uh please do not use npm it's very slow uh like if unless you have like a very specific reason you want to use it uh please don't use it go for like pnpm or even bun like uh I think bun has some problems here and there but I think you should be fine with this project so I'm going to use pnpm so I'm going to use pnpx create turbo I'm going to use latest tag here because in documentation they say use latest tag I already have a video on turbor repo so you can always check that I will have it in the description below so turbo latest I'm going to call it typ racer YT because I already have one in this folder so yeah let's go they should not take a lot of time all right we are going to use pnpm workspace so like just use whatever is better for you I'm just going to use pnpm it's going to download the files then it's going to install the dependencies and then we'll be then we will be good to go all right it has installed some stuff like docs and web we actually do not need both of them like we will be removing them so let's go and open code dot here we will be not not here not here actually we will be going to type race of ID and we will be doing code Dot and we will be opening vs code here now first things first we need to remove some stuff we do not need docs we are going to delete it we also do not need web we will create our own later so I'm going to delete web also in packages we actually do not even need a packages but these two apparently are needed by nextjs to work and we are going to use nextjs later in the video so we are going to leave these two and we're going to delete the UI one so we do not need this all right perfect now we can go here uh first we will be working first we will work on the front end and then we will work on the actual client so I'm going to create a new folder I'm going to I'm going to call it server and in server uh we actually need to run some commands so let's open the terminal I'm going to go to I hope you can see the terminal yeah let's go to apps SLS server and here I'm going to do pnpm in it I'm not really sure if you can see the terminal right here so I'm just going to bring the terminal like this and I'm just going to go to apps server and I'm going to clear this and I'm going to do pnpm in it perfect now we need to install some packages so pnpm install DD first of all we need uh typescript because we will be using typescript in this video second we will need nodon because we will be using our Dev server so that we do not like need to always compile and run our server nodon will help us a lot other than that we are using TS node so that node mod works as expected so I'm just going to hit enter this will install all of the three dependencies actually developer dependencies all righty now we can do clear and for the normal dependencies we only need one so pnpm install socket.io now you can go fancy and install like Express and stuff and you can like have a lot of features that that way uh but for the scope of this video I'm just going to use socket iio and that's just enough for us perfect now what we need to do is we need to set a few things up first of all we need to create a TS config file so we are going to use npx TSC in it the reason I'm not using PN M here is for for some reason it doesn't work with bmpm or like any other thing I have tried it using with bun and bmpm it doesn't work it only works in npx for me uh for you it might work I'm not really sure what's problem what's the problem here but let's see all right now we can go back we have installed all the packages so we do not really need to be here again and now what we can do is we can go to tsconfig dojason we are first of all going to change the out directory so just search for out there and you will find this one uh you can make it like U uh the output should go into build I'm going to like uh you can even like name it anything else you can even make it like a disc I'm going to make it a build uh it's just a personal preference and here you are going to need a few scripts so first of all we need a start script but before that we need to actually change the path for the main so uh we are going to run a Javascript file in production so how like we are coding in typescript right so we need to actually build the typescript project and convert it into JavaScript and we need to link the actual Javascript file so the first file actually we need the entry point will be index.ts so whenever this will be transpiled into JS it will be actually index.js inside the build folder because we just set the build folder as the out directory so we are going to say /u/ index.js and now in start we are going to have um node yeah perfect thank you get up copilot for Dev no this is not the complicated command we need we just need nodon index.ts and it will just work nodemon if you don't already know noon it basically just uh refreshes your server Whenever there is some change so that you do not need to run it every single time uh yeah we also need a build script uh so like when you deploy or like if you even try to build if you want like your transpile JS versions you can simply run the build command and you will have your JS equivalent code now we need to set up our socket IO server so let's do that by the way uh if we if you don't already know we uh you can always go to socket iio documentation um so I'm just going to remove this part and socket. i. do/ V3 and you can go to the server part and you can go to the installation like uh initialization or installation part so like you can Al like uh we already have installed it so like this is the packet we needed to install you can go to the initialization part uh yeah you can you can do it like this uh we are basically also going to do like this uh there's a lot of things you can get from the socket documentation even like building this myself I was referring to the documentation a lot so don't think that I'm just like magically knowing all of the stuff so uh feel free to like refer to documentation when things are not clear to you all right so uh we are going to use this method so we are first going to have like a port so cons Port is equal to process. env. Port so at we haven't even created an environment variable why are you okay what's the problem here all right it appears that uh we need to install a package which is like types for node so let's do that um pnpm install uh not inside this uh we are actually going to go inside uh apps server and here we here we're going to do pnpm install this is going to be a de developer dependency so at types node perfect I think they should fix every single thing perfect let's go back and now let's try it out yeah there is gone the reason we are having like a process. outport is because like if you're deploying it to services like render uh this is not sponsored video by the way so if they're like upload like uh pushing it to like services uh they have their own port so you just like have this variable process. env. port or like if it's a local environment it will just completely ignore the environment variable and just use your specified Port which is 880 in my case please do not use 3,000 because we will be using nextjs which relies on the port 3000 so I now let's create an HTTP server so const HTTP server is equal to create server we needed that from HTTP not from any other packages so we we are going to create the server and now we are going to create our socket IO instance so const IO is equal to new server and we are going to import it from socket.io and we are going to have we are going to just pass in the HTTP server and we are going to have some options so before we even move like I want to uh explain you why we are plugging the HT HTTP server here is because this HTTP server is like an like an actual server and the things you plug into it are actually uh based on that server so like if you want an expressjs application and if you want a socket IO instance running on a same HTTP server you can actually plug this HTTP server both in your expressjs application and in your socket iio so you could you do it without this without HTTP server yes are we doing it without it no why because if you decided if you want to add like an Express server uh you actually need to create an HTTP server and then you need to actually plug it in so like if you are using two different things you need an HTTP server that's why I did it I think this is a way better uh thing to do uh than just like using just IO it's just my personal opinion if you don't want it just go like with the socket IO just check the documentation and see how you can um do it very straightforward way but you still need to configure cost so we need to do cost here so for we need to pass in An Origin uh which is like we are going to allow requests from all Origins and we are also going to allow uh methods like uh we are also going to allow get and post so get post we are going to allow these methods perfect and now we are going to do HTTP HTTP server. listen we are going to listen on Port and then we are going to have a call back where we are going to do a console.log oops and where we are going to say server is running on Port Port perfect and this is just the entry point now what we can do we can go to our terminal and we can say uh clear we can do pnpm Dev and now this should start up every single thing in our monor repo but we only have the server right now so it's only going to start the server in a developer development environment now note that since we are using Dev command inside of this package.json file that's why it's able to detect the develop development mode for our node J so if you like change this to like Dev aaral something anything like that uh you need to actually configure that in your turbo repo so it's better you just leave it to Dev uh unless you have like a some very specific use case that's valid all right so what do we need to do we have actually uh done with this what you could do is like you could completely put everything in one single file and just call it a day and it will work but I don't think that's the correct option here I think we should create a new file to set up all of our socket I listeners so that we can listen to events sent by the clients side so we will create a new file here we are going to in the server for the server thing and we're going to call it uh setup listeners dots perfect and here we are going to do export uh function um setup listeners and we are going to have an IO here which is going to have a type so let's just open open the function this is we need a type for this so if this is a hack so like if we go here and just over about it we get the type of server we do not need all of the additional things here you could have it it will work but we just need the server which comes from uh socket IO so let's just go ahead and let just type it with uh server from socket IO perfect now it will uh do not it will not cry if you like just pass in the io here so like we can do setup listeners and we can just pass in IO here and it will just work so if there are no red lines here that means it will work so we have like passed in the correct types okay let me tell you if you're a beginner in JavaScript or typ script this next part might have you a little confused so please make sure that you give yourself enough time to understand this code so what we're going to do is we're going to take this IO and we are going to listen to an event which is going to be the connection event which is a default provided by socket IO so like if somebody connects they will be forwarded to this event listener so we will will have a socket here and unfortunately it appears that there is something wrong uh yeah this needs to be yeah this is a function let's let's just trust the process and see if the eror goes away yeah it does and you can already get the socket which is like the type of socket uh you do not need to type it so now what you can do is you can simply do a console log um new connection so like every time somebody joins uh this will be logged in your server and you can just print it in the socket. ID which will be unique to every single client so that way you can differentiate uh socket ID is the way you can differentiate between your different clients all right so within this you can create with different listeners like somebody joins you can create listeners for them so you need to have all of the rest of the listeners here so you like uh we are going to have one listener which is called as join game so we can do like socket do on join game uh this is not a you can like name it anything I'm going to name it join game and this will have a call back function and the params you pass here is custom you can like have any params here so the params I want here is one room ID which is going to be a string and I want a name for user which is also going to be a string so like whenever somebody is trying to join a game we first need the room ID for the game he wants to join second we need the name of the person so yeah uh you saw in the demo like we asked for the nickname so that's basically which is going to be passed here uh yeah now we can go ahead and uh we can do fun first check we can like if the room ID does not exist or like if the name does not exist uh I don't think we should like have this for name here exactly like I think it's a good thing to have but uh all righty I think uh we should do it separately because like U yeah I will show you so socket. emit uh so how do you send uh event to your client so we can do socket. emit so like to listen an event it's a socket. on but to send an event it's a socket. Emit and socket. emit will only emit an event to the specific client not to every single person so yeah don't get confused about it because there will be places where we'll be sending events to mass uh so like a specific room like with a bunch of players so don't get confused socket. emit directly only sends um like this is Socket this is referring to the one person so we are sending it only to one person so we are passing an error event and we are passing the message as invalid room ID and also we can create a new one so like uh if name I actually don't have it because I check it on the next JS site so uh I mean yeah but like you still should have it so socket. Emit and uh I can have error and please provide nickname all right what I want to do is I want to remove the brackets uh we do not need them and what I want to do is like have return here so like if somebody provides um wrong room IDs um the execution will stop here and they will not proceed any further or there will be like security things so yeah we need to have return here don't forget that after the checks are done we want to join the room actually so how do we do that we can do socket. jooin and we can pass in a room ID so I'm just going to pass in the room ID so we are not going to check if the like uh room is already like if it doesn't exist we are going to throw an error we are going to do like if the room does not exist we are going to create that room uh it's as simple as that so yeah uh we just going to join the room so socket. jooin means uh like socket IO has this native functionality where you can join in specific rooms and these room you can like like emit events to these rooms or like you can do stuff with it so like if you want to group your users like if you have a group chat you can create a room for that and you can add all of the people inside it and you can do stuff so this is basically the room so for for one game we are going to create a room and we're going to join that room so yeah I know my explanations are getting too explanatory but like I want to keep this video uh easier to understand for people that's why so now there are two things like um once you're joining a room there might be two things when the game already exist when the game does not exist so how do we keep track of rooms first of all before we even keep track of rooms we need to First create a game right how are you supposed to keep track of a game when you don't have a game sounds confusing right we need to First create a new class that represents a game and like whenever there are new people joining in whenever there are new games being made we can create a new instance of that class like objects and uh we can store them inside a map so I will explain you everything but first of all we will create a class so here we are going to go into server we are going to create a new folder call it as classes and I'm going to create a new folder called as game. TS now we can do export class game and yeah this is basically a class so what I'm going to do here is like in setup listeners uh don't worry about this we are going to add stuff here basically your entire game logic is going to be here so for now it's going to be empty but what I want to do here is I want to create a map which keeps track of the game so we are not handling any database of stuff this is all going to like nonpersistent so like if you restart the server all the active games will be destroyed so yeah export const rooms export I'm just using because we might need later uh in this video we are not but like you might but okay I'm just going to remove the export forget it so new map we are going to use a map map is a key value pair thingy so like you can have like the room ID and the associated CL um class on instance like the object with it so uh we can like have the like uh the key should be a string and the value should be a game object yeah and now we can name it uh no we just need to do it like this and now this map will contain a key value pair so the key will be the actual room ID and the game will be the actual object so like the actual game instance so you can actually access it from here so we want to do two two things here so like uh I want to do if we need to do check if the room already exists or not so like if the room already exists we just want the player to join if the room does not exist we want to create the room so we're going to do room do has um rooms do has and I'm just going to pass in room ID so this is a very good function for a map so like it just check if the game instance exist for this or not and yeah for this case the room exist and we are also going to have an else block here uh which says that room does not exist here we can do some stuff like U getting the actual game so we can do const game is equal to rooms doget room ID yeah and now we have this game instance here which we can use and um for some reason this can also be undefined so you can see it here so we need to do some checks so like if we do know that it exists because it has has property and we are only storing gam game instances there but just to satisfy typescript I'm going to do this so return uh socket do emit we are going to pass in an error which is going to be game not found which technically should never execute but we are going to have it here all right now the next thing would be to join a game but before we create the join the game logic we actually need to work with the classes because we need to actually execute a function inside the class so yeah let's work on the class now all right so we are going to start with the class uh if you don't already know class I think it's a like a very good concept you should know of uh like whenever you are using like instances of something I think the best way to do it is like the class and this is the first project I have been implementing this so yeah before I've have been doing it in C++ and stuff but not really in JavaScript and types because I'm more used to like the front end stuff where like react and stuff where it's like a functional based programming and classes are almost never used so okay let's forget about that and we are going to first create some properties so like it's basically variables inside a class so I'm going to have like the first one is like you don't have to like use con and stuff here these are basically public properties so first we are going to have a game status you could have values here but I do not want to have them I'm just going to have the types here for these so the types is going to be like it's going to be a string but it's only going to three Choice uh it's only going to be be having three choices so like it's going to be have not started like imagine like what a game status should have technically it should be like not started it should be in progress and in finished right I think realistically these are only three statuses for our game that we are building so yeah in progress and finished I think this should work but there's some error here game status has no initializer yeah actually there is no initializer we need to actually create it uh don't worry we will create a Constructor and we will assign all the values to it don't worry for it right now ignore the error let's move on second thing we need is the game ID actually which we will get through Constructor which is going to be a string the third thing we need is the Players it's going to be an array but array of objects so in an object we will have an ID of the player so it it's going to be a socket ID so it's going to be a string the second thing we need is a score of the person so like how many words he has typed till now so number and uh the third thing we need uh this is not this is not supposed to be a comma this is supposed to be an semicolon and this is the type definition by the way so if you're using JavaScript you do not need to do all of this name String but I really suggest that you use typescript because uh it's very important the next thing we need is is the actual server instance so like socket IO instance so this is going to be a socket IO instance from and we are needing this because we need to actually emit a lot of events so we need the instance here like the actual instance we created before so that we can do all of the stuff we need the next next thing we need is The Game host so let's let's have him we saw how like The Only Game host can start the game so uh we need the actual ID of The Game host here the next thing we need is the paragraph which will be displayed to the user it's not actually a constant paragraph We Are fetching it from an API we are going to do that later but uh let's have it here perfect now let's figure out all of these error we are going to have a Constructor and and we are going to accept an ID which is going to be a string we're going to accept IO which is going to be a server instance and then we are going to accept a host which is going to be a string uh basically a Game host and now you can just assign Valu so this. game ID is equal to ID then we can do this players and an initial game would have empty players you might argue that the first person joining should be here but we will be doing that in a separate function will be exposing a join player function so that the set setup listeners file can have access to it and it can add players to our class so yeah and then we need this. IO is equal to IO and next we need this do Game host is equal to host um this do game status uh we are going to set it to not started next we need this do paragraph which is going to be empty because we are going to fetch it from an API so yeah all of the errors are gone now we do need a uh setup listeners uh function here so like this uh function will actually fun hold on so we do not need to provide function like this we we can just set up listeners and we just need a socket instance so like this is different from the server instance which we are talking about so let me just type this and we can proceed in explanation all right so what the plan is like uh the The Listener thing in socket iio works like you cannot set a listener for an entire room you need to have listeners for specific clients so whenever somebody joins you need to set up listeners for all of those people who are in the lobby so like who are in the room so like whenever somebody joins you are executing the join player function inside the class which we will just make and the join player needs to ensure that all the listeners setup for that person so that the game works as intended there are no problems so the join player function will call this function eventually so this is just an advanced explanation I'm giving you we are going to leave this function empty for now uh the next thing we are going to work on is the join players all right so join player and we are going to accept uh a few things it's going to be first is going to be ID so it's going to be a string then we going to accept a name which is going to be a string then we are going to accept a socket which is going to be a socket instance which we eventually going to pass into the setup listeners function but let's not worry about it right now now a few checks first of all if the game is in progress we are going to have an error so if this dot game status is equal to in progress we are going to have an error so return error uh not like that socket do Emit and we can have an error in here and we can can just uh pass in the error uh game has already started please wait for it to end before joining I think this should be good enough right perfect now we can just push this player so like if the game is not started yet uh it's not like in progress It's uh we are good to push this player inside our class and we are ready to register that player so how do we do that we we are going to do this do players. push now we can simply pass in an object and typescript will help you here so if we can just pass in an ID and we can pass in a name we can pass in the score which is going to be Zero by default so why didn't we have values here because like we have the ID and name as Keys here we can just pass it like that and it will just understand the next thing we need to do is uh we need to actually uh tell the entire room that this person has joined joined so like imagine if I join your lobby I want the entire server like I want the entire Lobby to know that I have joined right or else everyone will be out of sync and you won't see the scores for a play you won't even recognize that a player has joined but somehow you will not be on the top of the lead leaderboard and that would suck right so uh so we need to actually uh push this event to everyone so we are going to not use the socket because remember socket represents the user so I'm going to use the names so like socket can be any name here I'm with referring to socket variable socket refers to the user iio refers to everyone so you can do IO to and uh we have to like to send this event to a specific game ID not to every single game in the server so this do game ID so this will only send it to this game and we want to emit an event and now the syntax is pretty much same so we are going to emit player joined and we are going to emit an object here uh we are going to have ID name and score should be default zero so that the front ends are up to date now there are a few more things I want to Adit so like uh we want the actual user who joined we want to let them know all the people who are in the game currently right there's no way for us to do that right now so we're going to do uh socket. emit uh players this will uh keep the uh current joining player sync with all of the other players so uh this do players perfect and the other thing we want to do is we want to emit who is The Game host so that like the front end can decide if you want to show the button or not so socket. emit we are going to emit new host I'm I'm using the new host because we will be using this event a lot of different places uh the purpose of this event in the front end is like just to update the host so we are just going to have one listener in the front end for this event and whenever we want to change the host we are going to use the new host event now what we are going to do is we are going to do this do setup listeners like once we have joined the game we want to set up the listeners so this do setup listeners socket now we can go ahead and set up our listeners here before that before we even set the listeners I want to go ahead and complete the setup listeners file so that we can go ahead and focus on what really matters is which is the game class itself uh we will just uh make sure everything is fine here and then we'll go ahead with that all right so we talked about how before like uh we are check if the game is existing or not so if the game is existing we simply want to join the player so how do we do it so we are just we already have the game instance here so we just going to say game. jooin player and we are just going to pass in details the first thing we need is the ID which is going to be the socket. ID the next thing we need need is the name and the third thing we need is the actual socket which represents the user that's it we don't need to do anything else and in the else block we need to actually create the game because the game does not already exist so to create a new game we are just going to use how classes work so con game is equal to new game and we are going to pass in a few stuff like room ID IO and we just going to pass in socket. idid as host so that uh the person is host at first all righty and uh now what we're going to do is we are going to do rooms. set we are going to do a room ID and we're passing the game instance so what we going what we are doing is we are adding a new entry to the rooms map and we are specifying the room ID and we are associating the game object uh to it so that we can access it later or we actually have a track of it so that whenever somebody tries to join this game uh we can actually identify this specific object and we can direct them to join this game I hope you're understanding how the flow is going right now the next thing we need to do is pretty easy the same thing we did before so game do join player and uh and we are going to pass in u socket ID name and socket that's easy now our setup listeners thing is done here and now U our main listeners should work what we need to worry about now is the listeners in our game class so now we need to our entire logic resides here basically you can split it up into files but I really do not want to do that uh I want to like have everything here because this is not a tutorial on how to like manage your files correctly I do not want to like confuse you guys a lot so in the setup listeners function the first thing we need there there a lot of different things here the first event we will be listening is like the start game so socket. on we are going to see if like any person emits the start game event which only the host can do by the way so we need to do some checks uh I'm going to use an Asing function here usually we do not use Asing functions in this app which we are making right now so the reason we are using Asing function is because we need to do a API call to get a paragraph so we will get into that later but first of all right now we are going to work on this so first of all we are going to check if the game is already running or not so if like a game is running you cannot already you cannot run a game again so like at the same time so this uh hold on so if this. game status is equal to is equal to is equal to in progress like if it's in progress right now we want to return socket dot not this socket socket do emit error and we want to say the game has already started perfect and I think that is a one more check we need to do yep uh the second check we need to do is like if uh the person sending this event is a host or not so like imagine like if you are not aost host and if if you find out a way to send this event if you don't have proper checks in place anyone can start the game so the game was basically has no meaning so we need to actually check if the person who sending this event is the host or not so if this do Game host is not equal to socket. ID so if the socket. ID is not the Game host then we are going to do return socket. emit we are going to pass in an error event and we are going to send uh you are not the host of the game only the host can start the game whatever I don't even care anyways now first thing we need to do is like we need to consider that um this function like the start game event can also be done when the game ends so what happens when the game ends like we saw we have a leaderboard right the leaderboard gets retained when the game ends what we want to do whenever the game starts we need to actually reset the leaderboard to zero so how do we do that so we are going to do four since we're using ASN CET we need to use this one version you could use promises and stuff with like for each um all of that stuff but I'm just going to go easy way I'm just going to use four here so don't be ever afraid of like embarrassed of using for so const player of this do players and for every player I want to set player do score is equal to zero so like for every player I want to set set the score to zero and now what I want to do is like I want to emit the score to play like I want to emit uh the changes to the our clients so how do we do that we actually already emitted this event first like the player one we are going to reuse this emit event so uh except I'm not going to send it to just this person we are going to send it to every single one in the lobby so we are going to do this. iio do2 this. game ID not Game host game ID and we're going to emit players and we're going to say this do players now this will emit all the players uh and their updated scores to the clients all of the clients in the room and once this is done we are good to start with the game we are going to do this do game status is equal to in progress and now we can start with the paragraph generation and stuff so what we want to do is I want to create a new file uh I know I just said that we are not going to create a lot of files but only one file we need and that's because I want to separate the API logic somewhere else in a somewhere different function so I'm going to create a new folder here I'm going to call it utils and I'm going to create a new file called as generate paragraph dots now there is one thing I want to do I don't want to write because this is a very long stuff you can go to my GitHub and copy this but uh I'm going to use this entire thing here so let me tell you what this means so this string is a local string so I saved it here what why did I do that uh because sometimes API request can fail and we still want to return something so what is the String I copied laurum and I translated it to English and this is that so we have a function called as generate paragraph using lapum which just uh splits all of these it just pick like random 50 uh stuff I think we should change it to like uh 150 so like uh yeah so it will pick up 150 words uh randomly it will shuffle them and like it will U just uh create a paragraph out of it and here what we are going to do is um in generate paragraph function which we'll be actually using we are making a fetch call to this URL so you could go through this Ur and you will see a fake um paragraph which will be generated which will have actually good letters like this is not actually translated properly that's why I'm using this API so if there is no response like if the response has any errors we are going to throw an error and we will look at the error uh handling later but if we have a response we are going to convert it to text and we are going to split all the new lines into spaces and we going to return the paragraph back to our flow if there's an error so we threw an error here so like if there is an error we are going to generate the paragraph using lpsum and then we are going to return the paragraph So if the API doesn't work we we have a backup and that's technically how things should work you can simply copy this file from my getup repository if you like are too lazy to just type this I understand I was even too lazy that's why I used the API in the first place anyways back to the game. TS file now we can go ahead and uh we can actually work on the paragraph emitting so how do we do that we set the game status now we can do const paragraph is equal to uh await generate paragraph the reason we using await here is because we are this is an async function the generate paragraph function is an async function and now yeah we will have the paragraphs so like even if there is error or not we will have the paragraph we don't need to worry about it the next thing we need to do is we need to set this do paragraph to paragraph So that our class has class keeps track of the paragraph now we need to set send this paragraph to every single person in the lobby so we're going to do this do iio do2 this. game ID just like we did before and we're going to emit a game started event and we're going to pass in the paragraph here so the game started event will recognize that the game has been started and it will contain the paragraph which will be given to all people at the same time um and they can start typing at this point now what I want to do is there's still one more thing left is I want to set a timer so I want to have like I want to give everybody 60 seconds to do their typing stuff so I'm going to do set timeout so there might be better way of doing this but I think this is by far the simplest way so this is going to run a function and I want this to be 60,000 milliseconds which is basically 60 seconds which is 1 minute uh and after 1 minute is over what I want to do is I want to do game this. game status is equal to finished the next thing I want to do is uh this.o do2 uh this. game ID and I want to emit an event here which says U game finished now there might be a case where like people might get disconnected and stuff and I still like it's a very unlikely case but I still want to keep every single clad in sync so I want to send all the players and their updated leaderboards when the game ends so yeah I it uh I'm just going to say players again and I'm just going to pass in this do players so like even after the game ends we will still send the players back as a last resort to sync everything on every single client so yeah now this event is done uh I think how many events we still have uh three more events out of which only one is very significant so I think we are still we are done with the core part like uh we are able to start a game uh we are able to uh we are able to finish it using the timeout all we need now is uh to manage like the key strokes of the user we are going to track the key strokes and we are going to see how many words the person has actually typed we are going to compare it with the paragraph and we are going to set the scores on the server side why on the server side because anybody can manipulate the client side so we are going to do that on the server side it might be expensive a little but I think this is the best way so we have set one listener here so which is socket on start game we do not need to Nest listeners here we can simply create a new listener here so I'm just going to do um this is going to track the key strokes like whenever we get any key strokes from the client we are going to send an event and we are going to track it here so socket. on player typed so whenever player types we will get this event and then we are going to have the entire paragraph with the person typed so it's going to be typed string so this is going to have the what the person typed and now we can work on this so we are first of all we going to check this um if this do game status is not equal to in progress then we are going to do return socket oops I accidentally socket. emit error and we are going to pass in the game has not started yet so the reason I'm doing this because uh if we do not have this check the CLI side person can actually like do some some stuff and they can basically send websocket events of player typed and even if the game is ended they can still update the scores so we we don't want that so we are just going to check if the game is in progress or not so what we want to do is we want to split the paragraph into words and we we are going to check everything so what we are going to do is I'm going to copy this code actually you know what yeah so basically what this code is doing is we are splitting the paragraph we have in the class then we are splitting the paragraph which we which the user has provided us we are setting the score to zero and what we are doing is like we are running a fall Loop we are doing like a we are checking if every word matches the thing or not if there is any word that doesn't matches uh we are going to break the loop and that's the score that's where the score ends like even if you mistype a if mistype a word and start typing the correct words later you still won't get any scores because you mistype one word there so that's we that's the logic for this and if every word is correct like if you have consecutive words correct you will get score Plus+ so this will add up your score so each time you type this logic will be run so you can optimize this by either like uh detecting where a word is typed on the front end but it's like writing double uh Logic on both sides and I don't want to do that uh you can do it of course if you want to again as I said I want to do some stuff in this project and not rely on me to just give you project uh as like uh hand over you need to do actually something like add some changes quality of light changes like if you put this in your resume you're not going to get accepted because this is actually on YouTube right so yeah so now we are going to have we are going to update the players so in our class we have the score so cons player is equal to this. players. find uh uh we need uh we're going to check if the player. ID is equal to socket out ID if we found a match that's the player we want to edit and then we can do um then we need to do some typescript check so if like player exist we need to basically do player do score is equal to score and now what we can do is like uh we can go ahead and do this.2 and we can say this do game ID do emit player score id socket. id and score yeah we are emitting this to every single person in the room so that every single person stays up to date about the latest score so like if they're typing they go to try hard mode they see at the side they see oh somebody else has passed me on the leaderboard now I I'm I'm just going to speed up my typing so that's how this is going to work so there are two things we need um first of all uh there are two more events then we are actually done with the back end part of this application then we can finally go to the front end so one thing which we need here is like what happens when a player leaves so there are going to be two events with basically same functionality so like uh we are going to have socket. on leave so this is going to do some stuff so like you might think that this is very easy like just remove the player from the thing but there's a catch what if the person leaving is a Game host like you don't want to end this game right there of course and you also do not want to leave the player standed so like nobody can start a game you actually want to transfer the host to somebody else how do we do that first of all we are going to do if socket. ID is equal to Game host so if the person is a Game host then we are going to do this logic if not if the person is not a Game host so this do Game host actually if the person is not a Game host we are going to first make sure this works so socket. leave we are going to make him leave the room so this do game ID and this we are going to remove it from our player stuff so I'm just going to copy this thing it's like same stuff again and again y now says uh this do players is equal to this do players. filter player is yeah we just like removing the person from The Players array and we are filtering him out so we are checking like uh what is the condition that needs to happen in order to not remove that person so like as long as the player ID is not equal to socket ID don't remove that person as long as it's equal remove that person so we are removing that player ID from our array then we are emitting to the entire room that hey this player left remove it from your client leaderboards now in uh this what we want to do if the person is a Game host we need to do a little more logic what we are going to do is first we are going to remove the person and uh why we are going to do this because we actually need to set the Game host so we are going to do if now now that the player list is uh has gotten rid of the host we can actually easily set a new Game host so we can do if this. players. length is not equal to zero there's also a possibility that that the person is a Game host but there's nobody in the lobby so like if uh there is nobody in the lobby so in the else case so if there is nobody in the lobby what we want to do is we want to do rooms which we got our import so yeah I was correct we need this to be export and we need to actually import it here rooms. remove uh rooms. Delete actually and we are going to delete this do game ID so this will basically remove the association of the game ID with this specific game and this game will be lost in the void and probably not even exist so yeah and if the there is there are people other than the host in the room what we want to do is we want to change the host so this do Game host is equal to this uh this is not a minus this should be equal to this do players Z we want the first player out of array because we already removed the host right so yeah do ID uh the reason I remove the host there might be some cases where the zero like the person on the Zero index might not like be the host it might be on like the host might be on be on the like two or three I know it might be impossible in this case but I still want to make sure so that's why I just remove the host before it's not that we are emitting anyone before the person is leaving so yeah we are emitting events as a wish goes so now now we are going to emit two events we already have used these events so I'm just going to paste them right here the first is the new host which is going to be the actual new host which we're setting here the second event is player left which we have already used before now what we're going to do is we are going to use the socket event again the same content you can actually extract this and have a different function but I'm just going to leave it for you uh in instead of leave we want to have disconnect which is actually a socket.io default so like if some disconnects of your game they will be removed from the game from our server side so we have the ability to do that so yeah I think our entire back end should be done right now uh yeah it's pretty much done yeah now we can move to the front end part and uh we can listen to all the uh things with the server is emitting like the player score new host player left player joined and stuff like game status like um game started game finished like whatever stuff so we are going to see all of that and um yeah let's get started with the front end uh if you are sticking till here I want you to leave a comment because I want to see if anyone sticks till here because this is going to be a very long video to be completely honest so if you are watching till now huge respect to you you are actually here to learn something new so go ahead leave that in the comments below I would really appreciate it so let's get started with the front end all right it's time to add a new project to a monor repo which is going to be the client so we are going to create a next JS application what I'm going to do is I'm going to stop this you know what I'm going to keep it running for now and I'm going to create a new tab here this will be the place where we can just go and install packages and stuff so in app we want to install a new next days application so we are going to use pnpx create next app and and I'm going to call it client or like uh yeah you can even call it web I called it web in my project so the reason I deleted web is because uh it's actually a demo built for uh the monor repo so I want to just create a blank next CH application it's just personal opinion but you can just proceed with that one also it's it doesn't matter so I'm just going to hit enter one of the reason is like we get the options here I just want to make sure that everything is the options we need so we are going to use typescript we are going to use eslint Tailwind yes SRC no we are going to use app router we do not want to customize the import alas they should not take a lot of time and after this is done we actually uh will um integrate Shad Z and UI uh which will allow us to do a lot of different stuff like using dark mode and stuff and uh you can basically have like uh components like buttons and stuff which we are going to use a lot in this uh build so yeah this is done let's go to Shad CN ui.com so Shad CN okay ui. Shad cn.com perfect let's do get started um very good thing uh this is like a I don't even know this is not even Library like it's like you need to copy paste components into your projects and you have a CLI to do that also like I have a video on shad and UI if you want to learn more about it I think you should because it's a very good thing uh I will leave the link in the description below so that you can always watch the video uh but I'm not going to talk a lot about it but let's go to installation and we are using next CH so let's choose that we already have the next CH project we are going to use this command to init our project so I'm going to copy the pnpm command let's go to terminal and I'm going to clear this I'm going to paste this command let's wait should not take a lot of time and and um there is a problem here yes I like how it detects that there is no package. just just a b okay we are in the apps folder we aren even the next folder we need to install Shad CN UI in the web folder right now we can just paste this here now it will now it should work so let's wait for this to be done it will actually we are going to use the default Stelling and we are going to use slate you just feel free to go with whatever you want and we are going to use CSS variable yes because it's very easy to customize uh if you want to know more we have things in like YouTube channel we have a video on Shar U again Shameless plug but yeah it uh detected all of our configuration of an next application and it just finished the initialization now you may add components now there are two components that we need uh we will uh before that we need to actually configure dark mode absolutely forgot about like a champ so let's have dark mode and let's for next uh next CH now we need to install a package called Next them so we are just going to paste the command here and just forget about it let's go back it says create a theme provider so go into the components folder and create a theme provider. TSX file and have the content so I'm just going to listen to it um so that it is done like installing the stuff uh we actually need to restart this so that our next CH application run as well yeah it is perfect on X this application is working but yeah let's go back to a dark mode thing now what happens is like um if you go to web shad and you has already created a folder called as components for us and here we can create a new theme provider. TSX file here and we can paste the contents just forget about it uh just chat c and do it do its thing wrap your root layout so I'm just going to copy this component we are going to need to go to app layout. TSX so let's go to um app / layout. TSX and we're going to have in the body um actually I'm going to have this paste it oops not this one copy paste yep and here we are going to close the theme provider and we need to actually import it from of a comp like valuing shs in here there a lot of confusion here you need to import from the components for folder not from the next themes so yeah uh default theme I want to keep it to dark like if you keep it to system you actually need to place a dark mode toggle or if or it will like uh become only light mode or it will not even respect your dark mode so I just want to keep it to dark mode I don't want to deal with all of the um stuff which is not relevant to this tutorial anyways so yeah uh add a Moree toggle if you want to do that do that feel free to do so but you need to set this to system and yeah um perfect you do not need to but I think it's the best one to have but uh yeah uh now you do have everything you need I think we need some components here so we are going to install a few ones so first of all we need a card component so let's Okay so let's go to alphabetical order we first we need the button component which we are going to use so to add a button component this is the command I'm going to copy for pnpm uh this is not going to install any packages more this just going to copy the components into our components folder the next component we need is the card component so I'm just going to copy this command for pnpm it says installing button should not take a lot of time perfect I'm going to install the card and I need a sonor as well so sonor to show you sonor I need to move myself up it's basically a form of toast so all right so if I click on show toast you look at the bottom right part of the screen and you will see the this school sonar uh toast so what I want to do with this is like I want to display my error messages here so let me place myself back to where I was hi all right anyways now we need to install Sona so how do we do that first of all we need to yeah we just run this command and we need to pass in toaster inside our root layout which is importing from component so let's just cop the pmpm command we're going to paste it here and we actually need to wait for it to install the sonor actually installs a dependency which is called a son sonor is not like made by Shu I believe it's made by somebody else and uh they're actually adding it to next year so yeah now if you go to UI uh do not add anything to UI it's basically all shui stuff it's Sona button and stuff but we need to go to layout. TSX and we need to add the toaster here which is from not from Sona but from our own components perfect don't make a mistake always check where you're importing from it's very important all right now we can go ahead and start working with all the juicy stuff all right so what I'm going to do right now is like I'm going to speed up the tutorial we have been using a lot of time I think you should be knowing the basics of react you should be knowing how GSX works this basically just HTML if you are watching this video I assuming that you know HTML so I think I'm just going to go ahead and I'm just going to remove everything inside of the actual thing in the main and actually I'm just going to go ahead and copy my stuff so I'm just going to go ahead and I'm just copy we will actually have a look at it so don't worry just yet we're going to paste this here okay so we need to import some stuff so I'm just going to import the card I'm going to import the button uh from our shat components we want to V yeah we do need to install input so let's go ahead and let's choose input uh let's install it as well oops pnpm let's go to terminal let's uh install it here should not take a lot of time should be pretty quick with it all right it's done now we can Auto Import it okay now I want to show you the UI I want to like remove these on submit functions and onclick things right now and I want to show you how this works and then we can go ahead and with uh we don't even need the next image thing we can just remove it let's go here and let's go to local 3000 it's taking you some time and here's a quick tip if you want this to load a little faster like right now I'm recording and while recording it's very very slow what I would do is I would go to uh package.json here uh and I would add like in front of next Dev I'm going to add next turbo so turbo uses the like U it ditches we pack and it's like their own bundler thingy I don't really know a lot of thing about it so like if you use turbo it will use its own rust thing and if you don't already know rust runs faster it's it's like a entire thing about rust so yeah uh now what we can do is we can just go ahead and restart this because just we we we just edited the package. so we do need to restart the dev Ser here perfect now does say turbo previously I don't think it did so yeah now it says turbo now it should be slightly faster if not a lot I'm going to restart uh refresh this page it's still taking some time but it should be a little faster so this is the UI it obviously doesn't work right now um oh what's happening here why is this working oh yeah because we are submitting a form yeah it makes sense uh but this should not be the case we are going to handle it different way but uh this is the thing like uh after we have create game we want to actually generate the generate a new ID from the front end itself and we are going to pass it to the web socket and uh in join game we are just going to take the invite code and we just going to pass the user to the correct game so we are going to have that by the params like we are going to pass in the IDS in params so that the user is pointed to the correct game so we need to do that so what in this page what we need to do we just need to add to the params so let's do that the first thing we need to do is uh we need to actually create create game functions so I'm just going to copy it it's very simple that's why I'm just copying it uh plus we do not want to use a lot of time so okay so this needs a package so we need to install a uu ID package uh let me tell you what it is so pnpm install uu ID so this package is used to Generate random IDs so we are going to use this random ID for our invite code so I'm just going to do import V4 as uu ID V4 from uu ID we actually need to also install types for this so I'm going to do pnpm install dasd types /u ID now this should work as usual uh yeah perfect and for router what we need to do is we need to use the next JS router so cons router is equal to use the router now this is very important do not use next SL router it's for the Pages directory use next SL navigation for the app directory which you're using right now so import again importing from the right places is key here so like just import from the right place now things should work so what this function is saying generate an invite code and push and just redirect the user to/ game/ invite code and then we will handle the game stuff there so this page is currently only doing this uh which is creating the game and then we will also actually join the game in the similar way so on click create game and for join game we want to actually go ahead and um create a new function so this is going to be a little complicated not exactly complicated but we do have a form we do need to have an on submit here so whenever submit someone submits the form we need to actually have a join game thingy here function which we are going to create right now so function when that works yeah but like let's create it anyway so join game uh we want e which is going to be yeah react. form event uh we can just import this we don't like yeah form event HTML form event this is the typing if you're using JavaScript do not need that but here what we are going to do is first of all we are going to do e do prevent default thank you cooperate but I do not need your help right now later maybe sometime then we need const const form is equal to new new form data is uh which is going to have the form now we will have all the values here oops it appears no this should be actually e do current Target so e do current Target e do current Target and now we can have const form data yeah and now we can simply access the invite code so con invite code yeah thank you go pilot uh just give me one line by line don't give me the entire code like that so if there is no invite code I want to uh invite code I just don't want to return I want to actually return toast uh which is a function from Sona so this is the only function from son which we need do error and we just pass in please invite I think yeah invite code is required not a valid one but invite code is required because if you pass in an an invalid invite code it will just create a new game using invite code so is required so if you use something like a tho as an invite code it will still work now we just need to redirect so yeah the reason why we use this and not like some like a state to map to the input like traditionally we do is I just wanted to use uncontrolled form so like if you don't already know I have uploaded a video on my read with AA Series where we read technical articles uh which was really related to like using controlled and uncontrolled forms I think that you should not really create controlled form when it's really not necessary so yeah this is the code we need and I think we are done with this page so let's test it out okay so used. only works in client components so we need to actually make this a client component so this is currently server component so if you use use client and do this becomes a client component now things will work now if you create a create game it will redirect us to this 404 but if you check the URL there will be an ID so if we go to join game uh not this one actually we do not need the invite code again and again if we add something like aava or 1 2 3 4 and if I click join game we will have that in the URL now what we can do is we can create that route and we can actually handle everything else so let's do that and I'm going to actually speedrun through this because this we still have a lot of things to do and we already have used a lot of time so yeah I'm actually going to yeah server is already closed um now in app actually we want to create a new folder called as game which is which is actually going to be a route and inside game we want to create a new file called as page. TSX I don't want anybody in like uh just going into uh Local Host 3000 SL game we actually want to param right I just don't want anyone to just go to SL game and no give us no ID so however we going to deal with that situation it's very easy since this is server component we can use a redirect function by next SL navigation and we can just go to slash uh so no ID provided gam I know I know my component naming is very bad just ignore just use whatever you want to but yeah uh if you go to now / game it will redirect us back to this page just like that now we need an page which will handle the IDS which we get in param so we will create a new folder with game ID which will receive as params uh inside of square brackets and now we can create a page. TSX now if you remember once we entered the invite code we had an option to enter our name this is where we will do that so all right so the mechanism we are going to use is like for each game so like if you noticed in the demo we still had SL game game but we also have name in the search P so we have like question mark name is equal to aava so if we have a name we just start the game if we do not have the name we actually prompt the user to add a name and since we do not even need any interactivity in the uh name form we are just going to make it a server component and the actual game is going to be a client component so uh this is going to be uh RFC and we are going to call this thing uh game join and uh yeah I'm going to copy the SX of course uh but first of all we need some props in in components you can just in server components you can just do search params params and uh you can get params and uh we need to actually give types to these so search params is supposed to be um no not don't trust copilot on this one params this is supposed to be an object and we only need the name here and which is supposed to be optional because we do not know if we have the name yet or not and uh params we do know that we have a param which is game ID and that's why we are on this page so we are not going to use optional so string that's that's a little logical thinging you need so yeah and now we need a little jsx but first of all we need to see if we have a name or not so we're going to remove this hear me out we're going to remove this and we're going to say if uh search params do name we do not if we do not have a name we are going to return a piece of jsx and if we do have we going to return some other piece of jsx that's that's very easy so I'm going to copy this entire thing I'm not going to use a lot of time to be completely honest I'm just going to paste this here we need to import card of course so import card you need to have a upend server so since this is a form action we cannot use like functions Cent side functions here we need need to create server s functions which is called as server actions in next year so yeah we can create a new server action here uh which which is going to be empty for now so um async function server actions need to be async so async function we I already have a video on server action so if you want to just go and watch it I'll leave it in the description upend name and I'm going to have the form data and this is going to be a form data you do not need a server action you could just make this a CLI component if you want to but if you want uh a server action you need to have the used server directive inside the function itself now you need to import input and you need to input import button itself perfect now if you go ahead and create a game we should be here which says enter your name we should be prompted to enter your name and join game we should have a name appended but we don't have anything in the logic here we need to add something so yeah we just going to use the form data so we already have the form data here so we we can simply access the values so cons name is equal to yeah and we can just do if uh there's no name we just return we just do nothing but if we have a name we redirect from next navigation of course yeah just like this we just SL game/ par. game ID uh question mark name and we just PR the name as the URL search parameters if we save this if we go here if we put name as a th if we click on join game you should see that we have a name here and the component is disappeared why because now we have a search param with a name and we we are not rendering this jsx instead we are rendering this part of jsx which is going to be a component so we are going to create a new component here called as game. DSX which is going to be the entire game basically and RFC let's do RFC this is going to be a game and we do not need the react import we are going to go back to our thingy and we going to render this component so game we of course need some props but I do want to see if this is working so yeah now the game component is being rendered what we can do is we can make the game component itself a client component so that we do not need to like we have isolated this enough so we can just make this client component do all of the things we want to crazy stuff you want to do here so it's a cent component it's still rendering good sign if we remove the name let's see if it works or not yep enter your name atava join game game perfect now we can go ahead and work on the actual game uh and we need some props here so let me see what props do we need all right we only need game ID and name everything else will be handled by our web sockets and servers so we do not need to worry about everything a lot so we need to actually first create a new uh types folder so that we can keep track of all the types which we are creating so in web I will create a new folder called as types uh you can simply create a types file instead and I'm going to have like a types. D.S D.S because we only have types in this folder so that's why I just have like this one I'm going to have all of the types here so that we will not create a lot of them a lot more so like the first type is a player which is going to have ID name and score if it if uh the server also has the same uh so like whenever the server is sending the players event we are actually sending in the same format so I already have it here so that it helps us knowing what a player is expecting in player score like whenever the score is being updated we are getting the ID and the score in the game status we already know and the game props is basically the component props so yeah uh we are actually getting the game props so I'm going to have um things from game props here and uh we actually will have type here because it's that's how it's supposed to be done and we are we are going to have game ID and name so yeah now we can go ahead and initiate our websocket and then we can listen to the events that our server sends and then we can emit our events as we create the UI but first of all I want to listen to all the events that the server is sending and I want to manage all the states according to that and then we will step into the UI part of things all right mes it's time to speedrun so there are going to be few States I'm not going to type it all you can go ahead and pause this video because it's going to just stretch this video to like different level so I just want to paste this here uh basically we just going to have us States I'm just going to import it we need socket from socket IO client we need to actually install the socket IO client we did everything and we didn't install the socket iio client so let's do pnpm install socket. i- client so this is the package for the client so I'm going to install it the types come with it so we do not need to install it now we can import it from socket.io I believe can we hello are we able to import it let me do restart TS server all right now let me import yeah perfect thank you so much and now we can import the player from types we can import the game status form types okay so now let's look at everything so first of all we are storing the iio instance in the state um don't ask why because I think this the best way to store uh players we are setting in the state because whenever they are updating we need to update the UI as well that's why game status we need to be have the state the paragraph which is being sent by the server needs to be in the state the host of the session needs to be in the state so like whenever the host changes if you become the new host you need to have that button so yeah we we have already discussed about that so if the input like an input paragraph is basically is going to control an input so this is the only controlled input we are going to use in this tutorial so this is going to keep track of what the user types and as the user types we are going to send it to the server itself so yeah now we actually need to connect to the websocket how do we do that we do know that our websocket is hosted on uh hold on uh it's hosted on Local Host 880 so we could directly uh hardcode it or we could create an environment variable right so I'm just going to go to web I'm going to create a new file which is called as hold on there's some error here yeah we need to pass in props so game ID let's do that I'm sorry let's just do this first so uh I think it was from params do game ID and we can just pass in what else does it need yeah it needs name so search params do name perfect now yeah now we need to set the environment variable let's go to web and create a new file called as do env. loal this is already um this is not going to be pushed so like if you are deploying somewhere you might need to mention your environment variables to them and we are going to have next public websocket URL and it's going to be HTTP Local Host 80 I know you might be thinking why are we using HTTP for a websocket socket IO handles it very uh in a very good way uh you can have WS it's fine like we are only using like websocket but you could also use something called as polling so if like websocket is not available you can use the polling and that's why we are using httv but I think for debugging purposes I think websocket is the best because you can see all the messages in one place and uh yeah and sometimes messages go through polling and they always go unnoticed and I think this is the best way now let's initiate a webs connection when do we want to initiate a webset connection as soon as the page loads right right so we're going to use a use effect and this will only run uh once when the page is loaded and we are going to have the dependency Arrow as nothing so that it only runs once the first thing we need is like the socket we want to create a socket so cons socket is equal to IO we need it from socket IO client and now we can just pass in process. EnV do next public web socket web soet websocket URL as string and now what we're going to do is uh you can leave it here um leaving it here means that polling will also work we want to set it so work only works with websocket you can skip this part if you want to but it I think it works way better while debugging so yeah we can have like a transports and we can just pass in websockets if you leave this alone it will also work with polling so yeah so we're going to set the io instance to socket so our states have track of it now what we're going to do is we are going to do socket. Emit and we are going to do join game and we going to have ID and name and we going to uh create listeners but the thing is uh okay let's forget about it but what we what we need to do is like whenever the component gets un Mount we actually need to uh disconnect the socket so you need to actually return a function that does socket do disconnect this is very important if you don't do it you might see a lot of socket connections created for a single page so use this this is very very important I'm repeating this is very important do not miss this all right so we need a function to set up listeners but when do we want to set up listeners when the socket is connected right so how do we do that hold on so we can do simply we can use a use effect um we can have a setup listeners function and we can have a remove listeners function so we need to create both of them so function setup listeners and one is going to be remove listeners so function remove listeners and what I want to do is I want to uh yeah so like what's happening is like we are setting up listeners and uh once the component gets unmounted we want to remove the listeners I also want to do it here as well uh so like uh when the socket disconnects you also want to remove the listeners socket um hold on we just yeah we just use the remove listeners I'm sorry it's been a very long time since I'm recording right now and my head is going all the way okay so in setup listeners we are going to have a lot of different things but what I want to do is like uh okay let's not worry about it right now but let's start creating our listeners okay first thing I want to do if I want to see if the io instance exists or not so if IO instance doesn't exist we are going to just do nothing we don't want to settle list we do not want to get undefined errors so yeah IO instance do on so this is a default for client so connect is a default for client and connection is the default for Server this is very weird I know uh I don't know why this is said this way but we need to follow what's made and we can do console.log connected connected to server basically this is like just for that you don't need to Nest listeners in the client side now you can work on like um The Listener which says like getting players like uh let's work on the players event first which gives us all the players so IO instance uh hold on I'm just going to copy it all righty it says io instance. on players uh we get the players so you can have like a okay let's go back to our server I want to show you this like how the params thing works so if you go to classes let's check the any players thing so like if wherever we sending players we are sending this do players directly right we are sending an array with the ID score and name which which which apparently matches the type here so in uh game. TSX it matches type so the thing you send in the argument you can get as an argument as a function it's that easy it does all the hard work behind the scenes you can simply do it like this I like this very much about socket iio so yeah you get all the players and you just set it to your state and your state can render the UI as needed then we need a player joined so like if a new player joins inside your inside the lobby you are in right now then this will execute it will take the previous state of players and it will add the new player into your state for player left we want to implement something like this these are very simple simple stuff all you need to do is manipulate with state so player left we are just filtering out the player out of the array and updating the state and player score so like uh if we get a player score event so like if uh score of any player updates what we want to do is uh yeah we need to import the type first so like what we are getting is like we are getting the players we are looping the players and we are seeing if the player ID is equal to the ID which is which the websocket is mentioning if the if the match is found we are updating the score and yeah we is returning the player and we are updating the state so whenever we get a score player score event we are basically updating the score for that specific player which the websocket is telling us so that's how it is working we still need a more we still need more events here so we need game started game finish so the game started event basically does this uh game started event takes the paragraph and we are setting the paragraph in the state and we are just setting game status as in progress and uh next we need is the game finished listener we have worked on listeners so many times in the server so I don't want to use a lot of time just typing it out myself I hope you really understand because uh this does should not take a lot of time so yeah like if you want you can even go and copy from my giup repository I'm just saying that uh but if you're a beginner like very very beginner I would still recommend like typing it on my yourself I think I'm very experienced and since this is a YouTube video I don't want it to go long that's why I'm doing this uh I think we need only two more uh listeners so I'm just going to copy those uh okay I I I forgot to explain the game finished on we are just setting the state has finished and we are setting the input paragraph As empty so that like we are resetting the input box of the user so so that they are prepared for the next game all right so io instance. on new host like whenever we get a new host we are changing the current host according to the client and we are setting it in the state and then we have io instance. on error we are just to start erroring that message so like I showed you the sonor thing right so like whenever we get an error from the server we are displaying it in a beautiful toast so yeah that's basically what we are doing we need a a few more functions here which is like U remove listeners function so yeah this function is going to basically remove all the listeners so it's going to do I instance. off and we just going passing the event name for all the events we created before like listeners we created before so like when the component unmounts we want to remove all the event listeners as well so that there's no performance issues and stuff all right so we need something like uh we need a start game function function which we are going to eventually map to a button uh it's just going to check if the web socket is connected or not if not it's just not going to do anything if it's connected we are going to emit the event called as start game and um yeah it is going to check if like the server is like we we worked on the server right it's going to check if the current person is host or not if not it's not going to let us do it all right so the next thing we need uh it's nitpicking it's not really you need it but I think uh it makes things a lot easier so like when somebody tries to close the tab we want to actually leave the leave that specific uh room so that uh what happens if you don't have this is like if you close the tab away the players do not get updated suddenly so like uh it takes like a couple of minutes for the players to get updated and for the player to disappear from the lead up boards but if you actually close the if you actually uh leave the room before you close a tab so like this says that before closing tab leave the room so like if you leave the room before that will be like the leader board will be updated instantly for everyone else so I think this is a good quality of life thing and now we will work on the actual UI part which is here it is going to be a little complicated so we are going to work a little bit on it so first of all we are going to have a div so I'm just going to copy step by step so this is going to be a div parent div which is going to have a width of screen padding of 10 we are going to use grid and uh this is responsive by default so that's why we have using Tailwind responsiveness here here what we want to do is uh I'm just going to copy the leaderboard because it's pretty straightforward code and it does not uh need a lot of things but before we do that we need to create a component called this leaderboard card because if you know like there can be many people in the leaderboard right so we need to create a card for each of them inste instead of like creating uh all of this nesting stuff here we actually should create a new component so instead of the components folder I'm going to create a new leaderboard card component. TSX this is going to pretty straightforward just a little bit of styling stuff so I'm just going to copy this and just pasting this so we are just getting the player and the rank from the uh actual um as props uh the player is going to from the player type that we have all the access to the player name and the player score and then we are getting the rank and we are just displaying the rank here and this is basically all the styling we using the card from Shard CN now we can save this and we can go back and we can start working here so hold on so where is my file all righty so what I want to do here is uh first of all okay this is going to be the leaderboard part so this is very straightforward I have the comment here so what we are doing here is that we are sorting the players like um we are taking them and we are sorting them with the scores like we want the one with the most score to be on the top right so we are sorting that array in that way and then we are mapping it uh we are looping it and uh we are uh rendering a leaderboard card for each of them and for the rank what we are doing is we are using the index so like we already know that the person on zeroth index will have the most score so like uh we are just and we don't have rank zero right so we're just going to add one to it so like the ranks the index zero will be rank one and so on so like if there is uh some person with index three the rank will be four because array start with zero people do not start with zero all right so the leaderboard stuff is done now we need to actually work on the game and there is a few things we need to work on here uh we do need actual um container which is going to be same for uh all of the cases we are going to create which is like U basically working with the grid columns now what we want to do is we want to check some cases so I want to like copy paste codes in very um modular way so like hold on so let me import the button yeah so what we're doing is like we're checking if the game status is not started the game has not started yet we want to render this U waiting for player to join and if the current host is us like if the io instance. ID IO instance. ID means that the current websocket connections ID if we are host we want to display this button and we are using the start game function which we just created above which just uh start we just uh emits the start game event to the server so if only we are host we are going to render it if we are not the host we are not going to render under it so this is the logic for like uh if the game has not started for the game in progress we are going to have this one so I'm just going to copy this one and we're going to paste it I'm sorry for the copy pasting I think that uh we should not be doing a lot of this uh typing and stuff it's already taking a lot of time and I think um if you take a pause and look at the code you will understand it properly we also need text area so let's install text area from um here so let's go to text area let's install it you can use the HTML text area as well it's fine but I just want like to use chat CN so yeah let's install it all right now we can just import the text area and we can save this file so that everything gets formatted in progress what if the game is in progress ress there is a lot of things we are doing to be completely honest and it doesn't really look that uh good as well like it is very cssc hacky thingy so like uh what we are doing so like uh first of all we have a type of paragraph below which is pretty simple now this is the part which will be a little confusing so if you saw the demo we had a text box where we typed things like it wasn't a placeholder right so if you type something the thing in the background remained so like you knew what you had to type in that specific place and you cannot achieve that with placeholders because if you type something the placeholder disappears so how do you achieve this kind of behavior what you can have is you can have a P tag with a paragraph inside it and you can make it uh you can make the parent as relative you can have this here and what you can do is you can lay a text area over that text and you can set the opacity so what will happen is that you can see the text but you can also see the text area on it exactly on it and you will also see the text under that since you have the opacity as low so what we are doing we have a p we have we are just rendering the paragraph as usual so for text area what we are doing we have the same things so like we have the p uh we have the text 5 XL for large text 2 XL for small we have the padding five which is small and then we are setting it to Absolute which means that we want to uh Break Free of the normal rendering and we want to actually go and uh display our element as like um we want to we want to control the element's position manually we don't want to adhere to rules anymore so what we are doing is we are exactly positioning it around the paragraph so like if the paragraph is this long uh look at my with the hand so if the paragraph is this long the text box will be this long if the paragraph is this long the text box will be this long so this is just mentioning this Z index 10 means that the input box needs to be above the paragraph itself so that the person actually click and type opacity 75 uh since uh we need to reduce the opacity because if like we have opacity 100 then we will not able to see the paragraph behind the text box that's why we are doing this and of course this will be disabled if the game is in if the game is not in progress or if the socket is not available right now so yeah this was a little complicated but I would really like if you like play around with the CSS here and try to make it a little better uh this is really janky code right now to be completely honest this might work this might not work but I think for a tutorial purpose this serves a lot of um education so I think um go ahead and make sure you do something flashy here and just make something great so we have one last part of the code this I hope this is the last part of the code because I've been doing this for a very long time all right so if the game state is finished we are just going to say game finished and if we are the host we are going to say say restart the game fresh if you're not the host we're just going to say game finished if you are the host we are going to see the start game button again that's it so yeah this is our game now we should be able to play the game if we go to our thing we are already here right like remember we had like the 404 thing and we just left it here we already started a game but I don't want to go here I want to go to the entire flow let's try it out everything I'm going to create a new game I'm going to enter my name as a tera waiting for players to join start game we are the host here so if I just copy the ID this is the ID we need if we go here and if we go to local 3,000 if we paste the invite code and join the game if we Noob Master okay I just deleted it but okay Noob all right what's wrong I think the server restarted or something okay let me try something again what's wrong here okay so something definitely seems wrong here it does not I think something definitely should be wrong on the server side all right this stupid mistake look at this we are listening for players event we are not listening for player event we need to change this to players see how one simple typo can mess you up so bad okay let's go ahead and let's we restarted the server so we need to uh refresh this if we refresh this we should have AA here we are not the host here Noob is not the host we are not seeing the button but aara is a host and we are seeing the button here so I'm just going to go and start the game I'm going to say before here and complete one word and it's not in taking the word for some reason and we need to fix that as well oh yeah that's because we didn't even make the logic in our game. TSX file I thought that this front end was over but we didn't create a logic to actually send the keystrokes to the server right the key the server doesn't even know that you are typing right now so how do you send the keystrokes it's a very simple code uh it's the use effect actually you can do many different ways but I chose it to do it in a use effect manner so this is the use effect code so I had a comment here so what you can do is you can first of all check so this user effect is run whenever input paragraph change when will input paragraph change whenever somebody type something into text box so this that time this state will change and this use effect will run again so we are checking if the socket exists or not if it does not exist we are going to return and we are also going to check if the game is in progress or not if it's in progress we going to just return we are not going to do anything and if everything is all right we are just going to do IO instance. player typed and we just go in input paragraph I think now it should work I think we should not face any weird bugs about now so I'm going to refresh this yeah so Aura is the host I'm going to start the game I'm just going to say unfortunately comma that is is wrong and for Noob I want to say unfortunately that is wrong on the contrary you see now Noob is one even though otherwise host Noob is one because that uh actual leaderboard updated the socket is sending us the leaderboard updates constantly so like if you go to web socket here so like uh okay we need to actually reload the page here um I'm going to do that right now so reload the page page oh yeah the game has started what I'm going to do is I'm going to just go to local 3,000 again and create a new game a thir one I'm just going to copy this and I'm going to paste it here this is going to be Noob now we do have a websocket right I'm going to monitor this so there going to be a lot of events because since we type everything is going to go there so if we we have newb here so if you start typing this is responsive that's why you are seeing it like this to be more specific authors often yeah I think I'm just going to leave it like that and here I'm going to say to be more specific authors often Mis interpret the I think that's that's that's fine so Noob is first so you are saying player score so you are getting the actual events of the player and uh if I bring this up if I look at one of of these events you are seeing the ID of the person uh which is actually Associated to Noob and you actually seeing the scores so the current uh score is eight and that's the latest event so they have stopped typing so you're not getting any player score events anymore so yeah that is how W sockets work and if something is not working that's how you should inspect it so I think I want also want to show you the responsiveness so if you go like this this is the mobile version so you can see it's I think it's pretty responsive I think that every part of the website is responsive responsive if there are any things you can add on it I would really appreciate it GitHub is in the link you can go ahead and open a PR please do not open spam PRS I really want only productive ones and not like update read me and stuff please do not do that we have a drama I have a video about open source contribution being like spam open source contribution so please do not do all of that stuff so yeah people we have finally done with the typ racer kind and a typ rer clone okay so we are done with the video we are done with the typ rer Clone we have actually built typ rer clone using nodejs using socket.io which is a library for websockets and we have used nextjs and we have used the latest and greatest nextjs app router within which we have used shad and UI which is also the latest thing going on right now so I hope you really like the video like if you're sticking it till the end like right now if you have watched the video till the very end I think I earned a subscribe from you so like just go ahead hit the subscri button hit the like button make sure you leave something in the comments below make sure you leave what you learned the most like what you found Most Fascinating in this build please leave that in the comments below lastly I wanted to share this video with your friends like if you if you have some friends who you think might get benefited a lot by watching this video I know this video is a long video but I'm pretty sure you understand how much I like to explain in this channel so like every single thing um yeah I do copy stuff sometimes but I really understand every single thing I copied so that you don't get left behind so yeah I would really love it if you share this video with your friends apart from that I would really love your suggestions like is there something you want me to build just like this typ rer clone is there something you would like me to build I'm not going to create exact UI to your clone this is not really my goal my goal is to create something uh and explain the functionality of it uh so I'm not just going to go ahead and clone the UI stuff it's already been done a lot of times on YouTube so yeah go ahead and let me know and yeah watch out for more more of my videos I pretty sure you will like my content so yeah that's it for this video I'll see you guys in the next one bye
Info
Channel: Atharva Deosthale
Views: 3,528
Rating: undefined out of 5
Keywords: programming, programmer, reactjs, react, shadcn, shadcn-ui, shadcn/ui, shadcn/ui documentation, shadcn/ui components, stunning react components, typeracer clone, typing speed game using nodejs, using socket.io, websockets tutorial, socket.io tutorial, typeracer websockets, websocket, websockets, ws, node.js, node, node.js websockets, node.js server, typeracer clone node.js
Id: haIZ94Gwf3k
Channel Id: undefined
Length: 108min 31sec (6511 seconds)
Published: Wed Mar 06 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.