As response to the question at 20:00. I've been using vanilla JavaScript with Esmodules and Jsdoc comments. Typescript LSP can parse the doc comments from .js files. That way I'm not using any dependencies or build system while having types and an LSP.
Delivering ES Modules without any bundling will make it more difficult for you to deliver a good user experience and avoid waterfalls, especially as you add more and more code and internal dependencies. Instead of bundling the necessary parts, and minifying them for higher compression ratios, you are delivering a dependency graph for the client to resolve through network boundaries. Sure you could try to manually structure your project such a way that the code necessary for a given page is delivered in the least amount of network boundaries, but you now have to make decisions of where place your code in which modules to prevent waterfalls. Great for hobby projects and small apps with very few modules, but not ideal for user experience-and your servers-if you want to scale beyond that. There is no such thing as "no dependencies" when you rely on ES Modules; each import statement creates a network-bound dependency in the browser.
Thanks for all your videos. Nowadays people just act as consumers of high level, messy abstractions without understanding the basics. Complex solutions are invading each area and people think it is cool and the right way. I’m so, so sick. I enjoy your recreational programming videos. They help me learn about different topics and understand a little bit better the basics.
I'm building a game/engine and have written all of the networking stuff in pure UDP. There is a ton of stuff you can get away/be lazier with in a single player game; put simply you can be lazier with your data and overall layout. In a single player game you can make a ton of assumptions, and/or rely on work that's already been done elsewhere. A good example is, on the server application(or in single player mode), every character has a ton of values associated with stats and bonuses and what not. For the client to properly simulate what's on the server, you'd need to either send a massive chunk of data from the server every single time a new character was visible, or find a way to detach various actions from their full simulation and send a tiny packet and expand upon it client-side. Do you send a damage value with the projectile_add packet? what if the damage isn't calculated until hit and there are crits/resists/etc? Then, obviously the nightmare that can be async, combined with the network layer and things like latency, dropped or re-ordered packets, etc. If a thread keeps getting blocked and goes to sleep, in my experiences the debugger isn't going to help, so it's print-to-console-debugging and other logging systems built into the program itself that you need to rely on. Sending some packets back and forth is incredibly easy and you could get something working in a couple hours probably, the bigger hurdle is the layout of your program being compatible with callbacks and simplifiying/minimizing interaction points between threads. Most of the system could be ''working'', until you put it under any load and realize it's constantly hanging waiting on main or networking thread... WHO KNOWS !? The 'plus-side' is though, doing the work to align things for networking usually means any sort of future feature-extending becomes easier. Certain abstractions or gains that you might think pointless for a single player game or might not even think of until you'd explicitly need it, can actually end up being a gain regardless. Something like allowing a player to save their game is really easy when you already have data accessible and formatted for network messages. Being that I decided to go with full UDP, I had to build the packet handling system for things like confirmation and resending for missed replies, connection/time-out/etc. TCP would be much easier I'd imagine in many ways, and would likely be the way to go for anything not intending to work on a larger scale(or maybe period lol).
@@StevenMartinGuitar Part of it was obviously learning, as this was my first networking system I've built. Unless you need confirmation/resends/etc on every single message going out, I think you'd technically be able to build a more performant and scalable system going with UDP. I don't like that TCP handles the connection and timeout stuff, and that's really easy to implement on top of UDP. A good portion of the fast -flying messages could technically get dropped without issue and I wouldn't want to potentially halt communication on required packets for TCP to catch-up(I do have systems in place for package sequencing to prevent out-of-order messages). To be honestly I'm not entirely sure how TCP handles confirmation, but I'm assuming it uses some sort of hashing function + sequence, but on the entire outgoing packet and not individual messages within? Currently certain things are easier, or even possible at all, because I can build my own confirmation packets for certain situations. There's also the fact that TCP headers are at least 2.5x larger than UDP packet headers, and since not every message can get bundled into a larger packet it can add up quick.
The trick is, you don't need to send a ton of data. Only the bare minimum. Basically location and direction and some visual queues like of they're holding a pistol or a bazooka, crouch/jump status. That's a handful of bytes. Everything else is client side or doesn't need to be updated as often. Location, you need every game frame. Their health, maybe every 10 or more seldom and only if you want to display it to the player. Otherwise bool alive/dead is sufficient. Same for every other stat/visual, like making them glow when they have a power up or rendering ice on them when they're frozen in some magic rpg game.
@@Hazanko83about the UDP/TCP. Ever since Google invented QUIC and managed to emulate TCP while using UDP, essentially rebuilding TCP from scratch and making it better and faster with less overhead, without the annoying slow start mechanic that was created 30+ years ago when 128kb/s was considered fast Internet. I think for most applications, it's better to not use TCP anymore, if you can use QUIC or something like it.
@@borstenpinsel Yes exactly. Client-side, all network characters regardless of whether they are a player or NPC don't use the full Player/NPC class but instead a network variant that only requires the bare minimum: things like movement, location, health/mana/etc, flags for combat and what skills are active, and then basically all the other stuff can be tied to uniqueIDs for what character to show and their weapon and what not. Location and velocity I send at a variable update rate depending on if they are moving at all, on a normal path, or if the path is congested with a lot of obstacles and/or there are collisions. Pretty much everything other message for things like health updates or flag changes are handled on events and obviously don't need to be sent regularly, or only needs to be sent upon the initial 'server-add-character' message
(just some general feedback/through on the project. Not meant to be feature request; just take on the way you're going so feel free to ignore them) So, a problem with having the entire state of the game to the client is that the client has the entire state of the game. So wallhacks are hard to prevent with that design. Another point is that you have a full server round trip every time a player tries to move (and the final position is decided by the server). Not the worst on low latency but effectively not having direct control over your character can jarring. Giving players control over their position does open up room for abuse but nothing a "trust but verify" approach can't prevent. But if you allow player to decide were they are, there are "fun" desync that can happen with 1 player stopping before a corner an another one shooting the server prediction going past the corner. One think they shoot the other, the other thinks they didn't get exposed. How you deal with that has to be decided by what feels right. You can make slowing down be slugish to reduce the size of the server misprediction. The most complex games engines I've seen had timestamp in client message and rollbacked the server state to process event sequentially. Even then, the issue had to be decided based on what felt right to avoid being biases toward player lagging and because you kinda want to reward head shots.
1:07:50 While it doesn't generate the function, but with the newest version, it does infer the return type (`arg is Test`) if you follow some rules (which helps reduce code bugs). There's also some libraries out there for it
2:10:09 the difference is that interfaces get merged, so if you declare an interface Vector2, you can later redefine the interface and it won't replace it but rather merge it.
On BSON: I used it quite a bit, and found it lacking for my purposes. I wanted smaller network messages, but the BSON serialized messages wound up being about the same size as the equivalent JSON. We switched to protobufs where we don't need readable strings.
Haven't used BSON much, but used to use MessagePack back in the day. And while it was not terrible for its time, it wasn't great for real-time either, and still very heavy. If I had to choose a format for delivering packets in real-time, it would not be either of those, that's for sure. I'd rather bite the bad apple and then either use protobufs (which has its own downsides; recommend reading "Protobuffers Are Wrong" by Sandy Maguire), or "just" manually define protocols and figure out a plan for compatibility with the team. It's a bit easier if you control the client and force people to update in case of protocol changes so you don't need to think about backwards-compatibility. But in cases where you can't, protobuf may be a safer choice, or flatbuffers depending on your needs.
Not too far off from how I did multiplayer in my engine, though I'm still kind of stuck trying to figure out getting physics objects synched without blowing up the simulation or needing insane amounts of bandwidth. I also added networking pretty late in my engine's design, it wasn't *that* bad adding it in... Not saying it's pretty, it's still pretty much hacked in still, but wouldn't take much to clean it up. lol It's something that's fairly low priority.
You happened to be in the lucky situation where your .mts and .mjs are in the same place so you can just switch to .mjs. Usually the correct way to import typescript files .ts .mts .tsx you just omit the extension and in the case of index.ts you can also omit the file name (just specify the directory containing the file)
Hello Tsoding / whoever it my interest. Could you please share your emacs else vim plugins/configurations?.New fan here and am amazed at how you immediately find docs for functions. e.g At timestamp 53:02
Found a BUG !!!!! When i throw multiple bombs, i only hear exploding sound when the last one explodes. And also sometimes if i throw a bomb 45deg at the corner of a block, it goes inside, like ignoring collisions.
Твои видосы отличные, но мне, как русскоговорящему, тяжело слушать русский акцент) Если тебе не похуй на мой совет, то изучи правильное произношение звуков в английском. Например звук "т" в англе совершенно другой (и при этом не сложный бтв)
lowkey does feel like mr tsoding is writing JS like it's C. I would at least try to process events in their callback to have more event driven architecture. it could complicate the sequence of events but i think you can account for that. it would flow better with the nature of JS imo
Finally new video from my favorite web developer!
Vid From fav web, game, c, c++, python, programming language, ...., game engine, ... all developer
My favorite JavaScript influencer!
💀
can your python do that?
@@nonefvnfvnjnjnjevjenjvonej3384why are you interested on what peoples "python"s can do? 😏
Bro: I don’t have any experience with networking
Also bro: Written a web server in assembly
sync of the multiplayer was an issue, we blamed it on Einstein and his time dilatation theory :)
As response to the question at 20:00. I've been using vanilla JavaScript with Esmodules and Jsdoc comments. Typescript LSP can parse the doc comments from .js files. That way I'm not using any dependencies or build system while having types and an LSP.
Delivering ES Modules without any bundling will make it more difficult for you to deliver a good user experience and avoid waterfalls, especially as you add more and more code and internal dependencies.
Instead of bundling the necessary parts, and minifying them for higher compression ratios, you are delivering a dependency graph for the client to resolve through network boundaries. Sure you could try to manually structure your project such a way that the code necessary for a given page is delivered in the least amount of network boundaries, but you now have to make decisions of where place your code in which modules to prevent waterfalls.
Great for hobby projects and small apps with very few modules, but not ideal for user experience-and your servers-if you want to scale beyond that. There is no such thing as "no dependencies" when you rely on ES Modules; each import statement creates a network-bound dependency in the browser.
the twitch chat as subtitles is the best things i've ever seen
Thanks for all your videos.
Nowadays people just act as consumers of high level, messy abstractions without understanding the basics.
Complex solutions are invading each area and people think it is cool and the right way.
I’m so, so sick.
I enjoy your recreational programming videos. They help me learn about different topics and understand a little bit better the basics.
+1 (Very Real)
Exactly
I just have finished to watch the previous yesterday after work and here we are again! My fav content on yt
These thumbnails are so good lol
I'm building a game/engine and have written all of the networking stuff in pure UDP. There is a ton of stuff you can get away/be lazier with in a single player game; put simply you can be lazier with your data and overall layout.
In a single player game you can make a ton of assumptions, and/or rely on work that's already been done elsewhere.
A good example is, on the server application(or in single player mode), every character has a ton of values associated with stats and bonuses and what not. For the client to properly simulate what's on the server, you'd need to either send a massive chunk of data from the server every single time a new character was visible, or find a way to detach various actions from their full simulation and send a tiny packet and expand upon it client-side. Do you send a damage value with the projectile_add packet? what if the damage isn't calculated until hit and there are crits/resists/etc?
Then, obviously the nightmare that can be async, combined with the network layer and things like latency, dropped or re-ordered packets, etc. If a thread keeps getting blocked and goes to sleep, in my experiences the debugger isn't going to help, so it's print-to-console-debugging and other logging systems built into the program itself that you need to rely on. Sending some packets back and forth is incredibly easy and you could get something working in a couple hours probably, the bigger hurdle is the layout of your program being compatible with callbacks and simplifiying/minimizing interaction points between threads. Most of the system could be ''working'', until you put it under any load and realize it's constantly hanging waiting on main or networking thread... WHO KNOWS !?
The 'plus-side' is though, doing the work to align things for networking usually means any sort of future feature-extending becomes easier. Certain abstractions or gains that you might think pointless for a single player game or might not even think of until you'd explicitly need it, can actually end up being a gain regardless. Something like allowing a player to save their game is really easy when you already have data accessible and formatted for network messages.
Being that I decided to go with full UDP, I had to build the packet handling system for things like confirmation and resending for missed replies, connection/time-out/etc. TCP would be much easier I'd imagine in many ways, and would likely be the way to go for anything not intending to work on a larger scale(or maybe period lol).
If you need reliable network comms, which you hinted at with confirmation and resends, then TCP likely would have been more appropriate
@@StevenMartinGuitar Part of it was obviously learning, as this was my first networking system I've built. Unless you need confirmation/resends/etc on every single message going out, I think you'd technically be able to build a more performant and scalable system going with UDP.
I don't like that TCP handles the connection and timeout stuff, and that's really easy to implement on top of UDP. A good portion of the fast -flying messages could technically get dropped without issue and I wouldn't want to potentially halt communication on required packets for TCP to catch-up(I do have systems in place for package sequencing to prevent out-of-order messages).
To be honestly I'm not entirely sure how TCP handles confirmation, but I'm assuming it uses some sort of hashing function + sequence, but on the entire outgoing packet and not individual messages within? Currently certain things are easier, or even possible at all, because I can build my own confirmation packets for certain situations.
There's also the fact that TCP headers are at least 2.5x larger than UDP packet headers, and since not every message can get bundled into a larger packet it can add up quick.
The trick is, you don't need to send a ton of data. Only the bare minimum. Basically location and direction and some visual queues like of they're holding a pistol or a bazooka, crouch/jump status. That's a handful of bytes.
Everything else is client side or doesn't need to be updated as often. Location, you need every game frame. Their health, maybe every 10 or more seldom and only if you want to display it to the player. Otherwise bool alive/dead is sufficient.
Same for every other stat/visual, like making them glow when they have a power up or rendering ice on them when they're frozen in some magic rpg game.
@@Hazanko83about the UDP/TCP. Ever since Google invented QUIC and managed to emulate TCP while using UDP, essentially rebuilding TCP from scratch and making it better and faster with less overhead, without the annoying slow start mechanic that was created 30+ years ago when 128kb/s was considered fast Internet. I think for most applications, it's better to not use TCP anymore, if you can use QUIC or something like it.
@@borstenpinsel Yes exactly. Client-side, all network characters regardless of whether they are a player or NPC don't use the full Player/NPC class but instead a network variant that only requires the bare minimum: things like movement, location, health/mana/etc, flags for combat and what skills are active, and then basically all the other stuff can be tied to uniqueIDs for what character to show and their weapon and what not.
Location and velocity I send at a variable update rate depending on if they are moving at all, on a normal path, or if the path is congested with a lot of obstacles and/or there are collisions. Pretty much everything other message for things like health updates or flag changes are handled on events and obviously don't need to be sent regularly, or only needs to be sent upon the initial 'server-add-character' message
(just some general feedback/through on the project. Not meant to be feature request; just take on the way you're going so feel free to ignore them)
So, a problem with having the entire state of the game to the client is that the client has the entire state of the game.
So wallhacks are hard to prevent with that design.
Another point is that you have a full server round trip every time a player tries to move (and the final position is decided by the server).
Not the worst on low latency but effectively not having direct control over your character can jarring.
Giving players control over their position does open up room for abuse but nothing a "trust but verify" approach can't prevent.
But if you allow player to decide were they are, there are "fun" desync that can happen with 1 player stopping before a corner an another one shooting the server prediction going past the corner. One think they shoot the other, the other thinks they didn't get exposed.
How you deal with that has to be decided by what feels right. You can make slowing down be slugish to reduce the size of the server misprediction.
The most complex games engines I've seen had timestamp in client message and rollbacked the server state to process event sequentially.
Even then, the issue had to be decided based on what felt right to avoid being biases toward player lagging and because you kinda want to reward head shots.
Love seeing your videos, man !
1:07:50 While it doesn't generate the function, but with the newest version, it does infer the return type (`arg is Test`) if you follow some rules (which helps reduce code bugs). There's also some libraries out there for it
Can't wait for continue.
Thank you for all your content!
2:10:09 the difference is that interfaces get merged, so if you declare an interface Vector2, you can later redefine the interface and it won't replace it but rather merge it.
Did I just watch whole vod on my holidays with gf? Of course, first things first
3:00:06 If you change from interface to type you’ll force the users of the type to initialize all fields, solving the problem
On BSON: I used it quite a bit, and found it lacking for my purposes. I wanted smaller network messages, but the BSON serialized messages wound up being about the same size as the equivalent JSON. We switched to protobufs where we don't need readable strings.
Haven't used BSON much, but used to use MessagePack back in the day. And while it was not terrible for its time, it wasn't great for real-time either, and still very heavy. If I had to choose a format for delivering packets in real-time, it would not be either of those, that's for sure.
I'd rather bite the bad apple and then either use protobufs (which has its own downsides; recommend reading "Protobuffers Are Wrong" by Sandy Maguire), or "just" manually define protocols and figure out a plan for compatibility with the team.
It's a bit easier if you control the client and force people to update in case of protocol changes so you don't need to think about backwards-compatibility. But in cases where you can't, protobuf may be a safer choice, or flatbuffers depending on your needs.
Crazy that Doom was usually getting about 35 fps on then current hardware when it launched in 1993 ;)
If you want to make it even fancier, add proximity voice chat
Not too far off from how I did multiplayer in my engine, though I'm still kind of stuck trying to figure out getting physics objects synched without blowing up the simulation or needing insane amounts of bandwidth.
I also added networking pretty late in my engine's design, it wasn't *that* bad adding it in... Not saying it's pretty, it's still pretty much hacked in still, but wouldn't take much to clean it up. lol
It's something that's fairly low priority.
Awesome stream zozin :)
You happened to be in the lucky situation where your .mts and .mjs are in the same place so you can just switch to .mjs.
Usually the correct way to import typescript files .ts .mts .tsx you just omit the extension and in the case of index.ts you can also omit the file name (just specify the directory containing the file)
7:16 It's literally Xorg 👀
51:08 NBT also exists
you are a legend!
p.s. как же я ору с чата на твиче 😀
Amazing playlist. Thanks.
Never realized subtitles are chat messages
Awesome episode, Im grateful
new follower of this genius dude
02:07:22 valid directions: __defineGetter__, __defineSetter__, __lookupGetter__, __lookupSetter__, __proto__, constructor, down, hasOwnProperty, isPrototypeOf, left, propertyIsEnumerable, right, toLocaleString, toString, up, valueOf
why is the twitch chat showing up on the subtitles owo
edit: i just realized now lol
Sorry for being 30 seconds late :(
I was a whole minute late 😔
God damn I love yasnippet. Such a massive (potential) time saver it's sort of ridiculous.
At 46:32 (extension on import) I like the way you think 🙃
Probably deno and bun will serve you better 😉
tsoding is real sus when it comes to explanation, he really shows the path from dumb to "let`s try that, sounds cool"
enjoyed this episode.
Tsoding trying godot 4 would be fun to watch
I am glad I lived until I saw tsoding turning into a web developer
plus we were dealing with like 96K bits per second
My ultimate hatred for JS grew exponentially ... Stay Up G and keep em coming!
3:03:45 Forgot to consider the player size when you hit the boundaries
1:05:15 ...these typeguards are going away in next version of typescript, it will assume it automatically (not sure to which extend tho)
12:35 yes, there is from gpu to cpu
how else would screen recorders like obs work?
Hello mr Tsoding, have you ever done a NES emulator?
This mf does in 3 hours what would take me 30
@TsodingDaily Would using protobufs be a good alternative to JSON?
What is the problem with using something like zod to define the types for the payload and using zod parse instead of this custom function
it was like he was using js on purpose and wanted to mock him. lol
data is pronounced data unless you're The Cherno
Type guards automatically works in TS 5.5.3+
My porn folder is much greater than 53GB...
Hello Tsoding / whoever it my interest. Could you please share your emacs else vim plugins/configurations?.New fan here and am amazed at how you immediately find docs for functions. e.g At timestamp 53:02
01:12:00 what if server sends bogus-amogus message that is not valid json and JSON.parse throws error?
I want to know how you did that at 40:00
Waiting for moving this project to urmom vps.
Why is it called properMod, can anyone explain?
it's corncob 3D :)
1:52:26
What is text editor?
What even is text?
@@user-fj3gl8wc7s по русски пжлст
лучший
2:21:22 📑
btw, why tsoding use ts even he doesnt turn any linter option.
Hes a chaddd
56:59 fkin LOL
Found a BUG !!!!! When i throw multiple bombs, i only hear exploding sound when the last one explodes. And also sometimes if i throw a bomb 45deg at the corner of a block, it goes inside, like ignoring collisions.
Pog
30 seconds and 2 views, tsoding really fell down.
Твои видосы отличные, но мне, как русскоговорящему, тяжело слушать русский акцент) Если тебе не похуй на мой совет, то изучи правильное произношение звуков в английском. Например звук "т" в англе совершенно другой (и при этом не сложный бтв)
Видимо ты единственный, кого акцент не устраивает. Все спокойно смотрят
@@Tezla0 завидую
You are a sooka babushka then , (don't heck me bliss)
I am hoping that I stop watching political hacks and that I start learning from a master here
lowkey does feel like mr tsoding is writing JS like it's C. I would at least try to process events in their callback to have more event driven architecture. it could complicate the sequence of events but i think you can account for that. it would flow better with the nature of JS imo