How To Make A Game With Unity Multiplayer Netcode | XR Multiplayer Rig

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
what's going on everybody it's elmer and welcome back to my channel so in today's video i'm going to continue with neco for game objects and specifically we're going to be looking at creating an extra rig that is going to be multiplayer this means that we can create virtual reality experiences where we can have many clients connecting to it and also interacting with different objects in the scene so i'm going to walk you through the entire process we're going to be creating an extra rig we're going to be adding an avatar we're going to be mapping different actions on the controllers there's a lot to do that i'm really excited about it so let's jump into unity and start working on it all right guys so the first thing that we're going to be looking at is creating an excel rig so the way that i have this set up and this is going to be checked into source control is i have two different scenes one of them is the setup scene and the setup scene is the one that is going to set up the network manager we haven't created a prefab for the player used yet but we're going to be creating that in this video and i also have a canvas which is what you see right here so the idea is that we're going to be landing in this scene the local player there's not going to be multiplayer in this scene just yet but we're going to be able to select are we going to be the whole so we're going to be the client and based on that information we're going to go into a new scene and start either the host or a star the client so they give us flexibility to determine who we're going to be so we also have an xor origin in here which is basically extra rig that doesn't move it's just going to allow us to move our head and basically interact with the with the ui so once we have this set up we're going to be jumping into a new scene so if you go into a network manager we also have the scene transition handler which is going to take us to the xr multiplayer main i could cover more about these all this is doing is basically going to allow us to to switch scenes and be able to keep our network objects alive so the network implementation and the documentation goes in-depth into how this works but for now just know that it's available you can download it from the repo and this default main menu is going to be the main menu that we're going to be going into so that's the name of the next scene so we're starting in setup we're going we're going into main a couple more things that i also want to mention before we we start digging deep into the extra rig multiplayer is these are going to be the dependencies that i currently have we don't need all of them used yet because we're not going to be implementing relay i show you how to do that in a different video so in this video just make sure that you have the xr interaction toolkit which which i'm using 1.00 pre that a and by the time that you watch this video there might be a different one and i'm also using the unity.net code game objects and then this is a version and also the utp adapter so just make sure you have those before you get started because otherwise you know things might not work exactly as i show you and i'm also using unity2020.3.16 f1 so if you download the code from github make sure that you you use the same version at least or if you upgrade and you have issues let me know in the comments and i'll be able to tell you how to fix it okay so now that we have these scenes so if you go into file and then build settings you're gonna see we have the setup and then we're going to main so make sure you have those two added to build settings so if we go into main you're gonna see that this one doesn't have an xl rig right now and the reason for that is because we're gonna be creating that through the network manager it's going to create an instance of that it's gonna make it you know multiplayer because we're going to be adding a lot of components to that then we have the xr interaction manager because we're going to be interacting with different objects and obviously using an xray this component is very important the input action manager because it's going to allow us to use more of an action based inputs so we're going to be using the new input system which is hook into the xr toolkit so make sure you have that at it and you know you can just right click on it and then just create an empty object and then just associate the the input asset which is also part of the sample so if you go into windows and then package manager and we go and look at the excel toolkit you're going to see that we have if we go here into the price the assets that we currently have in our project and then you go into the xor interaction toolkit you're going to see that we have samples here so recommend that you download the basically the default input actions i also did the xr device simulator i don't really like it to be honest it's very confusing but anyways i have those two at it this one is really important for what we're going to be doing this one is going to be optional so make sure you do that so once you get those input actions you're going to be binding them to the action asset there's also a network startup which is going to it's going to determine whether it's going to you know start as a house or start as a client based on what happened on the first scene so if we're going to look at that very quick so that i can show you how that works basically at this point we should know that we're going to be starting as a whole so this is going to be a variable that we're going to be setting in the same transition handler and if we start as a house we start as a host if we start a client we start a client that way we don't have to you know we don't have to do any any other magic to to get this going the scene transition handler is going to tell us what we need to start with and if i have another computer starting as a host then that computer will be the host and then if i have this computer starting as a client then this computer is going to be like clients so just a very simple implementation okay so once you have that i also have a grabable which i'm not going to be covering a lot in this video just know that it's going to be spawning a bunch of different game objects that we're going to be able to interact with with the xr multiplayer component and i basically use a floor that you know so we can play the extra rake on i'm going to go ahead and right click in the hierarchy and then go into xr and we're going to be creating an action based component so make sure you don't do the excel origin do the xr origin action base and then this one we can rename i think i name it xr multiplayer we can say xr rig multiplayer and then once you do it you know you're going to rename it and then this is going to have an extra origin by default i'm also going to be changing the the tracking origin mode i'm going to be selecting device and i have a couple settings in here that we're going to be setting so this one is going to be the camera offset i set it to 1.36144 so make sure that you set it to that we're also going to be adding a locomotion system because we're going to be allowing this system to basically it's going to be a rig that we can move around and i can also do a snap rotation so we're going to be adding a couple of components to that i don't think this one is required but i always add it just in case it's going to add the reference in there i think if you don't add it it just coins it's going to look at the game object that you have right now to get it but i always add it just in case so we have those two added now we need to add what's called a continuous move provider this one we could go in and add it but i'm going to show you why we don't i'm not going to add it this way because i want to make sure that i disable it i disable the input if i am not the owner of the client so if i'm if i'm doing a networking game and i am the owner the one that has two inputs i'm going to allow inputs i'm going to allow the rig to basically move around but if i'm another client who is not who i'm not the owner of basically if we have multiplayer game with multiple clients i don't want to have the input cause other players to basically move so we need to have a way on the networking game to to be able to disable this and i want to do is just do this i want to just disable the input so that's what i'm going to be doing let's go ahead and remove this and we're going to be creating a new component so if we go into scripts there is a network mode provider that i already have so this one is going to be very simple we're just going to do serialize field and then bring in the unity engine namespace and then i'm going to say private bull enable input actions and the reason why i'm doing this is because i'm like again i'm going to disable it from the other client so and then i'm also going to be doing a protected override and then we're going to be overriding the read input basically it's going to go into this class and it's going to override the implementation of it but we're going to determine where whether we want to read the input whether we want to move or not so what i'm going to do is i'm going to say okay if enable if enable input actions if it's not enabled then what i'm going to do is i'm going to return vector20 so that way if we like i said if we are a client that is not the owner then we can disable this rig from moving at all okay so if we go back into here instead of using the continuous mode provider i'm going to be using the network mode provider which is also an action based provider so and then what we can do here we can add the locomotion system we're going to be enabling strafe enabling gravity and i think all of these ones are okay then the other thing that i did is we can you know this is going to be the variable that we're going to be set depending on whether we want to allow input or not i also going to be binding the left hand move action so this one we can say that we're going to move with the left hand so we can just search for left hand and i like to use the list here so we can see everything and then you're going to see that everything you really label everything in an easy way to find out so if we want to move with this component all we have to do is just select which hand we're going to be using and what property which is going to be moved so this is basically going to allow us to move with the continuous move provider now the next part that we're going to do here is going to be adding a snap mode provider and i'm also going to be using the action base i'm also going to be binding the locomotion system it's going to tell you if you're going to allow you know how much of a turn you want so i'm just going to do 45 the bounce time i think i left that by default i'm not going to allow this one to turn around i thought that was kind of weird i didn't like that experience but if you want to do it you can allow basically what happens this component is going to allow you to you can do a turnaround which is going to be you know basically you're going to be facing on the opposite direction if you use that this one is just going to allow us to move a 45 degree angle every time and then instead of using the left hand i'm going to use the right hand here and then for the right hand i'm just going to say right hand or you can just type in right and then you can look for so there's a move here there's also a turn so it's going to be the one that we currently use so we have a move provider we also have an app provider so now the next component that we're going to be using is going to be the actual character controller and i'm going to get closer in here so we can see everything that we're creating and some of the properties in here are going to stay the same we're going to have a slope limit of 45. this is going to stay at 0.3 i think the skin width i left it intact the center some of these are going to be set automatically by a different component that i'm going to be adding the radius is going to be 0.1 and then the height i'm going to make it i think i made the high about the same as the camera offset and if we do that you're gonna see that that kind of this is kind of how it's going to it's going to align okay so once we have that there's going to be another component that we need to add and it's going to be the character controller driver and this is also going to require that we're passing the locomotion provider so in this case i'm just going to add this component here and it's going to tell you what is what's the minimum high and these are going to be just left alone like we have it by default okay so that's going to be most of the components that we need to have that are core to the xr basically the xr origin there's really no networking thing other than this is just a component that we added but what we're going to be doing now we're going to be adding the the networking components i'm just going to do network object this is going to be the only component that is going to have a network object these is going to be the parent and then the child so i'm going to have different networking transform that we're going to be adding so that's going to be that and then i'm also going to be adding a client network transform this component it's one that i covered on the previous video but if you don't see it by default go into package manager and if you go into the package manager you're going to go into your basically where is it macro for game objects and you're going to see that there's also an examples which is called client or transform and what it is just to give you an overview if you haven't watched the previous video this is going to allow you to synchronize transforms basically from a client to the server and to other clients automatically without you having to specifically call the server and then do some magic on the server side to synchronize that to the clients so this one makes it really easy to work with okay there's one caveat to this and i want to show you what that is if you go into that component let's go ahead and go back in here there well the first thing that i need to do is i don't want to synchronize the scale because i don't i'm not going to be changing the size of the xor rig multiplayer so this is something that i don't need to do and then the other thing that i need to do that i have to make a change to the script is currently when these these when the object gets pan automatically which is going to be the player this is going to determine whether we can commit the transform or not based on the ownership so what this means is that if i'm the player if i'm the owner basically the local player and i own this object i'm going to be able to transform to synchronize its transforms basically we can synchronize the position the rotation in this case the scale won't be sync because i disable that but this property is the one that is going to determine whether we can do that or not and it's only going to happen for the owner so but this only happens when we span the object but if i am let's say that i want to start using grabables where i'm going to be able to pick up an object well i want to be able to change ownership if i have multiple clients because one client may want to pick up an object and move around and then i may want to also pick up that object so i need to be able to change ownership and if i only do this here i'm not going to be able to sync those transforms so i had to make a change in here and basically just add this line to to this check basically it's going to allow us to change who can commit that transform or not well if i'm changing the ownership then at this point i should be able to do that i'll show you more about this as we get to grabbing different objects okay so once we have that i think we're good to go with basically some of the main components the other thing that i need to also add is going to be one that we're going to be basically implementing in this video and it's going to be the network player so network player right now just know that it's just an empty c-sharp script but we're going to be adding more to it so the next thing that i need to do as well if we go into prefabs i also have this cool guy that i design is very sophisticated 3d and i make fun of it because i actually was looking for somebody to help me with this but just know that this is just a cool dude that i just created and he has an xr developer shirt so basically just you know sphere here a couple eyes a mouth the body and then a logo so nothing nothing crazy but what we're going to do with this guy is i'm going to grab them from my prefabs and i'm going to add it to the main camera and the way this is going to work is basically gonna allow me to you know to if i move the camera then this guy it's basically going to be moving the next thing that we need to do is we also need to change the position so for the position i'm gonna set it to negative 0.25 that way we can align it correctly and i also have the scale set to 0.5.5 and 0.5 so that's going to be you know if i move like i said if i move the main camera this guy is going to move there's also going to be a couple things that we need to change on the on the actual left hand and right hand controller so if we go into the left hand controller you're gonna see that we have an extra controller action base also an xray interactor which is gonna allow us to use array to to be able to interact with items so what i need to do here on the xr controller for both of them is let me see if i can do both at the same time looks like i can i'm going to select both of them and i'm going to change the model the model that i'm going to be using is going to be one that i already have in here which is going to be the controller and looks like i don't show it in there for some reason but you can drag it and drop it in here and if you go into it i can show you what it is it's basically just a simple controller that i have that i got from the xr examples that they provide in unity but you can download it from this project as well so once you have that you should have basically a model that is going to be instantiated automatically for you as a child of the left hand controller and also one of the right hand controller the next thing that i need to do here as well is not only we need to add the clan network transform on the xr you know on these other components but we also need to do it to the controllers because we want to synchronize the position the rotation of the controller so i'm going to add that as well here and once we do that we're going to be able to also uncheck the x y and z axis for both of them so just going to make sure that they're both currently set and then basically once you do that we need to just now set the couple properties on the extra controller so this is going to tell us what we're going to be allowing and i'm going to be allowing enable input tracking because we want to basically do input tracking on it we also want to do input actions so it's going to be things like selecting these are going to be things like rotating the controller and positioning the controller and then that's basically how those so i'm going to go ahead and quickly set some of these ones because they're going to take some time so that's everything i really do on the left controller and the the right hand controller so basically have just all the action bindings we also have the action bindings for the left and right hand and also the controller component is now set up so the the next thing i wanted to do which is going to take some time is going to be implementing the the network player so we're going to be focusing on the network players so that we can also disable some of the movement on the clients versus the moving on the owner so the first thing that i'm going to do is i'm going to be doing a serializable field so it's going to be private and this is going to allow us to determine the placement area of our player i did something like this on a previous video so if you look at the previous videos that i did on ngo then you can you know you can learn more about that but basically it's going to be set the players on the plane and then i'm just gonna do negative 10 to 10 meters and then the next thing that i'll do here is i'm going to override the network span so we also need to make sure that this is going to be the object that we're going to be inheriting from which is network behavior and it's going to be you know all coming from that code so make sure that you do that and then the next thing that i'm going to do here is i'm going to be overwriting so i'll just do an override and if you don't know c sharp that while overwriting is basically overwriting the implementation on on the parent in this case we have these different methods that we can override because they they're actually virtual and then we don't need to do any of these what we're going to do here is going to say disable line input which i'm going to be implementing down below and i'll just copy this because i'm lazy i'll just do void and then copy paste okay so the the first thing in here that we need to know is are we the client right so if we're not the client and actually what i'm going to do if i am the client and i am not the owner because hopefully we have we don't want the server to do things that are specifically to the server in this case in this case we want to determine okay if this player is the owner and basically it's a client then we want to allow we want to allow people to be able to move to use input actions but if we're not the owner that means that it's a remote player right we don't want to be able to to change the position and rotation of those basically of those players because it wouldn't be fair right we're going to be we're going to be moving other players which doesn't doesn't make any sense okay so i'm going to do client move provider so what i'm going to do here on the next step is going to be basically disabling everything so let me go ahead and get all the components and then i'll show you here in just a second all right guys so just to give you an overview of what we're doing here is first we're going to be as soon as we expand this client we're going to check and see if we have ownership if we don't have ownership we're going to be basically getting all the different components that we want to disable for the remote client we're going to get the move provider the controllers the term provider the client head the client camera we're basically going to restrict them from doing anything so we don't want to cam multiple cameras to be enabled in one game because it's not going to work so we're going to be disabling the camera we're going to disable the movement we're going to disable if the character can turn or not and i'm also going to be disabling whether i can that character can rotate basically can get input and rotate the head which is going to rotate the avatar we don't want this to take control of that because we want this to come from the clan transform so that's why we're doing some of these and then i'm also going to be disabling the basically the left hand controllers and also that right hand controller so now that we have that the next thing that we need to do is i'm going to do private void star and this is what we're going to do to basically place the object so i'm going to say the same thing if this is a client and well in this case it's going to be if i if i am the owner because i want to basically only position the the player that where i am actually an owner of otherwise the clients are going to be sending me their position and rotation so i'm just going to do transform and then position and then here we're just going to do a vector three i'm gonna get random that range and if you remember on the very top we have a placement area so this is gonna be placement of x placement of y and then for the position of of why what i'm going to do is i'm just going to use whatever we already have i don't want to change it and then what i'll do here i'll also do the same thing and instead of using random that range i think i just use range there we go because the other one is deprecated and then i'll just use these right here for my z-axis as well so this is going to allow us to basically have the initial position be random so that way we don't keep the the player in the same area the next pieces are gonna be you know what is going to allow us to take ownership and i'll show you more about these in future videos but let's go ahead and work on it because i think this is going to make the experience a lot better so we're going to do on select grabable and it's going to be executed whenever we basically we select an item with the trigger button so i'm going to do select enter and then arcs and then i'm just going to do i think this one i just did event arcs and then again in here i'm going to say okay if i am the client and then i am the owner of this current current object so i just do the same thing here so the first thing that we need to do is we need to basically know okay what is the network object that we're trying to grab and for those for those of you who haven't done anything with grabables there is an xor grabbable component that you can add to anything that you're going to be able to grab and i'll show you how i set those up okay so if you're going to prefabs you're going to see that i have cue blue cube red cube y sphere blue and red so if we double click on one of these this is all the components that we have so it's basically just a cube with a box collider also has a rigid body and it has what's called an xr grab interactable so just make sure you add that component i didn't change anything in here this is all the defaults and then i also need a network object because it's going to be an object that we need to expand through the networking system so that we can synchronize that and i also have a client transform script without the x y and z scale because this object is not going to be changing the scale and i also have a network rigid body because this one is using well in this case it's always kinematic but if it wasn't then and you want to synchronize the physics you're going to have that that object in there i'll just add it for now and then the other ones are basically the same so if we go back into here we need to get the network object component so i'm just going to say network object and then in here i'll just say network object select it and then i'm just going to get it from the interactable object and then i'll just do a transform and get component [Applause] this will just do a network object so it's going to give me the network object of the actual object that i'm trying to interact with so once you have that i i would do this just by default just in case you know somebody disconnects and something happened it's always good to check so it's going to check if network object is not no then what i'm going to do here is i need to say okay i want to request ownership from this object to the server right because the server is the one that owns these objects anything that we span through the spamming system it's going to know the spamming system the spawning system is going to be on by the server so if we go into graphable creator anything that happens in here and i didn't cover this because i covered this in a previous video but whenever you use this which is called the span you're going to be basically it's going to be from the server the server is the only one that can do these kind of you know spanning of objects so that's what i'm having here if it's a server and if it's a host then i'm going to allow this object you know we're going to be instantiating this object and then we're going to spanning that object so so in this case i am selecting an object so i need to tell the server a server can i get ownership of this object obviously there could be collisions if we have multiple clients trying to interact with one object i'm not gonna be you know handling those collisions right now but it would be good in your experiences if you know okay if an object is trying to be grabbed by by two clients at the same time you need to be handled concurrency you might need to check okay who is grabbing that object first or you want to add some kind of priority to that for now we're just going to assume that it's going to be one client you know grabbing an object and then another client grabbing a different object or i let go of this object and then the new client grabs the object so we're going to be requesting ownership to the server or from the server so let me do around the server so i'll just do something here like request grabable which is going to be owner which is going to be the name of the the object of the mentor that we're going to be requesting ownership from and then i'm going to say server rpc and we'll come back into this because i need to implement that method and then if we're doing a server rpc remember we need that attribute and it's going to be public void and then we're going to be using that name new owner client id it's going to be the client id that we're going to be giving ownership to and then i'm also going to be using something that i haven't used in the past but this is how you can basically pass a network object reference to the server so it's serialized correctly when the server gets it and it's called the network object reference so that's the first time that i use that it actually works really well and then what we'll do here is i'm just gonna say okay you know what if i'm passing that in i need to get it out so i'm gonna try to get it and it's gonna be try it's going to be basically getting a now variable and then this one is going to be a network object because it's going to be the the type of object that we're going to be trying to get out and then it's going to be just network object the reason why i put that in an if is because if this can get it out of the out of the reference then it's going to be successful otherwise it won't be able to if that if it can't find that network object reference then this is going to be false so we won't be able to change ownership and then i'll just say network object change ownership and then a change ownership is going to be basically a new client if for some reason you can get ownership you can do something here like logger or you can use the debug that log we can say something like log info or we can do perhaps log warning and then we can say unable to change ownership for a client id and then we can pass in the client id that we're passing here and then we can do our string interpolation which you guys know that i love a lot and then in here we can go back and say okay this is a client so now we need to pass in okay what is going to be the client that we're trying to get so this is going to be the owner clan id so it's the player the owner so i'm going to be passing my own id because i'm the one requesting for ownership and then i'm going to be passing the the reference of the object that i'm currently selecting so this is how that's going to work it's going to run on the client side and then if i am the owner i'm going to get the object that is selected as long as that object is not null then i'm going to say hey server can can you give me ownership of that grabable and if that if everything works then i should be able to move the you know that object around as a client owner okay so that's everything that we need to do here let's go ahead and go back make sure that everything in here it's compiling it looks like everything everything is working just fine so the last thing that we need to do is beyond you know beyond actually testing this thing is i need to make this a prefab so it's going to go ahead and drag it and drop it into prefabs and we can go ahead and delete this and remember the player is going to be creating from the main scene so well the setup scene which i call the main scene is actually confusing the main thing is the one that we're going to be using to do the networking the setup scene is going to be that basically all the initial setup for everything so on the player prefab of the network manager we're going to be going into prefabs i'm going to drag and drop this component here and also drag and drop this component make sure you're using the unit transport that's going to be the one that i'm using for this video and that's basically everything that we need to set up in there all right guys let's go ahead and play and make sure that we can connect i have the oculus quest also connected you can see that i can move everything around so remember in this case i want to make sure that i select the hose so i'm just going to go ahead and select the hose and then as i look at you can see that we have couple cubes around i can also start looking let me see i'm going gonna see if i can move and i can currently rotate but for some reason i can't move the the player around so i can rotate it but i cannot move let me make sure that the avatar also looks correct i'm gonna go ahead and expand couple components here and then look at my little guy here and i think the little guy is looking okay i can't i can rotate looks like i okay so the only problem that i have right now is i can't move the component and okay so i think i know why it's because this one needs to be enabled by default which is gonna be enable input action so let's go ahead and fix that i'm gonna go into my prefab here and in the more provider remember we need to enable this by default but disable it on any remote clients so i'm going to go ahead and save that and make sure that okay so that looks good go ahead and hit play and let's try this one more time and okay so that looks okay so i'm going to go into a vr here and start the hose and now we can move around right i can rotate i can select an item except these ones are gigantic so let me grab one of these little ones i can select it with one hand and the ownership of these objects are changing in real time and i'm going to show you here in just a second to basically to do it with a different client and if we go back into here let me go ahead and make sure that everything looks okay so i'm going to go into my scene view and i'm going to expand the multiplayer and i'm going to go into my xr rig multiplayer and you can see how the object you know the avatar is changing obviously there's improvements in here if you didn't want to move the body you can change that and i can move the player here i can rotate it i can also if i move this you can see how the rays changing to y when i select an object if i wanted to select that object which is going to be gigantic and you can obviously change this so that it doesn't collide with your head so let me go ahead and get another clan connector and show you how that works all right guys so i got currently two clients it was kind of tricky to get it working but you guys can see this is the second player i can move the player i can move the ray and if i were to move the controller on the other player you're also going to see that also also moves i can also if i wanted to let's see if i wanted to move the other hand i can also move the other hand i can also move the player if i were to put the headset on but i can also interact with this right so this was the key if i want to interact with an object let me go ahead and get back into here and if i want to get closer let me go ahead and get closer in here and this is where i wish i had more more help to do networking and multiplayer there we go so i'm going to go ahead and grab this object right and right now i own these subjects so if i wanted to move around and so i'm going to go ahead and put it right here and if i wanted to basically grab that same object with the other component with the other controller i can also do that so i'm going to go ahead and take off this controller this oculus quest and i'm going to go ahead and put the other oculus quest so we can also interact with that same object so i'm going to go ahead and put it on and then see where i am and we can see that i can get let me get closer so that you guys can see it right in the view i see the other player getting here i can rotate and then i'm gonna also grab that object and as i grab that object you can see that now i can rotate and interact with the object i can put it right here let me see if i can grab it with the other controller unless it's already okay so i have to put it on to to show you but that was basically the idea is that we have multiple players the other thing that i got to show you here is you can also look and see the different properties so remember this one is the one that we currently own which is the oculus quest ii the other one is running on the oculus quest one so on the oculus quest one if i look at the network object you're gonna see that let me see here yep you're gonna see that this is the one that is currently the owner and the local player and if i were to actually this one is the oculus quest two this one is the oculus quest one and i know that because this is currently not the owner the owner is going to be this other object but but basically that's everything that i wanted to show you guys if you guys have any questions let me know and also don't forget to subscribe because it's going to help me in bringing you a lot more videos thank you guys
Info
Channel: Dilmer Valecillos
Views: 1,438
Rating: undefined out of 5
Keywords: unity xr multiplayer, normcore, mirror, photon unity, virtual reality multiplayer unity, vr multiplayer unity, xr multiplayer unity engine, unity relay server, unity relay server price, unity relay service, unity udp, unity udp server, unity udp networking, unity transport, unity multiplayer, unity multiplayer 2021, unity multiplayer game tutorial, multiplayer networking, new unity multiplayer system, netcode for game objects, unity netcode tutorial, ClientNetworkTransform
Id: pl6Pbb43E-Y
Channel Id: undefined
Length: 35min 34sec (2134 seconds)
Published: Wed Dec 08 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.