*IMPORTANT: these tutorials and the code in them are outdated!* I've been working on RiptideNetworking (a _much_ better multiplayer solution) for the last year, and I finally made a tutorial on how to use it: ruclips.net/video/6kWNZOFcFQw/видео.html
What do you mean by "outdated" ? Did you simply switch to Riptide because of preference, parts code got deprecated, or is it performance related? If it is just preference, I guess I dont mind following this series to make my own net solution. Because this is a very detailed explanation, one of the best networking tutorial, so thank you for that. I have already watched through the first 3 videos before to complete a freelance project with udp support, but now I wanna make a full server, at least for the same network, to maybe scale it to dedicated server later. If there are things that are done suboptimally, or performance bottlenecks with this method, then I guess I will switch too.
@@sadiqabbaszade4789 Riptide was a complete from-scratch rewrite. I kept the "interface" (how you as a dev interact with the library) pretty similar but all the internals underwent drastic changes. The solution from these videos is less performant, poorly designed & not modular (statics everywhere) which makes it hard to maintain and work with, and I think there's an issue with UDP when you connect more than a handful of clients. Riptide was the result of my desire to resolve all those problems-it has more features and is faster, cleaner, more modular, easier to work with & maintain/adapt, and better-tested with many bugs having been found and fixed with the help of the community. Riptide is quite literally better in every way. The one reason I think it may still be worth watching these tutorials is because they go through things from scratch, which can be helpful if you want to see how networking in C# works at the lowest level. However, even then I'd suggest watching these videos and then using Riptide in your actual project. Riptide also has documentation: riptide.tomweiland.net/
There's a number of things that could be causing this problem-troubleshooting is hard in the RUclips comments, so I suggest joining the Discord server if you need help (link in Description).
I had this problem too. I double checked my code with the one on GitHub and find out I had written "(socket.Connected)" instead of "(!socket.Connected)" on ConnectCallback method. Hope this helps someone
This happened to me, make sure you check that you're using stream.BeginWrite() instead of stream.BeginRead() in the SendData method in the servers client class.
After watching this tutorial so many times in the past and improving my type speed. I can finally watch this video at normal speed without pausing or rewinding.
I'm glad you like the speed! I personally don't like it when tutorials are really slow, which is why I made these so fast, although I'll admit that the first few might've been a bit _too_ quick :P
This is simply amazing. I have tried atleast 15 other videos and I kept running into errors and didn't understand shit. FINALLY!! A GOOD VIDEO WITH GOOD EXPLANATION AND CODE THAT IS STILL FUNCTIONALL!!! U DESERVE MORE LIKES AND SUBS MY MAN!!!
Awasome series, already helped a lot, and since I don't really see it mentioned I think it's best if people new to coding know. The reason the server used 7% cpu, was because the code inside isn't "once it's time update" but "is it time?no. is it time?no. is it time? yes. UPDATE!" that is why the sleep helps, since the code thinks you really wanna check if it's time on repeat.
Duuuuuuuuuude I've searched many times for tutorials just like this one and I never found one that was exactly what I wanted. Thank you sooo much for your effort.
I 100% agree. I had a pretty low level Networking Tutorial that I followed about 5 years ago. When Unity updated there networking it completely destroyed what I had and I barely knew how to use that. After that I pretty much given up on making anything networking. Then I stumbled upon this and my fire is lit back up. I truly am thankful for all your hard work. Sorry for the life story that no one asked for lol.
When RUclipsrs are better teachers than the ones in the actual schools. Sure, I had to watch some other videos related to the topic as I learn more from pictures/animations but this is already a working code that you just have to go through with your mind and edit to see what changes.
Although this tutorial is outdated but still helpful to learn how low- level networking works. Will still watch almost these tutorial and jump into your new tutorial of RiptideNetworking. Huge respects!
I like tutorial like these building from scratch! This is actually beneficial to everyone than using "pre-made" stuffs that when time comes that you want something to add or look under the hood you are doomed for eternity.
*Check out the next tutorial where we implement support for communication through UDP* 👇 ruclips.net/video/QajkUJeypy4/видео.html Also make sure to subscribe so you don't miss future videos: tomweiland.net/youtube-sub
@@MrPotatoHQ I'm aware it's fast, but at this stage there's nothing I can do about it. These were my first tutorials and at the time it didn't seem _too_ fast. You can slow down RUclips's playback speed, and all the code is on GitHub, so if you're really determined you can certainly find ways to follow along. Also in the later tutorials I've slowed things down a bit, so if you can push through until you get to those you'll be fine.
@@MrPotatoHQ yep, the networking side of things is entirely independent of how many dimensions your game uses-although in later tutorials (player movement for example) you'll need to change my code to work for 2D (mainly just swapping out Vector3s for Vector2s).
I'm getting this error "Assets\Scripts\Packet.cs(21,18): error CS0542: 'Packet': member names cannot be the same as their enclosing type" I have been stuck for hours lol
These tutorials are unique, Every single multiplayer tutorial, they use some servers online. While this one Makes everything from scratch. I love it dude! Btw: Legend still says you're replying to comments
I'm only this far into the playlist, and I just gotta say, you're a genius, now I am making mine read .ini files for other people to make their own servers on my game, so mine is getting heavy adjustments on what the server information is, however, I just gotta say again, this playlist tutorial is just the best, here's a sub.
This series is helping me a lot. I don't know anything about creating servers. When I see you go through all of this i'm just like how the hell could anyone figure this shit out.
I'm glad you've found it useful :) I was in your position two years ago and felt exactly the same way. The Microsoft docs have all the info, but actually putting it together in a way that works is a monumental task. Most of the TCP stuff came from some videos by Kevin Kaymak, but the UDP part I pieced together on my own using the docs & Google (but at that point I was somewhat familiar with the general concepts, which made it a bit easier).
I just transferred the code from console to unity like in your guide in tutorial 6. I also finished integrating a database to the server and had my FIRST TCP transaction where client trying to access data from the database. It was tricky at first but your tutorial is really good and code is self-documenting so learning was way easier. Thanks for the vids.
Amazing tutorial, thank you! And your discord server is nice too, actually helping people instead of making them look stupid for not knowing something.
Thank you very much, everything working, I'm trying to create this server with Node.js, I'm a beginner and I'm learning a lot here, the best channel I found, congratulations!!!
hi, thanks for sharing your knowledge with us, i live in Brazil, and here we have a few resources and information about C #, unity and socket at this level. again thank you very much.
That’s great to hear :) I’m not sure if matchmaking is something I’ll go into, since there’s a million different ways you could set that up, and it’s really about figuring out which players should be matched together (which is heavily dependent on the game). Once you get into the “multiplayer mindset”, matchmaking will become just another typical programming problem to tackle. Until then, you just need to keep working with this stuff-it took me several months of playing around with this to finally understand it to the point where I could do what I wanted with it.
No problem :) If you get to the end of this series and don't feel like you've got a good enough grasp on things yet, make sure you're not too hard on yourself. It can take time, and as repetitive as it may seem, it can be a good idea to build the networking solution multiple times from scratch. That's what I did, and it's amazing how much that helped my understanding!
Awesome video series honestly one of the best ones i' ve seen. When I press connect ( 9:35 ) I only get the : Initialized packets, message and not the welcome message. There isn' t an error message or something like that and I' ve checked the code multiple times but there doesn' t seem to be any problem with it. Is there anything except the UIManager, the Client and the ThreadManager I need to assign in the Unity Editor itself? (And the server itself of course)
Hmm, did you make sure to add an Update method in the ThreadManager which calls the UpdateMain method? If that doesn't help, join the Discord server and ask there-troubleshooting via RUclips comments is a pain 😅
I am a very big beginner in this topic, but I have found it helpful to sometimes just watch the tutorials without writing any code or doing any unity, as you don't have to worry about code it yourself, or worry about the syntax, and you can get the gist of what is happening much easier.
@@tomweiland I like that these videos are over a year old but you're still responding to comments! I'm on part 4 now and I'm feeling like I'm getting better at keeping up with you!
I often use Visual Studio in split screen, so I have it at that size to keep my code from getting cut off. I'll definitely zoom it in a little in the next tutorial, thanks for the feedback!
Huge respect to you, Tom, for this amazing tutorial series! I'm learning low-level networking with it's help. I like your idea, format, and explanation! But this amount of copypasting just drives me crazy, man :D You sure know that you can set up shared modules in your IDE between your client and server, my dude! :) Huge respect again, for everything else though!
I know you can add projects as references to other projects within Visual Studio, but unfortunately that doesn't work with Unity, as Unity regularly rebuilds the solution (and overwrites the references). As far as I'm aware, the only other good option is to use DLLs, but personally I find that more of a pain than just copy/pasting the shared code. As my personal project grows, I might switch to using DLLs, but I really do wish that there was a better solution to this problem :/
@@tomweiland Well, that's strange. It's actually hard to do in Unity's environment. So my best and very simple idea - is to have a shared folder on a server, and to copy its contents with a simple script to a client. Check it out, dude. It's very convenient :) Shared folder: github.com/NikitaShkaruba/among_us_clone/tree/master/AmongUsCloneServer/src/AmongUsClone/Shared Shared folder copying script: github.com/NikitaShkaruba/among_us_clone/blob/master/copy_shared_code_from_server_to_client.sh
For those people who want to implement utf-8 encoding. In Packet class change your Write method for strings >>> public void Write(string value) { byte[] data = Encoding.UTF8.GetBytes(value); Write(data.Length); // most valuable part buffer.AddRange(data); } In ReadString method change encoding to utf8 too. I hope it saves your time a little bit.
Oh my, Thank goodness you added those tags of where you are in future videos... I got so confused at one point then found out I was in the wrong place. :)
@@tomweiland It is so confusing having pretty much copies of code but they do different things. It also seems the footage is sped up x 10... Way to fast for me 😉
Another great tutorial that works just fine! Already added myself to the discord too and its filled with greaat people! Only small piece of advice, sometimes you do switch between screen a little fast XD Especially when copy/pasting!
Tom Weiland Can’t wait to see them! I honestly enjoy your videos and you deserve many more subscribers than you have. You explain very well and even have good video and mic quality :D
@@daxy5778 Thank you so much, I appreciate that more than you probably realize :) You sound like someone who would be great to have on our Discord server, feel free to come hang out there (link is in description).
alrighty done with video 2, watching the series first and then going to follow along the second time, would just like to say i have no idea whats going on or what half these words mean BUT, i am picking up more than i did from episode 1 because words or phrases are being linked in different places and uses so im learning what they are for and do, so hopefully ill get more as i continue :D
You are the only youtube tutorial maker that answers every comment on his videos I sincerely appreciate your works.Those aside I have a question.I'm fairly new to this networking things so I'm wondering if this setup has anything to do with Unity's upgrading on networking? And again thanks for this tutorials
It's nice to hear that it's appreciated, and although not many creators do it, there are a few others :) This setup uses .NET's networking features, so intrinsically it has nothing to do with Unity. You can use it outside of Unity if you want (like with the server's console app), but as you can see it also works with Unity. UNet is obviously deprecated, and as far as I know, Unity's new netcode is still in the rather early stages of development (although I haven't checked on it recently), which is why I personally am currently using this solution in my own project.
Hey at 10:56 you said beginRead Method and wrote a BeginWrite method what actually made me rewatch the video 4 times until i noticed that i wrote beginRead because i was not watching and just listening while i wrote my code maybe you could add a text there which tells this... this video still helped me a lot and thank you so much for making this series....
I think one or two others have pointed this out, but good catch :) Unfortunately I can't edit in text after the fact, so I'd need to delete the video and reupload it (which would reset views and search rankings).
Please I have two questions: At 15:42 the purpose of MainThread method is to call GameLogict.Update() always when 33.33 ms ( 1000/30) has passed? If yes, does Unity Update() method execute with the same delay? (to keep server-client consistently)
Yes, and no. Unity's Update method runs once each frame, so if you're running at 60fps that'd be every ~16ms, or twice as fast as the server. You'd want to use FixedUpdate instead and set your fixed timestep to 0.033 (like we do in the video)
@@tomweiland about that, I've also watched those Videos, but I am coding the Server in Python and i am Not sure If I can only use the Riptide Client without it's Server Out of the Box. If so, i'll definitely Switch :D
A cool little idea for people who might want to make this even "cleaner" - You can use the "Reflection" namespace and CustomAttributes for alot of cool things in C# and even automation. Currently we are adding another entry in our two enums for every server / client, networking method for sending and receiving. We are also adding this to our dictionary to pair the packet_ID with the corresponding "Receive" method for our packethandling. We are doing this for both the server application AND the client application. Instead of doing this, we can do some "Reflection" fuckery, to build dictionaries at runtime, given we set some rules / standards for the architechture of our application. This will allow us to simply add the methods to the "ServerSend", "ServerHandle", "ClientSend", "ClientHandle", or what ever classes you make after doing this, and "forget" about them, as our reflection will do the rest. This will also ensure readability, overview and low coupling as your project gets bigger. Now im not going into details, but rather leave some pointers to which direction to go in your research. And if you get this up and running, i'll assure you, that you'll run into another case, where this will save you some time in the long run. Reflection is very powerful and fun to use. How can we get information about a class AT runtime (when our application starts running)? a class we might not know about, at compile time (source code editing). How can we get access to the methods of those classes at runtime? How do we extract a delegate, from that method, at runtime? Can we use CustomAttributes, to get information about said classes and methods, at runtime?
I might have to look into reflection a bit more🤔 I've seen it mentioned here and there on forums, but never really took any time to find out how it works or what it's useful for-partially because (from what I've seen) people tend to say it's bad for performance. Thanks for the feedback though!
@@tomweiland It can be taxing for performance, but this is only ever a issue, when doing frequent operations that depends on execution speed. My usage, and for the idea above, its only using Reflection on startup, to map / build the ServerSend, ServerReceive, etc. And it is still fast nonetheless. ^^ Again, without going into details, if i want multiple "ServerSend" classes, but with names that give more meaning to the logic, ex: "RoomController" or "PlayerController", i just create that class, slab a CustomAttribute ontop of it. For the send and receive methods, within that class, i also just slab a CustomAttribute on top of those, the Reflection implementation will take of building a packethandler dictionary on startup. Im not even advanced at Reflection, but i bet there is so much overhead that can be removed from nearly any type of application, by using it.
I like this Tutorial. And even though I still don´t really know what you´re doing it´s really easy to just do some modifications to the code in order to make it fit my own games. :D
in Client.cs when i try to put "private Packet receivedData" on line 46 6:12 it doesn't recognize "Packet" Edit: in clientHandle it also doesn't recognize "Packet" on line 7
You probably copied the Packet class along with the namespace it's in. Remove the namespace and the errors should go away. If you need more help, I'd suggest joining the Discord server (link in description).
@@tomweiland I already removed the namespace. originally, it was in there, but i realized it wasn't supposed to be and removed it. so that definitely isn't the problem, im still searching for a solution. thanks for the quick reply though, i appreciate it.
How to fix 10:28 adding the client's username to the packet? I still got error: "Client" does not contain a definition for "usernameField" and no accessible extension method "usernameField" accepting a first argument of type "Client" could be found.
hay Tom! I got to 9:30, and I get 1 error on line 155 of the GameClient's Client.cs "The Name 'ServerPackets' does not exist in the current context" could ya help me out? :3
Double check that the Packet class and the two enums are in the same namespace as the rest of your code (since you may have copied the namespace part from GitHub as well). Beyond that, I'm not sure what it might be without more information. Remote troubleshooting is tedious in the RUclips comments, so if the namespace wasn't the problem, consider joining the Discord server (link in description) and ask for help there :)
I don't remember, and I haven't looked at this code in like 4+ years. It's also just a mess in general, which is why I've marked the series as outdated and strongly recommend using Riptide instead: ruclips.net/video/6kWNZOFcFQw/видео.html
Great tutorials. Thanks. I wonder how many people tried to "Update" their Visual Studio 2019 only to realize it was on Tom's screen? I'll be honest, I did!
This was a great introduction to networking, well done! However, one thing I need t bring up. You're setting yourself up for disaster down the road by using constants for the byte size of your primitive types. While an int is normally 4 bytes, that isn't always guaranteed. It is much safer to use sizeof(int) or sizeof(float) for whatever data type your are passing between the server and client.
If you've got any sources to back up your claim, I'd appreciate it if you could share those, as this is the first time I'm hearing about primitive types using variable byte sizes. Also, the docs on the sizeof method (docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/sizeof) indicate that sizeof(someInt) returns 4, and there's no mention of any exceptions. Nothing I've ever seen has ever led me to believe that primitive types' byte sizes can fluctuate in C#, but maybe that's the case in another language and you're getting things a bit mixed up? Unless of course you're referring to how a short is only 2 bytes or a long is 8, but even if you pass those types to a method that takes in an int, they'll be converted and the int will use 4 bytes like usual.
@@tomweiland It has to do with the computer architecture more than the programming language. I know in C when you need to worry about unbounded pointers knowing the size of primitives is very important. 99.9999% of the time, primitives will be the same size across different computers because there are a lot of standards in place. The only issue you'd really need to worry about is if those standards change sometime down the road, it could break your code. It's not really a legitimate concern I guess, just good practice. I loved the tutorial, and I'm sure you'll be fine leaving it the way it is for a long time to come.
Great tutorial! Thanks a lot! I'm up to just before you start getting the client to send data. I compiled in Unity, but getting an error that in the client's Client.cs, "The name 'ServerPackets' does not exist in the current context.' It's down the bottom in InitialiseClientData (I used the English spelling). Am I missing something obvious?
In the script client handle I have 16 errors saying the type or namespace packet could not be found (are you missing a using directive or an assembly reference) on line 9,22,32,43,54,62,70,77,86,93,102,112,123,131,139 and 150
When you copy/pasted the packet class, you probably copied the namespace it was inside of as well. If you delete the namespace your errors should go away.
Well if you're getting that error, it means one of several things: 1. You don't have a Packet class in the same project as the ClientHandle class 2. Your Packet class is in a namespace it shouldn't be in 3. Your ClientHandle class is in a namespace it shouldn't be in 4. You misspelled the name of the class you're trying to access, either when declaring it or when accessing it (aka where the errors are), so it's trying to find a class that doesn't exist Also be aware that sometimes Unity will fail to properly add a created script to the generated C# project, and it will end up in "Miscellaneous Files" (displayed near the top left in Visual Studio). If that happens, I've found the easiest way to fix it is to just delete and recreate the file from Unity and then copy over the contents. If none of that helps and you really have no idea what the problem is, join the Discord server and ask there (and show your code).
Hey! :). I am having some issues in the client class in the InitializeClientData at 8:55 because "ServerPackets does not exist in this context." It would be a huge help if anyone could help me out. Thank you and have a great day :D
i have an problem i got this error message " Error CS0051 Inconsistent accessibility: parameter type 'Packet' is less accessible than method 'ClientHandle.Welcome(Packet)'" in ClientHandle class and i dont know what is problem can somebody help me i am in 6:01 in video Edit i didnt have packet class to public it fixed my problem
Do you have a Packet class in your project? Is it in the right namespace? If that doesn't help, join the Discord server and ask there (and include the error message).
The last function of the client.cs (client side) " InitializeClientData()", unity show "ServerPackets.welcome does not exist in the current context", I copy your Github script to replace it, still have this problems, could you please advise any mistake of my process? thank you very much.
Hey tom, could you briefly explain the welcome enums? Specifically, if we are assigning an id of serverPackets.welcome to every packet to be sent, wouldn't that mean all packets have an id of 1?
Honestly? I have no idea anymore. It's been years since I wrote that code and there was a time when I had _some_ idea of what it was doing, but at this point I just don't remember. I'm pretty sure removing it causes problems, but I can't remember how or why 😅
Hello, I'm getting an error at different seconds after running the program ( 16:11 ). It says "A number must be non-negative or less than or equal to Int32" Please help, I'm not sure what to do at this point
4:23 Hi. I got it working, but here, we added 3 new scripts to unity. Yes, we attach ThreadManager. But Packet.cs and ClientHandler.cs, what to do? What uses them?
Ahh. ok. Client.cs uses ClientHandler which uses ClientSend and both of the last two use Packet.cs. Got a bit lost. Noob question; I didn't attach these scripts to anything. I thought scripts needed to be attached to an object to load. Do all scripts in unity just load at startup or when they are called by another method?
You only need to attach scripts to objects if they contain Unity methods (Awake, Start, Update, etc.) that need to be called or if you need to assign fields in the inspector. Scripts really just contain regular C# classes, and outside of Unity, you don't attach classes to anything-they exist on their own.
By having the second while loop, the server will execute multiple ticks in case a previous tick takes really long to execute in order to stay "caught up". I think you might be able to pull off the same thing using just an if statement and moving some of the other code around, but I haven't really looked into that.
@@tomweiland I fixed the problem. In the condition of while loop, I wrote _packetLenght > 0 && _packetLenght < receivedData.UnreadLength() instead of _packetLenght > 0 && _packetLenght
I'm kinda confused about why we needed the delegate PAcketHandlers? Also if you know any good links to understand networking I would greatly appreciate.
Without the packetHandlers dictionary, the server & client wouldn't be able to decide which method to call for each packet. To store a method in something like a dictionary, you need a delegate.
Please Help Me With My Error, I Dont Recive Welcome Message At 9:44 ServerSend.cs, Line 12; System.Collections.Generic.KeyNotFoundException: 'The given key '0' was not present in the dictionary.' Edit: I Changed The ServerSend.Welcome(0, "welcome") to ServerSend.Welcom(1,"welcome") Error is gone but welcome message is still not coming Edit 2: I am such an idiot i fixed it if anyone getting the same errors like me just check the code at github project you will find the solution :)
You'll probably want to have a master server to keep track of all the players that are ready to get in a game, and then just randomly pick some of them and connect them to the same game server.
During 5:09 when copying coded from game server Packet to unity Packet, I get an error saying "Error CS0542 'Packet': member names cannot be the same as their enclosing type Assembly-CSharp". Can you please help me how to remove this error? edit: found my error. thanks for the video
Hi Tom, I was wondering if there's any documentation to be read, that laid the foundation for these videos? Books, articles, guides etc. The videos were great, but I'd love to dig a little deeper into the subject, and get a solid understanding of the workflow. Thanks!
You can look through the Microsoft Docs since most of this stuff is in there, although I wouldn't exactly call that a great learning resources (the docs are good if you're trying to find out what a specific method/field does, but not really why or how it does it). In terms of just understanding the basics, regular googling is probably easiest-searching phrases like "TCP for beginners" should give you some useful results.
@@tomweiland Thanks for taking the time to respond. Yes, I've read most of the 'get-started-tutorials' on TCP using the client-server model written in C#. The documentation on Microsoft Docs is sparse, and severely lacking important behavior when it comes to the .Read() and .Write() for the NetworkStream class. What I'm missing from these tutorials is the way to construct the project itself, without having to duplicate code but rather reuse for server- and client-side. The guides I've read are mostly concerned with doing a simple chat by sending strings back and forth, but they rarely show a proper project with packing that allows sending more advanced objects to reconstruct on either side. So if your videos were based on some specific paper regarding that subject, it would be lovely to give it a read. Thanks again.
Unfortunately the networking solution isn't really based on any papers-I originally learned from Kevin Kaymak, and although I've modified his solution, there's still quite a few similarities. When it comes to the NetworkStream's Read and Write methods, I honestly think those are some of the more self-explanatory methods of this whole setup. They read bytes from the stream or write bytes into the stream, respectively. What do you mean when you say you're missing "the way to construct the project itself, without having to duplicate code"?
@@tomweiland I just saw a lot of copying the same code from the server to the client instead of making use of a shared library. I've figured something out, but I appreciate your reply.
Yeah I extracted the network code and stuck it in a library in my personal project because I use it for the master server and the game server-didn't want to have duplicate server code :P The problem is that the best way to share code between Unity projects (that I know of) is by using DLLs. This makes debugging network errors a bit more difficult, especially since you need to re-import the DLL every time you make a change. As far as I know you can't just reference another C# project as Unity will overwrite it when compiling or something (not entirely sure about the details of how that works, but correct me if I'm wrong). I'm planning to turn the networking solution we built in these tutorials into a bit more of a polished, out-of-the-box library in the near future-is that something you'd be interested in using?
That if statement doesn't necessarily check for a packet with a length of one, it more-so checks if there's 1 or less bytes left to read. To be completely honest, I can't remember why it's necessary (I used to know 🤔), I just know that things get weird without that if statement.
Hello, I'm having some problems with directives and/or assembly references, although I doubt the issue is coming from assembly references, I compared my code to the one on your gitHub but it's the same word for word. I'm at 8:40 in the video, the errors are mostly absences of the namespace 'Packet': -Line 18: Type or namespace 'Packet' can't be found -Line 51: Type or namespace 'Packet' can't be found -Line 77: Type or namespace 'Packet' can't be found -Line 102: The modifier 'private' is not valid for this item -Line 123: Type or namespace 'Packet' can't be found (this error appears twice, on both "Packet" 's) -Line 156: The name 'Server Packet's' does not exist in the current context using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Net; using System.Net.Sockets; using System; public class Client : MonoBehaviour { public static Client instance; public static int dataBufferSize = 4096; public string ip = "127.0.0.1"; public int port = 12301; public int myId = 0; public TCP tcp; private delegate void PacketHandler(Packet _packet); private static Dictionary packetHandlers; private void Awake() { if (instance == null) { instance = this; } else if (instance != this) { Debug.Log("Instance already exists, destroying object!"); Destroy(this); } } private void Start() { tcp = new TCP(); } public void ConnectToServer() { InitializeClientData(); tcp.Connect(); } public class TCP { public TcpClient socket; private NetworkStream stream; private Packet receivedData; private byte[] receiveBuffer; public void Connect() { socket = new TcpClient { ReceiveBufferSize = dataBufferSize, SendBufferSize = dataBufferSize }; receiveBuffer = new byte[dataBufferSize]; socket.BeginConnect(instance.ip, instance.port, ConnectCallBack, socket); } private void ConnectCallBack(IAsyncResult _result) { socket.EndConnect(_result); if (!socket.Connected) { return; } stream = socket.GetStream(); receivedData = new Packet(); stream.BeginRead(receiveBuffer, 0, dataBufferSize, ReceiveCallBack, null); } private void ReceiveCallBack(IAsyncResult _result) { try { int _byteLength = stream.EndRead(_result); if (_byteLength = 4) { _packetLength = receivedData.ReadInt(); if (_packetLength 0 && _packetLength { using (Packet _packet = new Packet(_packetBytes)) { int _packetId = _packet.ReadInt(); } }); _packetLength = 0; if (receivedData.UnreadLength() >= 4) { _packetLength = receivedData.ReadInt(); if (_packetLength
Is your Packet class in a namespace? On the server it should be in the same namespace as the rest of your code, whereas on the client it shouldn't be in a namespace at all. If that doesn't help, join the Discord server and ask there.
I had the same issue. What I did to solve it was to create a whole new project for the server side implementation and copy pasted all of Tom's code from github just to check if it would work then. I did this in order to figure out if the bug was in in server code or in the code written in Unity. As it turned out, it worked with the new code, so I figured the problem must have been with my server code (which i thought was exactly the same because I had double checked just as you). However, since I *knew* that I must have made a mistake there I just opened both projects and compared each file line by line to each other. As it turned out, in the Client.cs script, I had forgotten one small thing: on line 11, I wrote public static int dataBufferSize; instead of public static int dataBufferSize = 4096;. After fixing that, everything worked fine. Debugging logic bugs in projects with 10+ files and 100's of lines in each file sure is a struggle.
EDIT: It gave me some peace of mind when you say in the video that it took you months to understand all this networking stuff, thankyou, that actually motivated me again to keep going. Old comment: Hey tom, this is lovely stuff and I want to keep going till the end of the series, but I'm having some trouble: I'm a web developer and I've worked with http and websockets but a lot of this stuff is going over my head. I have a general idea of everything you are doing in the videos but I don't fully understand all the details, a lot of the time while watching this tutorial series I'm constantly googling to understand some concepts and functions being used here but I'm not sure for whom these tutorials are meant for, did you make these tutorials aimed at people who already understand tcp, udp and networking concepts a good amount? or should I just keep following along with you even though I don't understand 90% of the details and trust that it will all make sense eventually? sorry if that's a weird question but I have this problem where I start losing motivation to go on if I don't understand every line of code I'm writing. here's a less vague question as well: Why are we using two client files? one in unity scripts and one in the gameserver files?
I don't think I was really specifically aiming these tutorials at one particular group-my main goal was to get the knowledge out there since I had it and I've found that this kind of information is generally pretty scarce. However, I didn't intend it to be only for those that already have a grasp on networking concepts. I personally had very little understanding of what I was doing when I started, but after continuously "wrestling" with the stuff over the course of a few months, it eventually clicked. These first few tutorials were definitely too fast-paced (my first tutorials, so I guess you could say I didn't really know what I was doing :P). Regardless, the stuff covered in the first few parts is really low level networking which you actually rarely look at after initially putting it in place, so it's really only critical to understand it if you want to get in there and optimize or something. As for the two client files, we have two because they aren't identical (or won't be-I can't remember if they're identical at this point). It would be possible to extract the common functionality, but then you have to deal with DLL files and replacing those in Unity (since you can't add a regular C# project as a reference in a Unity solution) every time you make a change.
Thank you for the video, quick question here: why did you implement ThreadManager even though you are not running any separate threads? I've worked with many concurrent Servers written in Go, we use a thread manager like this to access the main thread from another thread, but here ThreadManager seems unnecessary since your application is single-threaded. Using async/await would probably be much better than creating a new thread. Or am I missing something?
_" your application is single-threaded"_ It's not. The BeginReceive method for example returns on a non-main thread. However, you should really use Riptide (my new and improved networking solution) instead of this dumpster fire 😅
To keep your server authoritative you need to have an instance of the world running on the server, which includes the map. This means you'll need some sort of physics library (unless you want to write your own, which is very involved, so I don't recommend it). I personally am using BepuPhysics for my project, but I'm not sure if I'll make a tutorial about implementing that because I'm trying to keep the series a little more on the broad side so it's applicable for most types of games that people might be making. Depending on what kind of game it is, you'll have completely different physics needs. Also, these tutorials take a lot longer to make than a regular video, and a physics tutorial would easily take another 10 times longer so I'm hesitant to sink that much time into it.
Hello Tom, quick question, did you have a tutorial to send from serial virtual com to ethernet IP using a NUC computer. I am looking from a PLC transmit by Serial-USB convertor to a windows virtual com and I want a program to get that data and transmit it by ethernet ip to a server the data, also, the server can return a data and the program should send it back to the PLC. Thanks
Uhhh...I'm not actually sure what a "serial virtual com" is, nor have I heard of "NUC" computers. Sorry I can't be of more help, but I'm also not really familiar with PLCs so I don't think I'm the right person to ask about this 😅
I've never heard of a BufferedStream, and the docs just say it can be used _"to increase the performance of certain I/O operations,"_ which is pretty vague-what would the benefit of using it be?
Thank you very much for this turbocharged tutorial. I quickly had to whip up a server and this gave me a boost. Just had to adjust to my data format and was done in one night. It's kinda working, but I noticed that the client is not taking the port I assign, but a random free one. For another reason I don't quite get, messages are still being picked up by the server on another machine (this is good, so it works). Do you know what's going on here? I need a set port so I can configure the firewall (right now it has to be off)
There should be no issues with clients using a random free port and your firewall-my client picks a free port and can connect just fine (whether on localhost, LAN, or over the internet) without turning off the firewall entirely. _"For another reason I don't quite get, messages are still being picked up by the server on another machine (this is good, so it works)"_ Not entirely sure what you mean...is it "good", or is there a problem with that?
*IMPORTANT: these tutorials and the code in them are outdated!*
I've been working on RiptideNetworking (a _much_ better multiplayer solution) for the last year, and I finally made a tutorial on how to use it: ruclips.net/video/6kWNZOFcFQw/видео.html
Can you please make a video on how to transfer large files using socket in C#
Even if this code is outdated, at least it's full
I know that making tutorials is hard, but im just joking
What do you mean by "outdated" ? Did you simply switch to Riptide because of preference, parts code got deprecated, or is it performance related?
If it is just preference, I guess I dont mind following this series to make my own net solution. Because this is a very detailed explanation, one of the best networking tutorial, so thank you for that. I have already watched through the first 3 videos before to complete a freelance project with udp support, but now I wanna make a full server, at least for the same network, to maybe scale it to dedicated server later.
If there are things that are done suboptimally, or performance bottlenecks with this method, then I guess I will switch too.
@@sadiqabbaszade4789 Riptide was a complete from-scratch rewrite. I kept the "interface" (how you as a dev interact with the library) pretty similar but all the internals underwent drastic changes.
The solution from these videos is less performant, poorly designed & not modular (statics everywhere) which makes it hard to maintain and work with, and I think there's an issue with UDP when you connect more than a handful of clients.
Riptide was the result of my desire to resolve all those problems-it has more features and is faster, cleaner, more modular, easier to work with & maintain/adapt, and better-tested with many bugs having been found and fixed with the help of the community. Riptide is quite literally better in every way.
The one reason I think it may still be worth watching these tutorials is because they go through things from scratch, which can be helpful if you want to see how networking in C# works at the lowest level. However, even then I'd suggest watching these videos and then using Riptide in your actual project. Riptide also has documentation: riptide.tomweiland.net/
Everybody using plugins and headless versions of their game for networking...
A great way to get started with network programming! I love this!
Which game are you talking about?
@@tomweiland sorry a little incoherent.. I fixed with an edit
Ah I get it now, I'm glad you like it :)
Hippity, Hoppity, your codes my property,
This man be like the emenim of dat coding properly.
I'm not even sure what this is supposed to mean 😂
@@tomweiland I think it mean you are spitting code as fast as Eminem is spitting bars
What do I do if I do not see "Weclome to the server" message on 9:39? Where did I may miss something?
There's a number of things that could be causing this problem-troubleshooting is hard in the RUclips comments, so I suggest joining the Discord server if you need help (link in Description).
@@tomweiland ok thanks!
I had this problem too. I double checked my code with the one on GitHub and find out I had written "(socket.Connected)" instead of "(!socket.Connected)" on ConnectCallback method. Hope this helps someone
This happened to me, make sure you check that you're using stream.BeginWrite() instead of stream.BeginRead() in the SendData method in the servers client class.
@@rob3rtsayshi idk if auto complete caused this or it was shown wrong in video but it fixed error for me tnx
After watching this tutorial so many times in the past and improving my type speed. I can finally watch this video at normal speed without pausing or rewinding.
That is extremely impressive 😂
Dude you are awesome and btw at 0.5 speed you sound like Walter White's son in braking bad
I actually haven't seen that show, but that's cool I guess :P
Damn thats so true LOL
That's actually so accurate lol
Ha! I thought I was the only one watching at .5 speed ^^
this might be the best youtube comment I've ever read
Finally found a understandable tutorial for what exactly I wanted! Thank you so much! Keep making this videos!
Glad you found it useful :)
@@tomweiland like bro ur the best keep with the series
@@thegamerjoshua2848 ill totally agree! @Tom keep up the good work!
well not for me XD frist time with these network stuff and there is alot of stuff jumping in my face it will take me some time i guess
i can understand what he wants to do but i usually understand code by just reading but when i read code i just get lost that my problem
17 minutes of video, i take 3 hours to finish. Just the way i like, lots of content in such small time! Great tutorial!
I'm glad you like the speed! I personally don't like it when tutorials are really slow, which is why I made these so fast, although I'll admit that the first few might've been a bit _too_ quick :P
This is simply amazing. I have tried atleast 15 other videos and I kept running into errors and didn't understand shit. FINALLY!! A GOOD VIDEO WITH GOOD EXPLANATION AND CODE THAT IS STILL FUNCTIONALL!!! U DESERVE MORE LIKES AND SUBS MY MAN!!!
Thank you for the kind words! I'm glad it's working for you :)
Awasome series, already helped a lot, and since I don't really see it mentioned I think it's best if people new to coding know. The reason the server used 7% cpu, was because the code inside isn't "once it's time update" but "is it time?no. is it time?no. is it time? yes. UPDATE!" that is why the sleep helps, since the code thinks you really wanna check if it's time on repeat.
Glad you liked it, but I'd strongly recommend checking out my newer series instead!
Me: looks away for 2 seconds
The code: *200,000 lines are ready with a million more well on the way.*
😅
@@tomweiland lol, jokes aside this is actually a good tutorial thanks for it
You ever seen the video meme of the dude copying and pasting an entire class. This dude is literally why the meme exists.
Duuuuuuuuuude I've searched many times for tutorials just like this one and I never found one that was exactly what I wanted. Thank you sooo much for your effort.
Glad I could help!
I 100% agree. I had a pretty low level Networking Tutorial that I followed about 5 years ago. When Unity updated there networking it completely destroyed what I had and I barely knew how to use that. After that I pretty much given up on making anything networking. Then I stumbled upon this and my fire is lit back up. I truly am thankful for all your hard work. Sorry for the life story that no one asked for lol.
When RUclipsrs are better teachers than the ones in the actual schools. Sure, I had to watch some other videos related to the topic as I learn more from pictures/animations but this is already a working code that you just have to go through with your mind and edit to see what changes.
That's some big praise, glad I could help!
I was really trying to find a tutorial so I could make my own server with my Unity client :) Thanks a lot! Now I can scale my server the way I want to
I'm glad you've found the tutorials useful :)
Although this tutorial is outdated but still helpful to learn how low- level networking works.
Will still watch almost these tutorial and jump into your new tutorial of RiptideNetworking.
Huge respects!
👌
I like tutorial like these building from scratch! This is actually beneficial to everyone than using "pre-made" stuffs that when time comes that you want something to add or look under the hood you are doomed for eternity.
Yep, having full control is nice :)
@@tomweiland And oh, I forgot to thank you Tom! Thank you so much and take care always! Loved your tutorials! Subscribed! :)
Thanks for subscribing :D
*Check out the next tutorial where we implement support for communication through UDP* 👇
ruclips.net/video/QajkUJeypy4/видео.html
Also make sure to subscribe so you don't miss future videos: tomweiland.net/youtube-sub
@@MrPotatoHQ I'm aware it's fast, but at this stage there's nothing I can do about it. These were my first tutorials and at the time it didn't seem _too_ fast. You can slow down RUclips's playback speed, and all the code is on GitHub, so if you're really determined you can certainly find ways to follow along.
Also in the later tutorials I've slowed things down a bit, so if you can push through until you get to those you'll be fine.
@@MrPotatoHQ yep, the networking side of things is entirely independent of how many dimensions your game uses-although in later tutorials (player movement for example) you'll need to change my code to work for 2D (mainly just swapping out Vector3s for Vector2s).
Hey man, I think the reason you need the Thread.sleep is because of the Game Delta value.
I'm getting this error "Assets\Scripts\Packet.cs(21,18): error CS0542: 'Packet': member names cannot be the same as their enclosing type" I have been stuck for hours lol
is that method compatible with android?
These tutorials are unique, Every single multiplayer tutorial, they use some servers online. While this one Makes everything from scratch. I love it dude!
Btw: Legend still says you're replying to comments
The legends are true 😂
I'm glad you like the tutorials!
Thank You! This is Amazing.
BTW, this tutorial has better explanation than the last one, thank you for explaining everything so well!
I'm glad you like it :)
I'm only this far into the playlist, and I just gotta say, you're a genius, now I am making mine read .ini files for other people to make their own servers on my game, so mine is getting heavy adjustments on what the server information is, however, I just gotta say again, this playlist tutorial is just the best, here's a sub.
Thanks for subscribing, I'm glad you like the tutorials!
this is the best 50 minutes tutorial i've ever seen
Glad you like it 😅
This series is helping me a lot. I don't know anything about creating servers. When I see you go through all of this i'm just like how the hell could anyone figure this shit out.
I'm glad you've found it useful :)
I was in your position two years ago and felt exactly the same way. The Microsoft docs have all the info, but actually putting it together in a way that works is a monumental task. Most of the TCP stuff came from some videos by Kevin Kaymak, but the UDP part I pieced together on my own using the docs & Google (but at that point I was somewhat familiar with the general concepts, which made it a bit easier).
I just transferred the code from console to unity like in your guide in tutorial 6. I also finished integrating a database to the server and had my FIRST TCP transaction where client trying to access data from the database. It was tricky at first but your tutorial is really good and code is self-documenting so learning was way easier. Thanks for the vids.
Congrats! I still haven't really touched databases, but that's something I'll have to get into soon. Glad I could help :)
Amazing tutorial, thank you! And your discord server is nice too, actually helping people instead of making them look stupid for not knowing something.
Thank you! I'm glad you like the Discord server :)
Thank you very much, everything working, I'm trying to create this server with Node.js, I'm a beginner and I'm learning a lot here, the best channel I found, congratulations!!!
Thank you, and good luck with your Node server :)
hi, thanks for sharing your knowledge with us, i live in Brazil, and here we have a few resources and information about C #, unity and socket at this level.
again thank you very much.
I'm glad you've found it helpful :)
I barelly started and I'm already in love with this series! Would it be possible for you to teach us how to make a matchmaking system in the future?
That’s great to hear :)
I’m not sure if matchmaking is something I’ll go into, since there’s a million different ways you could set that up, and it’s really about figuring out which players should be matched together (which is heavily dependent on the game).
Once you get into the “multiplayer mindset”, matchmaking will become just another typical programming problem to tackle. Until then, you just need to keep working with this stuff-it took me several months of playing around with this to finally understand it to the point where I could do what I wanted with it.
@@tomweiland Thank you! I hope that by the end of the series I can figure that out then, looking forward to do that =]
No problem :)
If you get to the end of this series and don't feel like you've got a good enough grasp on things yet, make sure you're not too hard on yourself. It can take time, and as repetitive as it may seem, it can be a good idea to build the networking solution multiple times from scratch. That's what I did, and it's amazing how much that helped my understanding!
@@tomweiland You are right but how to get into multiplayer mindset? How do I figure out stuff myself just like normal frontend stuff.
Awesome video series honestly one of the best ones i' ve seen. When I press connect ( 9:35 ) I only get the : Initialized packets, message and not the welcome message. There isn' t an error message or something like that and I' ve checked the code multiple times but there doesn' t seem to be any problem with it. Is there anything except the UIManager, the Client and the ThreadManager I need to assign in the Unity Editor itself? (And the server itself of course)
Hmm, did you make sure to add an Update method in the ThreadManager which calls the UpdateMain method? If that doesn't help, join the Discord server and ask there-troubleshooting via RUclips comments is a pain 😅
Hey man did you get this working?
if so can you please try to explain it and stop my suffering
@@dontcareyoutube7417 I just restarted my computer. Kind of weird that it works but anyway hope it helps
I am a very big beginner in this topic, but I have found it helpful to sometimes just watch the tutorials without writing any code or doing any unity, as you don't have to worry about code it yourself, or worry about the syntax, and you can get the gist of what is happening much easier.
Yeah, watching the video without following along can be very helpful, as well as writing the code several times!
Honestly I fully rate this tutorial series but you go so fast. I don't know if I love you or hate you.
Yeah, the first few videos are too fast. The later ones are better though :)
@@tomweiland I like that these videos are over a year old but you're still responding to comments!
I'm on part 4 now and I'm feeling like I'm getting better at keeping up with you!
One thing: Please zoom in/scale up the code so we can read it easily on mobile too :)
I often use Visual Studio in split screen, so I have it at that size to keep my code from getting cut off. I'll definitely zoom it in a little in the next tutorial, thanks for the feedback!
Huge respect to you, Tom, for this amazing tutorial series! I'm learning low-level networking with it's help. I like your idea, format, and explanation!
But this amount of copypasting just drives me crazy, man :D You sure know that you can set up shared modules in your IDE between your client and server, my dude! :)
Huge respect again, for everything else though!
I know you can add projects as references to other projects within Visual Studio, but unfortunately that doesn't work with Unity, as Unity regularly rebuilds the solution (and overwrites the references). As far as I'm aware, the only other good option is to use DLLs, but personally I find that more of a pain than just copy/pasting the shared code.
As my personal project grows, I might switch to using DLLs, but I really do wish that there was a better solution to this problem :/
@@tomweiland I'll try to find a proper solution (or unity feature request ticket) for this case. I Will let you know, my dude! Thx for the reply!
Sounds good :)
@@tomweiland Well, that's strange. It's actually hard to do in Unity's environment. So my best and very simple idea - is to have a shared folder on a server, and to copy its contents with a simple script to a client. Check it out, dude. It's very convenient :)
Shared folder:
github.com/NikitaShkaruba/among_us_clone/tree/master/AmongUsCloneServer/src/AmongUsClone/Shared
Shared folder copying script:
github.com/NikitaShkaruba/among_us_clone/blob/master/copy_shared_code_from_server_to_client.sh
I kown you made among us multiplayer I see your video it good.
Even branched the parts of the series in github, well played sir!
😄
Thank you Tom. Been following your content, it is becoming progressively better. Keep it up!
Thank you, that means a lot :D
For those people who want to implement utf-8 encoding. In Packet class change your Write method for strings >>>
public void Write(string value)
{
byte[] data = Encoding.UTF8.GetBytes(value);
Write(data.Length); // most valuable part
buffer.AddRange(data);
}
In ReadString method change encoding to utf8 too.
I hope it saves your time a little bit.
Yeah, if you want to be able to send more than the basic ASCII characters, do this ^
10:53 Oh man, that one difference between video and audio caused me so much headache. xD Positively LOVE the tutorials though!
Sorry about that!
Oh my, Thank goodness you added those tags of where you are in future videos... I got so confused at one point then found out I was in the wrong place. :)
Yeah, if I had gotten that suggestion sooner I would've added them sooner :P
@@tomweiland It is so confusing having pretty much copies of code but they do different things. It also seems the footage is sped up x 10... Way to fast for me 😉
You sound like Eugene Porter from The Walking Dead and that makes this whole tutorial a lot more exciting
Hahahaha 😂
Another great tutorial that works just fine! Already added myself to the discord too and its filled with greaat people!
Only small piece of advice, sometimes you do switch between screen a little fast XD Especially when copy/pasting!
Yeah, the first few videos are definitely too fast. It gets a bit better in the later ones :)
Well made and well explained. Thank you for these tutorials!
Glad you like them!
Great tutorial! Keep it up man :D
Thanks, I definitely have a few more videos planned for this series :)
Tom Weiland Can’t wait to see them! I honestly enjoy your videos and you deserve many more subscribers than you have. You explain very well and even have good video and mic quality :D
@@daxy5778 Thank you so much, I appreciate that more than you probably realize :)
You sound like someone who would be great to have on our Discord server, feel free to come hang out there (link is in description).
@@tomweiland I joined :)
Awesome!
Im having trouble at 5:30 , i keep on getting a error that says “the type or namespace ‘Packet’ could not be found”
You probably copy + pasted the namespace from the server along with the Packet class. Make sure your Packet class isn't inside a namespace.
Thanks ! I will let you know if I have any more problems
i dont even need this but im following your series anyway, this is amazing!
I'm glad you like it that much!
one minite of the video = 12 minits in real life BTW greate video and tutorial
helped me soooo much till now
Haha yeah, the first few videos are definitely a bit too fast-I'm glad you've found them helpful anyways :)
alrighty done with video 2, watching the series first and then going to follow along the second time, would just like to say i have no idea whats going on or what half these words mean BUT, i am picking up more than i did from episode 1 because words or phrases are being linked in different places and uses so im learning what they are for and do, so hopefully ill get more as i continue :D
Best of luck :)
You are the only youtube tutorial maker that answers every comment on his videos I sincerely appreciate your works.Those aside I have a question.I'm fairly new to this networking things so I'm wondering if this setup has anything to do with Unity's upgrading on networking? And again thanks for this tutorials
It's nice to hear that it's appreciated, and although not many creators do it, there are a few others :)
This setup uses .NET's networking features, so intrinsically it has nothing to do with Unity. You can use it outside of Unity if you want (like with the server's console app), but as you can see it also works with Unity. UNet is obviously deprecated, and as far as I know, Unity's new netcode is still in the rather early stages of development (although I haven't checked on it recently), which is why I personally am currently using this solution in my own project.
@@tomweiland Thanks for the response my friend
Hey at 10:56 you said beginRead Method and wrote a BeginWrite method what actually made me rewatch the video 4 times until i noticed that i wrote beginRead because i was not watching and just listening while i wrote my code maybe you could add a text there which tells this...
this video still helped me a lot and thank you so much for making this series....
I think one or two others have pointed this out, but good catch :)
Unfortunately I can't edit in text after the fact, so I'd need to delete the video and reupload it (which would reset views and search rankings).
Please I have two questions:
At 15:42 the purpose of MainThread method is to call GameLogict.Update() always when 33.33 ms ( 1000/30) has passed?
If yes, does Unity Update() method execute with the same delay? (to keep server-client consistently)
Yes, and no.
Unity's Update method runs once each frame, so if you're running at 60fps that'd be every ~16ms, or twice as fast as the server. You'd want to use FixedUpdate instead and set your fixed timestep to 0.033 (like we do in the video)
4:28 personal note :) ty for the tutorials btw xD
You're welcome, although I'd recommend checking out the new tutorials instead. Riptide is far superior to the solution we build here.
@@tomweiland about that, I've also watched those Videos, but I am coding the Server in Python and i am Not sure If I can only use the Riptide Client without it's Server Out of the Box. If so, i'll definitely Switch :D
A cool little idea for people who might want to make this even "cleaner" - You can use the "Reflection" namespace and CustomAttributes for alot of cool things in C# and even automation.
Currently we are adding another entry in our two enums for every server / client, networking method for sending and receiving.
We are also adding this to our dictionary to pair the packet_ID with the corresponding "Receive" method for our packethandling.
We are doing this for both the server application AND the client application.
Instead of doing this, we can do some "Reflection" fuckery, to build dictionaries at runtime, given we set some rules / standards for the architechture of our application. This will allow us to simply add the methods to the "ServerSend", "ServerHandle", "ClientSend", "ClientHandle", or what ever classes you make after doing this, and "forget" about them, as our reflection will do the rest. This will also ensure readability, overview and low coupling as your project gets bigger.
Now im not going into details, but rather leave some pointers to which direction to go in your research. And if you get this up and running, i'll assure you, that you'll run into another case, where this will save you some time in the long run. Reflection is very powerful and fun to use.
How can we get information about a class AT runtime (when our application starts running)? a class we might not know about, at compile time (source code editing).
How can we get access to the methods of those classes at runtime?
How do we extract a delegate, from that method, at runtime?
Can we use CustomAttributes, to get information about said classes and methods, at runtime?
I might have to look into reflection a bit more🤔
I've seen it mentioned here and there on forums, but never really took any time to find out how it works or what it's useful for-partially because (from what I've seen) people tend to say it's bad for performance.
Thanks for the feedback though!
@@tomweiland It can be taxing for performance, but this is only ever a issue, when doing frequent operations that depends on execution speed. My usage, and for the idea above, its only using Reflection on startup, to map / build the ServerSend, ServerReceive, etc. And it is still fast nonetheless. ^^
Again, without going into details, if i want multiple "ServerSend" classes, but with names that give more meaning to the logic, ex: "RoomController" or "PlayerController", i just create that class, slab a CustomAttribute ontop of it. For the send and receive methods, within that class, i also just slab a CustomAttribute on top of those, the Reflection implementation will take of building a packethandler dictionary on startup. Im not even advanced at Reflection, but i bet there is so much overhead that can be removed from nearly any type of application, by using it.
I like this Tutorial. And even though I still don´t really know what you´re doing it´s really easy to just do some modifications to the code in order to make it fit my own games. :D
Glad you like it :D
in Client.cs when i try to put "private Packet receivedData" on line 46 6:12 it doesn't recognize "Packet"
Edit: in clientHandle it also doesn't recognize "Packet" on line 7
You probably copied the Packet class along with the namespace it's in. Remove the namespace and the errors should go away. If you need more help, I'd suggest joining the Discord server (link in description).
@@tomweiland I already removed the namespace. originally, it was in there, but i realized it wasn't supposed to be and removed it. so that definitely isn't the problem, im still searching for a solution. thanks for the quick reply though, i appreciate it.
I'm having the same problem aswell, it has redLine under Packet. (Public class Packet : IDisposable)
Nvm I got it fixed! Phew!
Neisan Land how did you fix it?
0:49
bits: Am I a joke to you?
binary digits: Am I a joke to YOU?!
Considering you can't send individual bits, yes.
How to fix 10:28 adding the client's username to the packet?
I still got error: "Client" does not contain a definition for "usernameField" and no accessible extension method "usernameField" accepting a first argument of type "Client" could be found.
Compare your code to what's on GitHub. Also, I'd strongly recommend using Riptide and it's tutorials instead of this series.
Great series, how do you keep the client connected across scenes?
Call DontDestroyOnLoad on the game object which the Client class is attached to.
@@tomweiland Thanks ;)
hay Tom! I got to 9:30, and I get 1 error on line 155 of the GameClient's Client.cs "The Name 'ServerPackets' does not exist in the current context" could ya help me out? :3
Double check that the Packet class and the two enums are in the same namespace as the rest of your code (since you may have copied the namespace part from GitHub as well).
Beyond that, I'm not sure what it might be without more information. Remote troubleshooting is tedious in the RUclips comments, so if the namespace wasn't the problem, consider joining the Discord server (link in description) and ask for help there :)
please tell me why on 9:20, line 141 to 144, if(packetlength
I don't remember, and I haven't looked at this code in like 4+ years. It's also just a mess in general, which is why I've marked the series as outdated and strongly recommend using Riptide instead: ruclips.net/video/6kWNZOFcFQw/видео.html
this still helps me A LOT. You have my subscription :D Thank you for your sharing, will definitely watch your other videos, they are really helpful
Glad I could help :)
Great tutorials. Thanks. I wonder how many people tried to "Update" their Visual Studio 2019 only to realize it was on Tom's screen? I'll be honest, I did!
Did I have a notification about an available update in the video?
@@tomweiland ya...no biggie. I laughed when i tried to click it and it just paused the video :)
@@MQNGameDev :P
This was a great introduction to networking, well done! However, one thing I need t bring up. You're setting yourself up for disaster down the road by using constants for the byte size of your primitive types. While an int is normally 4 bytes, that isn't always guaranteed. It is much safer to use sizeof(int) or sizeof(float) for whatever data type your are passing between the server and client.
If you've got any sources to back up your claim, I'd appreciate it if you could share those, as this is the first time I'm hearing about primitive types using variable byte sizes. Also, the docs on the sizeof method (docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/sizeof) indicate that sizeof(someInt) returns 4, and there's no mention of any exceptions.
Nothing I've ever seen has ever led me to believe that primitive types' byte sizes can fluctuate in C#, but maybe that's the case in another language and you're getting things a bit mixed up? Unless of course you're referring to how a short is only 2 bytes or a long is 8, but even if you pass those types to a method that takes in an int, they'll be converted and the int will use 4 bytes like usual.
@@tomweiland It has to do with the computer architecture more than the programming language. I know in C when you need to worry about unbounded pointers knowing the size of primitives is very important. 99.9999% of the time, primitives will be the same size across different computers because there are a lot of standards in place. The only issue you'd really need to worry about is if those standards change sometime down the road, it could break your code. It's not really a legitimate concern I guess, just good practice. I loved the tutorial, and I'm sure you'll be fine leaving it the way it is for a long time to come.
@@augustmiller6845 interesting 🤔
Great tutorial! Thanks a lot! I'm up to just before you start getting the client to send data. I compiled in Unity, but getting an error that in the client's Client.cs, "The name 'ServerPackets' does not exist in the current context.' It's down the bottom in InitialiseClientData (I used the English spelling). Am I missing something obvious?
Ah! I hadn't spotted it being declared in the Packet class. Sorted
👌
thanks man XD
In the script client handle I have 16 errors saying the type or namespace packet could not be found (are you missing a using directive or an assembly reference) on line 9,22,32,43,54,62,70,77,86,93,102,112,123,131,139 and 150
When you copy/pasted the packet class, you probably copied the namespace it was inside of as well. If you delete the namespace your errors should go away.
Ok I’ll check
What should I do it’s not anything to do with namespace like you suggested
I had the same error but what you suggested like The bad programmer doesn’t work for me please help
Well if you're getting that error, it means one of several things:
1. You don't have a Packet class in the same project as the ClientHandle class
2. Your Packet class is in a namespace it shouldn't be in
3. Your ClientHandle class is in a namespace it shouldn't be in
4. You misspelled the name of the class you're trying to access, either when declaring it or when accessing it (aka where the errors are), so it's trying to find a class that doesn't exist
Also be aware that sometimes Unity will fail to properly add a created script to the generated C# project, and it will end up in "Miscellaneous Files" (displayed near the top left in Visual Studio). If that happens, I've found the easiest way to fix it is to just delete and recreate the file from Unity and then copy over the contents.
If none of that helps and you really have no idea what the problem is, join the Discord server and ask there (and show your code).
Hey! :). I am having some issues in the client class in the InitializeClientData at 8:55 because "ServerPackets does not exist in this context." It would be a huge help if anyone could help me out. Thank you and have a great day :D
You probably copied the Packet class along with the namespace it was in. Make sure your client-side Packet class is not in a namespace.
When you copy from your Packet server scripts
----------------------------------------------------------------------------------
namespace GameServer
@@tomweiland Thank you!
@@Gears2Game Thank you!
after so many years finally... an answer
Well I'm glad I could help :)
i have an problem i got this error message "
Error CS0051 Inconsistent accessibility: parameter type 'Packet' is less accessible than method 'ClientHandle.Welcome(Packet)'" in ClientHandle class and i dont know what is problem can somebody help me
i am in 6:01 in video
Edit i didnt have packet class to public
it fixed my problem
Glad you figured it out yourself!
i cant use "Welcome(Packet _packet)" because "Packet" has a red line under it how do i fix this? btw this is at 5:36
Do you have a Packet class in your project? Is it in the right namespace? If that doesn't help, join the Discord server and ask there (and include the error message).
Can’t wait to use this
:)
Excellent tutorial, thanks a lot for your sharing !
The last function of the client.cs (client side) " InitializeClientData()", unity show "ServerPackets.welcome does not exist in the current context", I copy your Github script to replace it, still have this problems, could you please advise any mistake of my process? thank you very much.
I copy all the script from your Github then fix the problems, may be some mistake by me, haha.
Maybe your Packet class was in a different namespace? That would've caused an error like this.
@@tomweiland Thanks a lot for your reply, just finished this series total 11 Video, Excellent Tutorial !
Hey tom, could you briefly explain the welcome enums?
Specifically, if we are assigning an id of serverPackets.welcome to every packet to be sent, wouldn't that mean all packets have an id of 1?
Only the welcome packet uses the ServerPackets.welcome packet ID. Different packets will get their own IDs, as you'll see in later videos.
@@tomweiland thankyou, that makes sense
in function HandleData, I confuse with this check
if (_packetLength
Honestly? I have no idea anymore. It's been years since I wrote that code and there was a time when I had _some_ idea of what it was doing, but at this point I just don't remember. I'm pretty sure removing it causes problems, but I can't remember how or why 😅
Hello, I'm getting an error at different seconds after running the program ( 16:11 ). It says "A number must be non-negative or less than or equal to Int32" Please help, I'm not sure what to do at this point
Double check that you're checking if _nextLoop is greater than DateTime.Now and not less than.
4:23 Hi. I got it working, but here, we added 3 new scripts to unity. Yes, we attach ThreadManager. But Packet.cs and ClientHandler.cs, what to do? What uses them?
Ahh. ok. Client.cs uses ClientHandler which uses ClientSend and both of the last two use Packet.cs. Got a bit lost. Noob question; I didn't attach these scripts to anything. I thought scripts needed to be attached to an object to load. Do all scripts in unity just load at startup or when they are called by another method?
You only need to attach scripts to objects if they contain Unity methods (Awake, Start, Update, etc.) that need to be called or if you need to assign fields in the inspector. Scripts really just contain regular C# classes, and outside of Unity, you don't attach classes to anything-they exist on their own.
9:14 the last few lines in the HandleData method can be replaced with:
return packetLength
True.
In 15:00 you are nesting two whiles, the second while couldn't just be a if statement? If not, can you explain to me why? Thanks, great tutorials.
By having the second while loop, the server will execute multiple ticks in case a previous tick takes really long to execute in order to stay "caught up". I think you might be able to pull off the same thing using just an if statement and moving some of the other code around, but I haven't really looked into that.
@@tomweiland Got it. Thanks and please keep doing the series, it's helping me alot.
Hey, thank you for this amazing tutorial! I sure will use it on my games!
I'm glad you liked it :)
I don't get the message 9:40
And it doesn't show any errors.
What to do, please help?
Join the Discord server. Debugging stuff like this in the RUclips comments is extremely tedious :P
@@tomweiland I fixed the problem. In the condition of while loop, I wrote _packetLenght > 0 && _packetLenght < receivedData.UnreadLength() instead of _packetLenght > 0 && _packetLenght
@@tarongaming9507 It Didn't Work for me.
At 5:52 it gives me an error for the ReadInt() and ReadString() and i cant fix it, does anyone have an idea what i did wrong?
Without the error message, there's nothing we can do except guess as to what's wrong.
@@tomweiland I fixed it now, there was just a problem with the port, thats y there werent any errors
This guys is a champion
😅
i always got errors but didn't give up and now i am Done with the series without errors.
Glad it's working for you!
I'm kinda confused about why we needed the delegate PAcketHandlers? Also if you know any good links to understand networking I would greatly appreciate.
Without the packetHandlers dictionary, the server & client wouldn't be able to decide which method to call for each packet. To store a method in something like a dictionary, you need a delegate.
Please Help Me With My Error,
I Dont Recive Welcome Message At 9:44
ServerSend.cs, Line 12;
System.Collections.Generic.KeyNotFoundException: 'The given key '0' was not present in the dictionary.'
Edit: I Changed The ServerSend.Welcome(0, "welcome") to ServerSend.Welcom(1,"welcome") Error is gone but welcome message is still not coming
Edit 2: I am such an idiot i fixed it if anyone getting the same errors like me just check the code at github project you will find the solution :)
Glad you figured it out on your own :)
Cool tutorial series!!. Any recources or tips if I want to create a random matchmaking system :D ?
You'll probably want to have a master server to keep track of all the players that are ready to get in a game, and then just randomly pick some of them and connect them to the same game server.
@@tomweiland Ok thanks :)
During 5:09 when copying coded from game server Packet to unity Packet, I get an error saying "Error CS0542 'Packet': member names cannot be the same as their enclosing type Assembly-CSharp". Can you please help me how to remove this error?
edit: found my error. thanks for the video
Glad you figured it out yourself :)
Hi Tom, I was wondering if there's any documentation to be read, that laid the foundation for these videos? Books, articles, guides etc. The videos were great, but I'd love to dig a little deeper into the subject, and get a solid understanding of the workflow.
Thanks!
You can look through the Microsoft Docs since most of this stuff is in there, although I wouldn't exactly call that a great learning resources (the docs are good if you're trying to find out what a specific method/field does, but not really why or how it does it). In terms of just understanding the basics, regular googling is probably easiest-searching phrases like "TCP for beginners" should give you some useful results.
@@tomweiland Thanks for taking the time to respond. Yes, I've read most of the 'get-started-tutorials' on TCP using the client-server model written in C#. The documentation on Microsoft Docs is sparse, and severely lacking important behavior when it comes to the .Read() and .Write() for the NetworkStream class. What I'm missing from these tutorials is the way to construct the project itself, without having to duplicate code but rather reuse for server- and client-side. The guides I've read are mostly concerned with doing a simple chat by sending strings back and forth, but they rarely show a proper project with packing that allows sending more advanced objects to reconstruct on either side. So if your videos were based on some specific paper regarding that subject, it would be lovely to give it a read. Thanks again.
Unfortunately the networking solution isn't really based on any papers-I originally learned from Kevin Kaymak, and although I've modified his solution, there's still quite a few similarities.
When it comes to the NetworkStream's Read and Write methods, I honestly think those are some of the more self-explanatory methods of this whole setup. They read bytes from the stream or write bytes into the stream, respectively.
What do you mean when you say you're missing "the way to construct the project itself, without having to duplicate code"?
@@tomweiland I just saw a lot of copying the same code from the server to the client instead of making use of a shared library. I've figured something out, but I appreciate your reply.
Yeah I extracted the network code and stuck it in a library in my personal project because I use it for the master server and the game server-didn't want to have duplicate server code :P
The problem is that the best way to share code between Unity projects (that I know of) is by using DLLs. This makes debugging network errors a bit more difficult, especially since you need to re-import the DLL every time you make a change. As far as I know you can't just reference another C# project as Unity will overwrite it when compiling or something (not entirely sure about the details of how that works, but correct me if I'm wrong). I'm planning to turn the networking solution we built in these tutorials into a bit more of a polished, out-of-the-box library in the near future-is that something you'd be interested in using?
Sweet video man :)
Thanks, glad you liked it :)
Hey Tom, Is it possible to receive a packet with length of 1 on any condition 9:18 line 141. Thanks!
That if statement doesn't necessarily check for a packet with a length of one, it more-so checks if there's 1 or less bytes left to read. To be completely honest, I can't remember why it's necessary (I used to know 🤔), I just know that things get weird without that if statement.
Hello,
I'm having some problems with directives and/or assembly references, although I doubt the issue is coming from assembly references, I compared my code to the one on your gitHub but it's the same word for word. I'm at 8:40 in the video, the errors are mostly absences of the namespace 'Packet':
-Line 18: Type or namespace 'Packet' can't be found
-Line 51: Type or namespace 'Packet' can't be found
-Line 77: Type or namespace 'Packet' can't be found
-Line 102: The modifier 'private' is not valid for this item
-Line 123: Type or namespace 'Packet' can't be found (this error appears twice, on both "Packet" 's)
-Line 156: The name 'Server Packet's' does not exist in the current context
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System;
public class Client : MonoBehaviour
{
public static Client instance;
public static int dataBufferSize = 4096;
public string ip = "127.0.0.1";
public int port = 12301;
public int myId = 0;
public TCP tcp;
private delegate void PacketHandler(Packet _packet);
private static Dictionary packetHandlers;
private void Awake()
{
if (instance == null)
{
instance = this;
}
else if (instance != this)
{
Debug.Log("Instance already exists, destroying object!");
Destroy(this);
}
}
private void Start()
{
tcp = new TCP();
}
public void ConnectToServer()
{
InitializeClientData();
tcp.Connect();
}
public class TCP
{
public TcpClient socket;
private NetworkStream stream;
private Packet receivedData;
private byte[] receiveBuffer;
public void Connect()
{
socket = new TcpClient
{
ReceiveBufferSize = dataBufferSize,
SendBufferSize = dataBufferSize
};
receiveBuffer = new byte[dataBufferSize];
socket.BeginConnect(instance.ip, instance.port, ConnectCallBack, socket);
}
private void ConnectCallBack(IAsyncResult _result)
{
socket.EndConnect(_result);
if (!socket.Connected)
{
return;
}
stream = socket.GetStream();
receivedData = new Packet();
stream.BeginRead(receiveBuffer, 0, dataBufferSize, ReceiveCallBack, null);
}
private void ReceiveCallBack(IAsyncResult _result)
{
try
{
int _byteLength = stream.EndRead(_result);
if (_byteLength = 4)
{
_packetLength = receivedData.ReadInt();
if (_packetLength 0 && _packetLength
{
using (Packet _packet = new Packet(_packetBytes))
{
int _packetId = _packet.ReadInt();
}
});
_packetLength = 0;
if (receivedData.UnreadLength() >= 4)
{
_packetLength = receivedData.ReadInt();
if (_packetLength
Is your Packet class in a namespace? On the server it should be in the same namespace as the rest of your code, whereas on the client it shouldn't be in a namespace at all. If that doesn't help, join the Discord server and ask there.
@@tomweiland Doesn't seem to be working, I'll join the discord.
Thanks.
All working fine :P
Liked&Subscribed
Thanks for subscribing :)
after double, triple checking my code, I still can't figure out why my console won't display the welcome message.
please help.
Join the Discord server if you're looking for help.
I had the same issue. What I did to solve it was to create a whole new project for the server side implementation and copy pasted all of Tom's code from github just to check if it would work then. I did this in order to figure out if the bug was in in server code or in the code written in Unity. As it turned out, it worked with the new code, so I figured the problem must have been with my server code (which i thought was exactly the same because I had double checked just as you). However, since I *knew* that I must have made a mistake there I just opened both projects and compared each file line by line to each other. As it turned out, in the Client.cs script, I had forgotten one small thing: on line 11, I wrote public static int dataBufferSize; instead of public static int dataBufferSize = 4096;. After fixing that, everything worked fine. Debugging logic bugs in projects with 10+ files and 100's of lines in each file sure is a struggle.
i am still facing the problem brooo... DID u found any solution??? please helpp!!
@@AbhishekHShah just clone the whole github repo
I think you forget to add ThreadManager script to your scene
EDIT: It gave me some peace of mind when you say in the video that it took you months to understand all this networking stuff, thankyou, that actually motivated me again to keep going.
Old comment:
Hey tom, this is lovely stuff and I want to keep going till the end of the series, but I'm having some trouble:
I'm a web developer and I've worked with http and websockets but a lot of this stuff is going over my head.
I have a general idea of everything you are doing in the videos but I don't fully understand all the details,
a lot of the time while watching this tutorial series I'm constantly googling to understand some concepts and functions being used here but I'm not sure for whom these tutorials are meant for,
did you make these tutorials aimed at people who already understand tcp, udp and networking concepts a good amount? or should I just keep following along with you even though I don't understand 90% of the details and trust that it will all make sense eventually? sorry if that's a weird question but I have this problem where I start losing motivation to go on if I don't understand every line of code I'm writing.
here's a less vague question as well:
Why are we using two client files? one in unity scripts and one in the gameserver files?
I don't think I was really specifically aiming these tutorials at one particular group-my main goal was to get the knowledge out there since I had it and I've found that this kind of information is generally pretty scarce. However, I didn't intend it to be only for those that already have a grasp on networking concepts. I personally had very little understanding of what I was doing when I started, but after continuously "wrestling" with the stuff over the course of a few months, it eventually clicked.
These first few tutorials were definitely too fast-paced (my first tutorials, so I guess you could say I didn't really know what I was doing :P). Regardless, the stuff covered in the first few parts is really low level networking which you actually rarely look at after initially putting it in place, so it's really only critical to understand it if you want to get in there and optimize or something.
As for the two client files, we have two because they aren't identical (or won't be-I can't remember if they're identical at this point). It would be possible to extract the common functionality, but then you have to deal with DLL files and replacing those in Unity (since you can't add a regular C# project as a reference in a Unity solution) every time you make a change.
@@tomweiland thankyou Tom, I appreciate you taking the time to reply!
Amazing work!!! Will you potentially look at webgl (websocket) support?
Thank you :)
Unfortunately I don't have any plans to add websockets (I have no experience with them), but perhaps at some point in the future!
Dudeeee!! thank you so much!!
You're welcome :)
Dude wtf why are you so smart?
I don't feel like I'm exceptionally smart, I've just been working with this stuff for the past 2 years 😅
Thank you for the video, quick question here: why did you implement ThreadManager even though you are not running any separate threads?
I've worked with many concurrent Servers written in Go, we use a thread manager like this to access the main thread from another thread, but here ThreadManager seems unnecessary since your application is single-threaded. Using async/await would probably be much better than creating a new thread. Or am I missing something?
_" your application is single-threaded"_
It's not. The BeginReceive method for example returns on a non-main thread. However, you should really use Riptide (my new and improved networking solution) instead of this dumpster fire 😅
The interesting thing is how you will make the mapping over the server.
To keep your server authoritative you need to have an instance of the world running on the server, which includes the map.
This means you'll need some sort of physics library (unless you want to write your own, which is very involved, so I don't recommend it). I personally am using BepuPhysics for my project, but I'm not sure if I'll make a tutorial about implementing that because I'm trying to keep the series a little more on the broad side so it's applicable for most types of games that people might be making. Depending on what kind of game it is, you'll have completely different physics needs.
Also, these tutorials take a lot longer to make than a regular video, and a physics tutorial would easily take another 10 times longer so I'm hesitant to sink that much time into it.
Tom Weiland nice man
Thanks :)
Hello Tom, quick question, did you have a tutorial to send from serial virtual com to ethernet IP using a NUC computer. I am looking from a PLC transmit by Serial-USB convertor to a windows virtual com and I want a program to get that data and transmit it by ethernet ip to a server the data, also, the server can return a data and the program should send it back to the PLC.
Thanks
Uhhh...I'm not actually sure what a "serial virtual com" is, nor have I heard of "NUC" computers. Sorry I can't be of more help, but I'm also not really familiar with PLCs so I don't think I'm the right person to ask about this 😅
Amazing video!
Glad you like it, but I recommend checking out my new series instead!
@@tomweiland Thanks for the heads up! I'll be sure to do that!
Great video, wait for the next xD
Thanks Xavier, glad you like it :)
I'm wondering if a BufferedStream wrapping the NetworkStream could be used instead?
I've never heard of a BufferedStream, and the docs just say it can be used _"to increase the performance of certain I/O operations,"_ which is pretty vague-what would the benefit of using it be?
Thank you very much for this turbocharged tutorial. I quickly had to whip up a server and this gave me a boost. Just had to adjust to my data format and was done in one night. It's kinda working, but I noticed that the client is not taking the port I assign, but a random free one. For another reason I don't quite get, messages are still being picked up by the server on another machine (this is good, so it works). Do you know what's going on here? I need a set port so I can configure the firewall (right now it has to be off)
There should be no issues with clients using a random free port and your firewall-my client picks a free port and can connect just fine (whether on localhost, LAN, or over the internet) without turning off the firewall entirely.
_"For another reason I don't quite get, messages are still being picked up by the server on another machine (this is good, so it works)"_
Not entirely sure what you mean...is it "good", or is there a problem with that?
you sir.. deserve a subscribe
Thank you :D