Hey everybody, welcome back to another episode of our scalable game design stream. I was gonna say podcast, but this is totally, totally not a podcast. I'm Eric Jacobs, I'm the host here, leading this merry band of rabble rousers and full stack developers, I guess we all decided we were. So today we've got Derek Greese. Hey. Who unfortunately had poem all nighter. So he's a little under the weather. We've got Roger Keeley. Hey folks. Kylie. Kylie. Kylie, I put you that all the time, I apologize. I will commit it to memory now. Okay, Jared, Sprague, Sprague. Yes, Sprague. Hello. Starting to get these right, and Michael Clayton. Hello. Is that the Santa Fevers ringing in my ears? So please forgive me. Oh yes, right, yeah, roofers. So today we've made a ton of progress since the break. We skipped a month because we wanted to make lots of progress. And so today we've got an interesting agenda. We're going to start with Roddy, and he's going to talk about AMQP and Stomp and all things messaging, and then sort of give a little bit of a high level tour of some of the rip and replace we did to change from Stomp to AMQP on the server side. And then we made a super, I made a super hack job of a prototype of the web client that Jared then turned into a much prettier version that actually is something that humans can develop on and not fat fingered, ham-fisted people like me. So he's going to show that off. And then we're going to talk a little bit about actual game design-y stuff. So now that we have sort of a play field and players, we need to start thinking about like, how big should the play field be? And where should we put the players? Clearly if people are shooting each other, they shouldn't start right on top of another. Or maybe they should. I don't know, we'll talk about it. So that being said, Roddy, I'm going to kind of make it your show a little bit only in the sense of a share screen, dear thing, your charge share. So yeah, so looking back at how we got here, we took basically something that was a proof of concept. Off to a good start. Can you hear me okay? Yeah, yeah, I was just mumbling on my breath. How did we get here? Oh, so. How did we? Yeah, we're all here today.  And it was based on stomp so that we could communicate into the browser and then using a payload of essentially Google protocol buffers, right? So basically WebSocket on the browser side using stomp, which is a simple text oriented messaging protocol. I think that's what stomp stands for. I was just about to ask you. Yeah, yeah, it's really simple, right? Like, I mean, you could open up Telnet and talk stomp really. Yeah. So yeah, the goal there was to talk to like a C++ back in and have talk through WebSocket into a browser. And at the time it was through like through Flash using the old Netscape API in the browser. So since then now we have the like Eric said, we have a JavaScript based web client. The chart just basically put some nice structure around using NPM plus the knowledge and he said to actually structure it properly. And then we here today wanted to be doing more modern things moving into an open shift deployment, that type of thing. And so if we look at what stomp is as a protocol, it's an implementation of the JMS API. And so JMS was Java messaging system or something like that. And that is very much a middleware oriented protocol. So looking forward, we wanted to be using AMQP. Now if I can find where the chat is on the Twitch screen or actually in the Discord is probably a great place to drop it. Oh yeah, I should even maybe put a link to the Discord. Yeah, that'd be good. So we wanted to start using this AMQP thing because we here at Red Hat leave in open standards and an open fully internationally recognized standard is better than a de facto standard. So AMQP is actually a full standard. Let's see if I can find the right links. First, it started out at Oasis. I'll just drop the link into the Discord channel here. Okay, I will put it back into the restraint chat. Okay, perfect. And as well, we can see that later on basically over the course of a couple of years it was fully standardized through working groups and committees into AMQP 1.0. Which is an ISO standard, 19-464-2014, all fully available with regards to the standard. And if you want to understand how the gory details work. So one of the important things there is that it actually fully defines how the data looks on the wire and it defines the type system. So Stomp didn't really define how the data looked on the wire. And if you're using like a previous message broker like the original ActiveMQ classic, the data on the wire in different broker implementations was actually different. So even though all message brokers may have been JMS API spec compliant, the API was the same, but what happened on the wire was different. So ActiveMQ had this thing called OpenWire which was basically the definition of how the data looked in binary going across the wire. Whereas AMQP includes that in the specification. So not only is it the protocol and the API and the behavior, it is also what the type system and the data that looks like on the wire. Now of course that being said, we sidestep a little bit of that because we use Google protocol buffers as the payload in the data section for the AMQP messages, right? And one of the reasons that, well, we'd started out using protocol buffers, but I still like the idea of using protocol buffers because the message formats are not implicit. They're very explicit. And you define these dot-proto files that basically lay out like, this is my data, this is this particular type of message. This message contains position, which is an X and Y and velocity, which is an X and Y. And the other thing the protocol buffers gives you is really nice is the way they serialize and DCI realize the data onto the wire, or in this case, into the message, the protocol buffer message is with a variable size encoding. So if you only have an int of size eight and you set it as a variable size encoding, then you're only taking like three bits to encode that data onto the wire. So obviously the amount of data we're pushing across the wire is always a big concern, especially in the case of gaming, right? Like you want to be able to support as many clients as possible. So the downside at the moment is that, so AMQP defines the messaging protocol and it defines the type system. And in their case, we're using Google protocol buffers as the payload, but traditionally messaging from like an enterprise standpoint, enterprises like their messaging to be reliable generally. When one business function sends a message to another business function, you want to be pretty sure it's going to get there, right? So that- And you may need to be confident that it got there. And you also may need to be confident that it can get there, right? With AMQP, you have different types of settlement modes like you can send and wait for settlement. You can send a pre-settle, which is more like a fire and forget. So we had this different types of delivery depending on the need, but ultimately we're sending over TCP, right? So AMQP is a layer above TCP and TCP is how the internet works, right? Well, parts of the internet. Or sometimes doesn't work, like the head of the line blocking problem that sometimes gets run into where things that have to go from here to Beijing and I'm in Eastern Canada have to pass through a lot of hops, right? And depending upon packet prioritization and any number of factors that are completely out of control, TCP might wait or it may take a while for the packet to get through or the packet might disappear and the hardware at different levels decides, oh, I'm just gonna keep resending it and the application is basically like, hey, what's going on here? I'd really like to do something, but I'm waiting for this one packet and then that one packet disappears then has to transmit a whole bunch of gain. So like it can be a really bad thing when it comes to introducing latency, which is bad for games, right? So- Generally for certain types of games. For some types of games, that's true. But ideally we would like to use AMP for all types of games and host all types of games on OpenShift, right? So there is some movement to utilize, for example, the library where we're using for the server, which is now called Cupid Proton, which is an AMQP implementation. There's some move there to basically make that support not only raw TCP, which was recently implemented so that other protocols could be implemented using that library, but also UDP, meaning we hopefully in the future can do a fully ISO standard open protocol over UDP, which gets us closer to that mix and match of reliable UDP for games that need it versus regular TCP for something like maybe a turn-based strategy game, right? So I'm just gonna drop some links in there just as a reference. Yeah, I just put the Cupid link in the restrain not in the discord, but I will put it in the discord now. So that's Cupid, which includes the C++ data. Yep. So what we were using is this library in the past called the CMS Client for ActiveMQ. And essentially it was called CMS because it was a C++ implementation of the JMS 1.0 API specification, right? So even though it was in C++, it was very familiar for those backend enterprise developers who came from Java and- For all the Java people that randomly got assigned to write C code, it felt familiar. Well, I found myself in that bucket, right? For sure. Yeah, square peg in a round hole, it does happen. Yeah, for sure. So what we've been trying to do over the last month or two is basically rip and replace CMS. We succeeded. And we did. Don't cut yourself short. And we did succeed, correct. So I'll just, so from the backend server point of view, I'll just drop a link in here to the GitHub. One of the main pull requests where things were almost working, but not quite where you can see a lot of the work essentially was to like take all the references to CMS out. And not only do we depend on CMS in the backend server for the messaging part, the server was kind of very non C++ 11 adherent, meaning like the threading model came from CMS, the new taxes came from CMS, all that kind of stuff. So it was a couple of stage process where we put in standard thread, we put in more like standard cues, we put in standard locking mechanisms. And then as well, then we ripped out the CMS messaging stuff, we put in the AMQP messaging stuff. And then as well then we said, well, hey, we got to do this with the client too, right? So on the client side, there's a very good AMQP implementation written in JavaScript by a fellow messaging engineer, Gordon Sim that we basically hacked into place quickly. And then Jared did some great massaging on to get it more structured and look sensible, call the REIA. So I had what we call a day of learning recently and I spent my day learning JavaScript and REIA to kind of hack it into place, bit outside my wheelhouse, but I had a little bit of JavaScript experience, meaning I can get in there and look at, make it look really mangled and hopefully at the end of the day it works, right? That's what happened when somebody comes from like a static type language like C++ where C year go jumps into JavaScript. But I think at the end of the day, I think the result with some leadership by Eric to smooth over my mistakes and get the ball rolling there. Hardly leadership, the blind leading blind, sir. It could be. But either way, I think at this point, like I'm pretty excited about it, we're in good shape. Like we went from my perspective, like I had this code sitting in a local Git server from starting in 2011, right up through like basically 10 years ago. And I've been maintaining it slowly over time, like getting it up once or twice a year, I'd get a chance to poke at it and upgrade versions of the compiler and that kind of stuff. So for me, this is really exciting to have taken something that was old and didn't appear very useful anymore, but there was a proof of concept and proved something could work and to bring it kind of to modernize something that was dusty and creaky and leaky a little bit. We just did enterprise application modernization right here. Just happened. We're gonna strangle the monolith next and do some market service stuff. I mean, eventually, well, we're not really starting with a monolith. So I guess we're really strangling one. We can avoid that part. Yeah. We get to skip this. What is it, do not, we get to pass go and collect $200? Is that how this monopoly game? No, that's your problem. Yeah, and now it has some great logging that Eric found a Laguru library. Oh, kudos to those dudes, man. That library is super awesome. Yeah, so that's really been fantastic for us. Do you wanna show any code? Yeah, I can share here. It's a little bit slow where the stream is going all over the place here. Let me share a screen. Let me see if I can guess the right screen. It's like, is that the tech nerd roulette is guessing which one of your displays you have to share with the tool? I don't know, but it's on my conference called bingo card. What, share my screen or? Let me find the right screen to share, yeah. Oh, yeah. C line. So I think I only have one instance of C line opened up now. That's the UI I've been using. You're not sharing anything yet though. I'm trying. Oh, okay. I'm making it. Already going sideways. Yep. So I see that the right screen is number five and my assistant really wants me to open system preferences and give permission. Okay, that sounds like progress I think. Oh wait, it needs another password so I can get in to give it permission. Oh my gosh. This is Mac OS 11, by the way. Thanks Apple for my privacy. I don't know. More hoops to jump through when you really need to do something. Yeah. Oh, zoom OS will not be able to record until you're reopened. I don't think I'm gonna do that now. Quitting might be bad. But you don't need to record. That's right. I just need to share it. Oh, I can see the window in the little preview thingy now. Hey, something happened. Oh, do we have video from me? Yes, I see a screen. Awesome. All right. So I guess we can go, where do you wanna go here? I don't have it set up very easily. Let's go to me. Oh, is it possible for you to make your font bigger or was that a huge question? Does it present mode? Yeah, when you and I tried to do that though it ended up on a different screen and it was like- Yeah, it jumped around and stuff. See if I can do it very quickly. Appearance, that'll be good. I don't see an easy way to, I know there's a special key combination. I will look for that in the background. Okay, my keyboard is unfortunately- C-Line, SEA or C? C as in like the native- The letter C. Yeah, like JetBrains. Okay. So yeah, so essentially if you had looked in here before you would have seen like an active MQ initialized library statement. And in this case, we have something new here. Control plus mouse wheel. Oh, let's try that. No joy for me. Change the font size and tabs. In settings preferences, control alt S go to appearance and behavior, appearance. In the size field, specify the font size. I think that's what he just did though. I was trying to do. I guess it could be a little different on Mac, right? Cause everything is with the command key or whatever. Command alt S, command S? I don't know, whatever the appearance and behavior settings is. View, appearance. Do I see settings? Edit settings. All right, so maybe we'll show it a little closer later. What I'll do, I'll go and I'll make it bigger and come back, but essentially there's just a couple of lines that we- Oh, or you could just go to GitHub in the browser. Yeah, I could do that too. I probably won't automatically share my browser and let's see if we can share- Oh God, yeah, then you're gonna have to- Right? Can you see an empty tag? No, wait, I still CC line. Yeah, so what I've highlighted in blue that I can talk more to later maybe, there's just a couple of lines of code like literally too to get something that's called the proton container up and running in a thread. So essentially we create an instance of it and then in SDD thread, we capture the environment and then we do container.run. And essentially it has this thing called the proactor and basically means that it proactively takes care of intercepting messages and then gives you callbacks you can essentially listen for on the container. And when you receive messages of certain types like you'll get back, not even the message but you'll get an event from proton that says like send or open.  I've created a sender. We're good. We can send the message now. Yeah, so as that's kind of small I will stop sharing here for the moment. And we can maybe transition over to the client and take a look there and see what the flip side of the equation is. Cause it takes both sides of the coin in order for us to actually have the game like a full multiplayer game. Both the client and the server. That's right. Totally overrated. I really, everything should just be servers. Well, in some cases you're not far off, right? The client and the server is one thing and it exists in multiple places. Sometimes that's the case. Yeah, context is true. Jared, do you wanna share your name? Yes, let me go ahead and share. We had one person in the chat, who was it? Brett Toffle was like, oh, you should make a TypeScript, which I think I would have a TypeScript. And I said, oh, well, we're gonna have to talk about that. We are gonna talk about that. Okay. Do you see my screen then? I now see your screen. I don't. Okay, all right. So first, just a few updates about the web client. The first one is this cool little rocket chip that one of our... Yeah, Luke and Eric. Yeah, one of our fellow game devs made in about an hour after we asked for, we needed one. So that was awesome. But yeah, let me just... Okay, so first thing I wanna talk about is a little bit. Like I've re-architected the client to actually put some architecture around it so that we can have a sane development language that we talk to each other. So this is an MVC, basically architecture, but it shows how the client network fits into it. So basically we have the client code that Roddy and Eric wrote got extracted out into its own class called the AMQP game client. And all it does is talk to the server and sync the state and send commands pretty much. So between the server and the client, it syncs the model, which is the game state and it sends commands to the server. So it's gonna bi-directional. It's a game client. It's not a generic client. The generic client is the REIA client that Roddy mentioned earlier. Messaging client, yeah. Yeah, and that's generic. It just sends and receives. The game clients are wrapper around that that actually has some game logic in there, like player join game and player move, like sending a move command of the player. So there's a wrapper around that. And so that's what it does. So that took all that stuff out and put it into that class. So it's much easier to understand. So when it syncs the model, what it does is it, it gets instantiated with a model object that the game that shared across the whole game. And everything that comes from the server is just updating that model. And it is a pojo. I don't know what pojo name is for JavaScript. I guess it's still pojo. And... Podge. Yeah. So, right, yeah. Right, and so it has the players, all of the players that are connected and whatever other kind of game state. That's all we have right now, pretty much is just players. But in the future, it'll have other actors, like enemies and objects that you can run into, asteroids, I don't know what all the stuff we're gonna add to it. But the model will have all of that stuff in it. The entire model is always on this server. We can do some optimizations in the future where only partial bits of the model get synced to the client, because it could be really huge. So the game client is constantly syncing the model. And then we have the controller, which is like the orchestrator, but the view takes that model and renders it pretty much. So it paints all of the players on the screen and basically the state of the world. And then the controller does stuff like, any kind of orchestrating stuff, like handling key commands that's gonna have to send a command to the server via the game client. That's what that relationship is for. And this architecture is very, very good because it does a few things, well it separates concerns very well, but what it does is one thing that's really important in multiplayer game is that the model and between the client and the server stays in sync. So having that extracted out into its own object makes that a lot easier to do than having it coupled in with other parts of the game. Makes it much easier to pass around. And having the view decoupled from everything else is really good because it lets us do things like change skins. And that's what we do like in Zorbio, like in another game we made where you can have many different skins. And you easily accomplish that by this NBC kind of pattern, the NBC pattern where you could write like the unicorns and rainbows plug in and then somebody else could write the Tim Burton Nightmare Before Christmas skin. Yep, exactly. And not only skins, but effects too. Like when something blows up with a skin, you get different color particles or you have different colors. Yeah, so any part of the view can be swapped out pretty much. And yeah, so yeah. So that design problem too of like, if the view can be swapped out. And in a lot of games, even though it's not intentional by the developer, you can still get into the DirectX API and modify the view. If there's information in the model that you don't want the player to know, but they still have it on the client, they can just add it to the view themselves by hacking it. True, yeah. I mean, then we get into the thing about like, you know how World of Warcraft has all these like view plugins because the API is open. And so I think it'd be cool to allow players to extend the UI somehow. Yeah, that'd be kind of a cool design trope, right?  So, but yeah. So any other questions before I move on? Well, I think the point that Derek was trying to make there was more like, if there's a variable, if you will, that the player shouldn't really know about, like you don't want, you don't want it to be in the model anywhere on the client side because, in theory, they have access to it. Is that what you're saying, Derek? Yeah, essentially, it restricts what you want available in that model, which is not going to be the exact same as what's on the server because the server is keeping track of everything. Yeah, yeah, yeah. Those are things, well, those are bridges we'll cross. And you have to, I mean, right, but they're... Well, the client has to know, the client has to know the positions of things. Yeah, yeah, there's a core set of things that the client must absolutely know. And then there's a lot of other stuff that the client maybe doesn't need to know, but we don't know what the client shouldn't know until we sort of get into it by the thing. It's like during the arcade week, when we had the Red Hat Arcade up, which by the way is technically public now, right? Oh, we should mention that. It is, yeah. When we had that up, the guy that looked at the JavaScript, and we were all concerned with like hashing and MD5 something, I don't remember what it was like. He just changed the variable in the browser console and then used the send command. It's like, oh, we didn't think about that. Free high score. The browser and he changed it before our secure stuff. So it... Yeah, he changed the input into the security function. It's like, oh, in a weird way, it's like the data supply chain of the client. Like where does somebody perform an injection attack? Yeah. Right, yeah. Even in games, ladies and gentlemen, it's especially a problem with Java script-based games, web games, because all the source code is in the browser and you cannot avoid that. Like it's just the nature of it. So you have to...  There's probably some wacko way to avoid it that hasn't been figured out yet. Well, it's kind of true on any game. Yeah, if there's a game client running, you're in control of the bits ultimately. It's just way easier to manipulate them. Yeah, in browser. True. You've got to be able to do the tools right. Isn't that how the old... Oh, what was that thing called? The game genie that you'd put between the cartridge and the console and then you could flip dip switches and stuff and it would modify. Super snapshot. That was magic. You push the button and you end up into disassembly and you just go in and manipulate the memory directly. And you could watch the assembly commands running for the copy protection check or your character dying or whatever. Just jump past it. Yeah, you just jump past it. Yeah, man. Game genie was awesome.  All the permutations. What does this dip switch do? Yeah. I mean, I'm sure there was a more strategic way of doing it, but maybe not. Maybe it was just, you know... Some people just do that. He's on keyboards writing Shakespeare. Right. Wow, we've gotten far off topic. No, no, I think it's totally relevant. Yeah. So, all right. Well, I'll move on then. So we can go on. But, so I just want to talk just like super briefly about the refactoring that I did on the web client as starting with TypeScript and Webpack. So someone mentioned TypeScript in chat and I also have a background in C++ and Java before I moved on to Node JavaScript. And so when I was like, well, this is a good opportunity to learn TypeScript. So I started by embarking on making it into TypeScript. And at first it was, well, it was awesome. Like, I was like giddy when I was like, oh my gosh, like in a JavaScript class that can take Type Private on a property? Like that's insane. Like that's never been possible in just normal JavaScript. You type private and then the variable name and this is a string and you can even make it read only. It's like, and then all the stuff is typed and just being able to type that it felt like coming home almost to like my roots of JavaScript of like C++ and Java. And then on all of the parameters and stuff and the other wonderful thing about it is when you import the types of all the libraries that you're using, almost, you know, most editors have an intelligence where you can just hover over it and it'll tell you all the stuff you need to know about it. And like, what is this like property that's three layers deep like dot, dot, dot property in an object that I'm reading right now? Just hover over, like in normal JavaScript that's really hard to do. Like you have no idea what that is without. Yeah, and you just have to, but yeah, there's a lot of problems. It works, but the only way you can really know is by just knowing what that is. Like you have to have trust and you can look into the debugger, but with TypeScript, you can see exactly what type it is and all of the stuff about it. So to start out, I said that was, that all is the good part about it. So the negative thing about it is if you have to write something in a super short amount of time from scratch, TypeScript is gonna, I found it to slow me down because you have to be careful. You have to make sure everything's typed like and sometimes it takes the time to look up, okay, what is this function returning? And then is it actually a template of another type? And it's in the end, it's going to lead to a much more robust and easy to read code, but it slows it down a little bit. Would you agree with that, Michael? In general, yeah, I think that's true of all strongly typed languages. They slow you down a little bit at first, but you have a lot more assurance that your stuff is gonna work when it actually runs. Yeah, totally. And it helps you refactor because you can move your stuff around and break everything and then fix the types. Yeah. It's probably gonna work. Yeah, yeah. I mean, as a non-developer, what it sounds like to me is TypeScript versus not TypeScript simply changes where the code blows up. That's one way to put it, that's for sure. Yeah. I think that is nice about TypeScript though, how they've implemented the compiler is that even the errors, like the, if there's a type error that occurs when you run the compiler, it shows up as an error. But by default, I think it's still, it may be a setting, but it at least used to be the default behavior. It'll still emit JavaScript to run in the browser. So even if there's a problem with the types, you can kind of, as long as you're okay with a lot of red text in your console, you can implement stuff really quickly, not worrying about the type errors and have it run in browser and then go back and fix the type error. If you don't mind. Yeah. So you can kind of get around that slowness. Yeah. The quicksand. Yeah. And I think the slowness is really amplified at the beginning when you're starting something from scratch. Oh yeah. Oh yeah. And that's what I was doing. So I think once you have like a very solid foundation and you're not like all of your library, all your dependencies are pretty much set and working then, you know, in your code base is going like, then the like slowness is much, well, it almost goes away, I think by then. But when you're starting from scratch and you're like, okay, now I need to pull in a totally new library and start using its properties. And then I have to look up all of its types. Like it's multiplied when you're starting something from scratch and that's what I was running into. So it's like the difference between snowboarding and skiing. So you can get started with skiing and kind of make it down the mountain the first time, like not too bad. Yeah. Snowboarding is no. And so like the ramp up curve for one versus the other, like one is just like sort of gradual, whatever. And then kind of there's a huge ramp later and the other one is like huge ramp at the beginning, but then very gradual slope kind of. Yes. That's a really good analogy. Yeah. Totally. That's what it's like. And so- You can tell it's one of the origin sales. Yeah. So I, since I was racing to finish this demo by today, I like, I just had to give up on it because I was at the rate I was going with TypeScript wasn't gonna happen. Not that I don't like TypeScript and I think it's awesome. It's just, I had to go fast. And so, and it's starting from scratch. Quick and dirty. Yeah. I'm probably gonna go back to it again. Yeah. And then Webpack was the same thing. Like I, so Rhea with the latest version of Webpack does not work well. And I think I'm gonna file a bug with the maintainers of that. It throws in here. Webpack for Rhea. Rhea and using Webpack to package up your bundle. So Webpack is a quick background. It's like a bundler for JavaScript. So it takes all the JavaScript modules using push of them into a big JS file. Right. Or multiple. You could say it packs them. Yes. And it also does stuff like compiles the TypeScript and does be able to transpiling if you need to, et cetera. But the, it was throwing an air with Rhea and I could not figure it out.  And I think it's a bug with Rhea. I think it's a bug with Rhea. Got it. Yeah. It's not a bug with Webpack. Yeah. The newest version of Webpack is pretty, I mean, you know, it has a lot of changes, I think in it. So I'm, yeah. So I'll like talk to the maintainers maybe I'll find an issue about it. Cause it definitely is a problem with Rhea. But because I need to get something working I went totally buildless and that's the next step. So a lot, all the games that we've made except for one was square off. So Zorbio, PD about Earth, commandling heroes, Bash, all of those, they don't even have a build. They're just, they're just an index that HTML files and we just import the JavaScript in the index file and then reference it in the code. That's how this works. Yeah. So that's what it is for now, like until we can figure out some of the bugs about it, which works great and it's like clean. It also makes me, I don't know. I feel like, I feel freer when that happens cause then I don't have to worry about compiling anything or doing any kind of weird like modification, it just, it makes sense. But plus it's really fast because you don't have to wait for a build step. You just change a thing and it instantly is in your browser. The problem with it is that, so we're using features on ES8, which is 2017. It had async await and probably there were still some browsers out there that won't support that natively without being transpiled, I would think. ES6, I think it's like universal now, but ES8 was only three or four years ago and browsers are kind of slow to, people are slow to update. But it's a demo, so I think it's fine and it works for all of the people working on it anyway. We'll probably add a bit build later to add Babel to transpile it, but why not? So browser sync is a really nice tool where you can have your browser on one side, your editor on one side, you make a change and then it instantly refreshes, which I think a lot of front-enders or would be familiar with it, but it really helps make a speed-up development. I added ESLint to the project, which is very good if you're sharing code. It keeps standards consistent across developers, so everything, and it also finds a lot of common errors that might happen in JavaScript. Static code analysis is massive and important for keeping large game code bases and really any large code base in a quality, maintainable position. Yes, absolutely, yep, and it makes it, yeah, go ahead. Are you using VS Code? I'm using WebStorm, yeah, but ESLint will be, I mean, it'll run in VS Code, but I tested it in VS Code too, yeah. I just added the VS Code, ESLint extension. Yeah, and what that'll do is it'll give you linting errors as you're typing, so if you use var instead of let, for example, it'll give you an error right there in your browser, yeah.  And then it has a thing you can run to do it, like a script that'll run to check the entire code base and tell you any errors, yeah. One thing I wanna mention about browser, or not browser, but editor plugins for things like ESLint is that they're awesome because they show you in a very like editor native way where the errors are to fix them, but they're not awesome in the sense that most of them come kind of enabled by default, like let's say you install the ESLint plugin for VS Code. Which I just did. It will probably run on every JavaScript file you open, even if the projects that you're working on isn't it supposed to be using ESLint? And it's not so bad for something like ESLint, but it kind of depends on, like there's a ton of ESLint settings that you can tweak, like let's say you don't like the defaults so you change the defaults to something, like you don't wanna be warned about unused function arguments. Because sometimes you can't help it if you're like, if you have a callback for some API you're using and that callback is past arguments that you don't care about, you don't wanna be warned over and over about those. So something, just an example. I guess the short thing of what I'm trying to say is that if you have an editor plugin for ESLint or an equivalent for other tools, try to find the setting for it that says only use this if there's an ESLint RC file present in the project. That way you'll be sure that you're honoring the preferences of the project you're working on and not your own editor's configuration or over your own editor's configuration. Yeah, you wanna make sure you use the same one that the project is using, that's for sure, yeah. Yeah, and thanks for that, Michael, cool. So the, all right, so real clearly the structure about like how the code is organized pretty much. It's pretty simple, only you'll notice that it matches the architecture. So we have a directory for model view and controller. The scene in Phaser has mostly like the world is rendered by scenes. So you have a scene for your menu and then you have a scene for playing. And then when you die and you get taken to the game over screen, if it's a different screen, it'll show you that scene. Or for example, if you were making like a adventure game and you're changing room to room, you could be changing scenes. So it helps keep things very organized. This is a very nice thing about Phaser that makes a ton of sense, but that's under views. And then all the networking stuff that you guys had written, went into the network directory. So all the proto-buff definitions are under proto and then I made the AMQP game client is a network. Makes sense. Yep, and so yeah, that's pretty much. And then of course, the assets. Okay, so that is it for the slides. I don't know if you wanted to see a little bit of code real quickly. Sure. All right, so let me share my whole screen, my whole desktop, entire screen. So I think the easiest way to make this big is just put it in a terminal. Control plus. Can you guys see this? Let's show, I'm gonna show the preload actually. So. Yeah, I was just digging around in the code and was having trouble figuring out how. I'll show the game pretty much. I'll just say, yeah, yeah, I'll show you how it works. So the index HTML file, like I said, since it has no build, and also is this font good enough for people? Yeah, looks good for me. Okay, so since it has no build, you have to import the scripts yourself. So we import all of our dependencies. We only have four right now. And then finally add the, your first party scripts, which is the actual game. So there's a launcher is the index.js. So that's pretty easy to understand. And then if you look at index.js, it's very small. All it does is wait for the window to load. And then it starts a new game and it imports the game from game.js. And when you say new game, it launches the game. And then game.js. Oh, wait, no, that's index. That's a, so game.js, what it does, yeah. Yep. So what it does is it starts the game, it starts the phaser game. It's very small. So one, yeah, so keeping these kind of discreet files is easy, easier to understand. So in phaser it just takes a config object and that pretty much decides your whole game world. And then once the game, oh, actually one important thing about the really important about this is when you start the phaser game, you pass it, it's scenes. So there's a, and the first one here is the first scene it's gonna go to which is the preload scene. And that's imported here preloads. So when you say you pass it a list of scenes. Yeah. So it's gonna do the scenes that are in the list in order but that doesn't mean, that doesn't preclude there from being other scenes. It adds the scenes to the game container. It doesn't launch them until you tell it to but it will launch the first one. The first one it will launch. Okay, so the first one in the list it always launches and any other scenes you want to be present at initialization time in the array. Yep, and then you can bounce to them easily which I'm gonna show you next. So once you have them in the container you can jump to them easy. So then it'll go to the preload scene and this one is responsible for loading, loading the game obviously. It's gonna load all the assets. Do any asynchronous loading like it loads the protobufs. So loads images, loads audio, loads the protobufs via the AMQ game client. And it does all of that. It does that, it waits for that to, all of that to be done. So it preload is an asynchronous and it can run asynchronous functions and the game won't start until all of this stuff is completed loading. Once that's all done, then it does, it calls scene.start and then you pass it the key of the scene you wanna jump to. So now we're gonna go to the menu scene and this would be like the scene that has the play button on it. And you pass, you can pass arbitrary data to it which is the client, that's the AMQ game client and the model. So now we go to the menu, does nothing right now. All it does is it skips to the main scene. So in the future, when we add the play button, settings, the title screen, the title screen of the game will get rendered here when we're ready for it. There may be other things to do before the player is dumped into the play mode. Exactly. So then that's that. And then the final one is the main play area scene and what this does is like, back to the architecture is, it pretty much just renders. Like it doesn't do any network stuff, it doesn't do any model stuff. It gets the model from the, it has a reference to the model, but the model itself is getting updated by the AMQP game client. Most of what it does, so it starts the music as the background, but it renders the scene that we're in. And then here's the update function that updates the player positions. And it does it without any knowledge of the network. It's just going over the model. The model and the background is getting updated by the client. Does that all make sense? Yeah. Oh, makes sense. And then, oh, and then one very last thing, which we're working on right before this is, this scene also right now is handling keyboard presses. And when it gets a keyboard press, it's not going to do anything itself. It's going to pass that to the client to send the command to the server. So it's going to call this function on the client. This function that you're in right here, this is the actual game loop function, which gets called on every iteration of this scene, or this is the scene loop, if you will. Yep, this is the main, yep. And so then, yeah, and then that, so they press a key, it's going to send this move. Yeah, so if you scroll up real quick. Yeah. Again, to the iteration. So you can see it's iterating over every player in the model and essentially updating the location of their phaser body, which is like where the entity on the screen is, essentially. Yep, exactly. And so that's the position piece. The camera center, is that just like if you had moved the camera, you're offsetting it? Yeah, so that, and there's a couple, we were trying to center that, and I'll explain what this does in when I show the actual game. Sure, we're trying to center it on the actual player. Yeah, so you were doing, you had a fixed width, so you could take the width and the height and just divide it by two. Yeah. The camera's main center is telling you the X and Y of the very center of the camera in the inner window. So you resize it, no matter what size it is, that center X, Y is the center of the browser window of the game area. Yeah, so it makes it easier when you have a dynamically resizable play area. Okay, so let me show the game now. Probably need to start the server if it's running. It looks like it's running, so. You might want to restart it, because like, yeah, because you've got several players and every time you read the browser, there's new play and it's just like. All right, so let's go ahead and refresh here. So, so this is a full screen and this player is getting drawn by via the server, the client and passing the model to the server and then the client rendering the players. Yeah, can you go back to the server real quick? Yep. Oh, back to the server, yeah. Yeah, well, you're on it. If you restart the server and pass it, so right now it's in verbosity one, which isn't particularly interesting. So if you kill that and then add a dash E, so it's gonna be dash E. Log level, is it capital one? Log underscore level, log gas. Log level. U4. Equal four? Yeah, try that. Okay. And now refresh the browser. Oh, now it's dumping out more stuff. Yeah, but you'll see, so as soon as you refresh the browser and you go back to the server, now there's a player. And so what you'll see is I added a bunch of log messages into the server game loop. Yeah. Yeah, you're probably gonna have to maximize it because it's like super indented. Yeah, here, how's that better? Yeah, and so you can kill the server if you want to just scroll. But what you can see is it iterates the server, iterates over all the players, and then puts messages onto the message broker with information about each player's pod.   Yeah, or we've got something weird in the loop, but basically it says, okay, I'm gonna update this pod, which is UID, whatever. There was no movement, there was no shooting. I'm gonna update the timers. Here's the velocity and the position, and I'm gonna send that out to the client. Okay, next player, no movement, no shooting, here's the position. And so what we would see if we had the keyboard commands working, which we don't have them working.  I don't wanna send too much time on that because we want to get to some design issues. So let me just see if it, no, but it doesn't work. Sorry, break out of... It says handling incoming commands. I don't know. Yeah, break out of your server, restart your server, and go to log level eight. Okay. Because if I remember correctly, log level eight will barf out anything it actually gets. You may wanna change the game loop time also to like three seconds or multiple seconds. Oh, instead of... Sleep cycle, make it 1,500 or 2,000 or something like that. Okay. So that's 1.5 seconds per loop, which is still pretty fast. So now if you refresh the client. All right, this is good. All right, I'll refresh the client. And then if you press a button. Thumped out a bunch more. Yeah, that's fine.  Yeah, it doesn't look like it's receiving it. Okay, which means it's either not sending it or there's some other... It is sending it. Like if I... So here's the dev tools. Yeah. Wait, what happened? Well, so what happened is the server died. Oh, the server died. Yeah. It got stuck. Something. Yeah. I think when we left off, we didn't actually close the loop and test the input, right? Because it wasn't on the client side. So there definitely could be an issue still on the server side with the switch. Yeah. But okay, so, but we don't have to talk about that. The commands is like the next thing to fix. It is connecting, it's drawing the players. And it's sending commands, but it's just not hitting the right queue or the server's not receiving it or something. Yeah, we had it working at one point. Now we refactored everything and it's not working. Yeah. So one of the things we wanted to talk about was kind of game design issues. And this is sort of a good time to talk about it. And so one of the challenges is we're using, yeah, you can stop sharing screen. Where do I stop share? Here we go. So we're using box 2D, which is a 2D physics engine for C, well, I mean, the one we're using is the C++ implementation. There are implementations for lots of languages. And one of the interesting things about box 2D is that the universe has no fixed size. It is theoretically infinite. And it doesn't even really have a way, you have to like clues your way into creating a bounded 2D space, if you will. So you really have to create a boundary and then have objects bounce off the boundary or implement some other game design trope to prevent people from exceeding the boundaries of the game. But the other challenge is like, it also has some theoretical units, but they don't mean anything in our game, so to speak. So we sort of need to figure out like, well, okay, this is a spaceship. How big is the spaceship? Like in the game universe. And then we have to take those measurements and speeds and other things and then go backwards to display this in a way that makes sense. The units can be completely arbitrary. The scales don't even have to be meaningful, but we need a consistent mapping from server idea of player space to here's how we show this idea to the user experience. That was a very terrible sentence. So we had had a conversation in the Discord a couple of weeks ago about like, I sort of looked through popular small spaceship sci-fi stuff. I was like, how big is the ship from Firefly? How big is the Rosinante from the expanse? Like how big is this other thing? And what was the number that we got to? It was like, the ship should be 100 meters long or something like that. I don't remember, do you recall it? Let's see if I can scroll up in the Discord. If you were saying that these aren't like like last fighter individual that even goes flying, it's a big idea that we had very, very early come out with or discuss was like, you start out in an escape pod because the trope of the game is it's very circular, right? Like you keep trying to glom stuff onto your ship as you take out other players. And if you get taken out, you sort of end up back in an escape pod and have to start up all over again. It's like groundhog day in space. What? It's like groundhog day in space. Oh, absolutely. I mean, generally we're all living groundhog day, so we sort of need the both extremes of the scale, right? Like what are we envisioning as the largest, slowest, like yuckiest, capital ship being and then what's like the starting player size? Yeah. You know, go ahead, Derek. Oh, I was just gonna say the, what we had kind of talked about or what I talked about is 300 meters to 600 meters as the range, the reason behind that, behind having that mid-level range is that we want players to feel like their ship upgrades are substantial changes to the way that they play the game. So that means either we're looking at, like, you know, fighter size ships or capital ships, right? And if they get too large, we'll lose detail of the upgrades visually that we want a parent from like a game design perspective. So we don't wanna do fighter ships because the game is more about strategic and tactical thinking instead of, you know, your reaction time. And we wanna be able to communicate that to players. Like the first time they flop into this game, they should be like, I'm controlling a capital ship. I am thinking about strategy. I am thinking about the way my ship is upgraded, not how fast can I swipe my finger across the, you know, phone screen or whatever. Yeah. Yeah, so I'm finding the, I found the conversation now. And yes, you did say 300 to 600 meters. I'm the captain now, somebody says. Tachidi, can I get super capital ship? So, 300 meters, okay. So that gives us one number, if you will. And we almost, the meters is almost relevant. So it's 300 units, whatever those units are. The next question then becomes like, all right, well, how many players, yes, theoretically, there's an infinite number of players in a sector. But reasonably speaking, there's a finite number of players in the sector.  And so if you've got 20 things that are all 300 units in size, like what does that mean the play area needs to be from a unit perspective? Like a hundred thousand, like a 10,000? I don't know, right? We have to pick something and kind of go with it. And I think that's where a lot of the game tuning will come into play. It's like, oh God, it takes me five minutes to get to a player, like the player. Yeah, yeah, yeah.  So if the play field, you know, do we make the play field smaller or do we just make the speed of the ships faster? The player has no idea, doesn't have to have an idea what the units are until later, they just know like, okay, I'm covering ground more quickly than I was previously because I held the button down longer. The actual number of units that are elapsing is almost irrelevant, but we still need like unit numbers to sort of function. Yeah, I mean, if I were to pick a size to start with, I'd be like a hundred thousand units. And the reason for something so small is because we have talked about this mechanic of having players drift towards each other, regardless of where they're choosing to thrust, right? Or where they're trying to go, they need to move relative to other players and not necessarily at a static point in the map, right? So a hundred thousand units is, I just did math, it's 333 players across, if you will. So if you took a player and then just stacked players touching all the way across the play field, that would be 333 of them. You know, is that good or bad? I don't know, but that's the number that we'll go with for now. And then we have to sort of determine a speed, right? Like a top speed of the starting unit, if you will. Because theoretically we all are in agreement maybe that every mod you put on your ship makes you slower. You start at the top, at the fastest possible speed you can have. And everything you do makes you slower, either rotation or velocity or both, agreed? And the way that I, yes. And the way that I like to do balance in games is I like to keep all numbers under 50. And if I can help at all numbers under 20. Makes balance easier, it's a lot easier to talk about with other people. Human brains are really bad at math that goes beyond like 10 anyways.  So if you're balancing around these, you know, these small numbers, it's a lot easier to talk about or easier to make sense. And it's also one of those things too where it's like we don't need to tell the truth to the player about how fast they're going. If they, if, you know, it feels good in the game to go super fast, we just have the background move super fast and they can still move one, you know, one unit. Or we change some config value in the game for how fast it's actually moving kind of thing. So from an initial dumb math perspective, how long do we want it to take the player to cross the playing field from one side to the other? Assuming they were at top speed from the moment they started and they had to traverse the whole thing. Is that- Well, they're never going to be able to do that, right? Like they're never going to be able to do that. They won't, but we need to start somewhere. So it's like- Right, me, the answer is one, right? How fast does the player get to go? One second. One a second, you know, one a second. No, no, no, sorry. One player, one unit, that's fine. Okay, so- I like Eric's framing of that, like you, we could choose like how long do we want it to take for a player to go at top speed from point eight- Yeah, they may never get there. From one side to the other. But we should have an idea of- What we want the minimum to be and then we can scale everything relative to those two values and we can call a unit, whatever we want a unit to be, because it's a unit. And to Derek's number that he threw out, one unit per second, that means it takes 333 seconds to cross the playing field. That's a long time. At times. Which isn't necessarily a problem, right? Because you're never going to do that. It's all about fighting their players. I mean, the biggest thing that's going to inform all of our balancing decisions about scale and size and movement and everything is our target session time, right? If somebody needs to be able to play all the other players and move on to the next ring or whatever within a certain amount of time, it's that time that we need to play. And because this is a mobile oriented casual type game or something you're playing in a browser, that time needs to be somewhere around two minutes. No, it makes sense. Yeah. And the other thing is that if we do the, so this brings up the player distribution. And so I already forgot the name of the distribution mechanism. But essentially, I think out of the gate, if we start with an algorithm that equally distributes players around, well, see, this is tricky. Because if you do equal distribution and you start the very first player in the dead center of the play area, then the next player equally distributed is at one of the edges, if you will, which means it takes two and a half minutes for the two players to reach each other. The first two players to play. I think the way we saw that is, so I think it was like our second stream. We kind of drew how the rings are concentric. But that's the, there are many sectors that make up a ring. Yeah, I know. Whatever. Yeah, so everyone will spawn on the outer side on the outer ring when they start. But the outer ring, let me think, so they're all divided up into sections of a ring, right? When players are joining, we're not gonna put, I don't think we would wanna put one person on an outer sector on the left side and then one person on the outer sector on the right side. Yeah, I needed to agree. We wanna fill them up to the optimal number of players per sector. So if, let's say there's no one on the game at all and two players join, they should join in the same sector. Yeah, so pause there real quick. 100,000 units is the sector size or the game universe size? Think of the game universe size. I think it's the sector size. No, it should be the sector size. Yeah, the game universe is made up of many multiple sectors. The gameplay field is the sector. The universe is something that the players may never see or maybe they see it as sort of gooey. Well, they may not even know about conceptually sectors because we make it transparent, right? Like a server might be in charge of a sector, but if you end up transitioning or transiting from a sector to another one, that may be transparent to you, but you did so because you crossed some literal boundary that the game knows about. Doesn't mean the player knows about the boundary, just means that there is a boundary and a transition between one thing to the other. So, again, going back to if a sector is 100,000 units, the first two players would need to be some reasonable distance apart and then you can go to equidistant distribution because otherwise you end up with players five minutes apart.  Yeah, well, one of the odds of you finding that player in a 100,000 unit circular or square box, like, so if you start here and I start here and we go this way, like, oh, boogers will never find each other. I think we would, yeah, I don't know. Well, that's another trouble we can solve with stuff like that. Mobile game design, right, is you have 30 seconds to grab a player's attention. So, they launch the game, they're into the menu, they join a session, that's already between five and 10 seconds. You have 20 seconds left to get their attention in this game, right? When they warp in, that should be, to me, that says you have under 20 seconds to get into range and fight another player. And to me, part of that, like, that, you know, the cycle of gameplay that you're gonna be experiencing, that feedback loop that we want players into is being able to destroy another player and then move on. So, to me, that even says it's not 20 seconds, it is 10 seconds. You need to be able to be within 10 seconds of another player from joining. That's where you should be on is 10 seconds away from another player. So, that's 10 units, basically, 10 ship-sized units, which is 300-ish, whatever. So, that's 3,000. So, every player should start at around, approximately 3,000 units from at least one other player. That's the outer bound. Where, who's taking notes on this? And the other thing we want to do, like, another, like, that brings up another point, which we've seen on almost every multiplayer game we've made, which is, it's actually hard. Like, when you're first starting a multiplayer game, it's hard to get a lot of people connected at the same time. And one person- We can figure that out. Yeah, but no- There's ways to, go ahead. Let me finish, yeah. So, what I'm saying is, is that, let's say there are no players connected at all, right? And one person joins, and there's no players to be here too. They still need that, what Eric was saying, about getting, grabbing their attention. Like, we can't rely only on other players being connected. We have to have other stuff going on, whether it's NPC ships flying around, or just stuff for them to do, because we have to, we can't rely on another player being there. And this is what we talked about. We need to have NPC ships no matter what, because we have to test the scalability, right? We have to be able to literally spin up, you know, 10 million players and sort of them at this game and show that working on an open shift. Maybe we want to pay for 10 million to demo it, but then we should be able to. Right. Yeah, and the NPCs, like in that case, don't have to be smart, especially starting out, right? They just need to be NPCs. They just follow a path, yeah. They can just fly in circles. They can really bomb, yeah. That's what Zorbia does. That's exactly what Zorbia does. Like all those spheres flying around are just following a path. So. Can you hear me now? Oh, so, Roddy, my audio problem was hardware mute on my headset. Oh, you had to flip the switch. Yeah, I went to the restroom to fill my water and I was like, let me put them on mute. Wait, the button is out. Oh, I've been muted. Too many points of failure. Six mute buttons. Okay, so we've got sector size of 100,000 units, initial ship size of 300 units, speed of 300 units per second to start, and a player distribution of 3,000 units. So I think those are good numbers to go with. So now the question then becomes what the hell do we do in Box2D to do any of that? And so, Roddy, I don't know if you want to share your screen and hit the Googles, but. Let me just bring open Box2D, right? So every body you create in Box2D has a number of units and size that it is, right? And then proportionally, you also have to set up its mass and its friction with the underlying two-dimensional surface, right? So there's a lot of parameters there we can tweak based on size that we want and then based upon other physics-related parameters of how we balance, like how much force do we have to apply to make it move? So there's a balance to be found there, like how does it feel when we, you know, we have a ship that looks like it does on the screen there now and we apply a small force, like perceptually we think something that big, that shouldn't, if I'm just pushing my finger on it, that thing shouldn't go anywhere. Like I should be really pushing on it hard to make it go, right? So there'll be a balance to be found between size, mass and force applied with regards to like, when I click a button and apply a thrust, if I picked up a thruster and I wanna move it over to the other side, like with little tiny thrusters shouldn't move a big ship very, very quickly, right? So yes, so given that we want a maximum speed of, to start, given that we want a maximum speed of 300 units a second, how long should it initially take somebody to get to maximum speed? The reason I asked the question this way is this is gonna back us into a force number versus our mass number, if that makes any sense. Right. Like simple algebra. It's a good calculation that works out there in order to make those things happen. Well, fun Joel, we'll make all the numbers configurable, you know, so that we can just like tweet, and really it's about what it feels. It's not about what's accurate, even though it's being physically simulated, it's a matter of playing it and tweaking it until, hey, that feels right. That's exactly what Derek was talking about, right? Yeah, so do, what do you think Derek, how long to get to top speed? Two seconds? Well, I would say the first thing that I would wanna figure out is turning, like radius and time and everything. And to me, you want to get that like feel of a massive capital ship, it shouldn't take any shorter than four seconds by default for you to turn. On your default, So make a 360 degree rotation. A 180 degree rotation. Oh, reverse. Oh, so as if somebody was coming behind you and you wanna be able to turn to engage, for example. Well, assuming you had only guns in the front, right? Or weapons in the front, but yes. Sorry, four seconds to rotate 180 degrees or eight seconds to rotate 360 degrees. But that math and those forces can actually be completely separate from thrust force. So like rotational thrusters versus forward, like accelerate, decelerate thrust, I think can be too totally different. Like if the ship has a mass of N, the force that you apply to it to get it to rotate how we want versus the force you apply to it to get it to reach top speed, those numbers can be scaled independently. Does that make any sense? Yes. Yeah, and I would say from that, like the players should be able to accelerate in half of that amount of time, which puts us at two seconds. So four seconds to rotate, but two seconds to reach top speed. Okay, so if it takes two seconds to reach 300 units per second, what is the physics on that one? What is it? Four sequels, mass times velocity. That acceleration was 150 meters a second. Yeah, I don't remember anymore. 100 units a second. So, okay, so we've got acceleration of 150 in a second. I need to pull up like just basics physics here. Physics body formulas. So with an acceleration of 150 units a second, what is the mass, what do we want to choose as a starting mass number? And then what do we want to do as, that'll tell us the actual thrust force.  But what book did you just grab off the shelf? Mm-hmm. Physics for games. And second one. I have that one too. Yeah, they've been gathering dust a little while, but it sounds like I need to review. Worse is mass times acceleration. So we just need a mass number or a mass. Yeah, and I don't remember off the top of my head with the easy numbers to work with in box 2DR, but I mean, I would pick one for everything, right? Like easy, small numbers, if ever possible. Well, it would be the starting mass of the ship because remember that changes to your ship change its mass. So- Right, exactly. And if we want to just use a round number and just say a hundred, like, it doesn't matter really because we're just going to scale the, we're either going to scale the force or scale the mass later. So- And for balance, for every number, I prefer things under 20 if we can help it. And the visual representation is independent of those numbers. Well, so if we choose a mass number under 20, we're going to get a monstrous force number. If we choose a big mass number, we'll get a starting force number. So which would you rather be under 20 if you want force to be 20 or mass to be 20? That's a question. What's the difference? How do you, what? Starting mass should be, I think. Starting mass should be which? A low number, because that makes more sense when you're- So if acceleration- When you're balancing stuff, like the starting mass. So if acceleration is 150 and starting mass is 20, that means that the initial force capacity is 3000 mass units per unit second. We need to pick some real values here. So if we stick with meters, then it's 150 meters a second is the acceleration. If we do the mass as tons, then it's 20 tons times 150 meters a second, which I don't know what unit of force would be at that point. I need a pencil and paper to actual scribble. There's only so much that I can completely do in my head. A blank piece of paper. It is a blank piece of paper. And I have a literal pencil. It's an actual pencil. So that's 20- That's tons of force and you just convert that to whatever unit you'd like to use if you want to use something else. Well, I don't know what box 2D uses sort of out of the box. All depends on what you said. Well, if we want to stick in metric, what's a ton in kilograms? A thousand kilograms. Is it a thousand? It's a metric ton versus an imperial ton. Oh, well, if we do 20 metric tons. Yeah, a thousand kilograms. It's a thousand kilograms as a metric ton. So then it's 20,000 kilograms is the mass. Or, you know, we can say 20,000, but it's really 20. So 3,000 metric ton years per second is the force. There's a question. Does this work with VR controllers? No, no, no.  If there's a browser VR plug-in interface thing, it could work. There's a web VR, right? Web VR, yeah. There you go. So you have just signed up, Mr. Person, for running the web VR client. Get to it. We'll see you in another Johnny TV. So here's a note, since we're talking about tons of ships. Tons of what? Tons of ships, yeah, no, ship tons. So I was curious like what a lead dangerous ship. So one thing a lead dangerous is really good is like having accurate scale. And their small ships start at 35 tons, 35 metric tons for a small ship. Yeah, but again, like we're, I mean, good for them. We are still in the process of figuring out. So here's the deal. I agree with what you're saying in the sense that, yes, lead dangerous has done a very excellent job of accurate physics, sort of giving you the feel of space travel, suspending a little disbelief of what the capabilities of physics are and the whole jumping between stars and stuff like that. But that's like, that was a design trope that they came out of the box with. I don't think they backed into like, oh, we've got really realistic sizes and whatever. It was like, we're gonna make a realistic space ship. Yeah, yeah. So this game is not like, I don't think realistic space sim is a design trope for us. So we're just kind of throwing out units here to get to an initial scale. And again, I don't think we're gonna expose any of these numbers to the player. Like they'll just be literal numbers. Like you're moving at 150, you're moving at 400. Like what does it mean? I don't know, who cares? That is it doesn't matter. Like do we even need to show them anything or does the experience of the game tell them that they're going fast or slow? Like I don't know if we're there yet. If it's simple. So back to Roddy. Now that we have a unit of mass of 20,000 kilograms and a force and some sizes or whatever, like do you wanna pull up some box 2D stuff so we can figure out how to put some of these numbers in there? Yeah, it's not difficult. I just did that here. And I can now increase the font size via click and scroll wheel. Hell yeah. That didn't by default was turned off. Oh, brilliant. Let us make it as hard as possible to show you anything. Yes. Yeah, so we'll do this and then we've got about 30 minutes. We'll go back to Derek and maybe talk a little bit about how do we prevent people from getting to the borders? So yeah, like, so originally the stuff that was set up if you think back to the early demo, essentially what we had was circles, right? Even though now we have like a boxy ship but you can basically put like a circle shape in or you can put in a box shape. So that's update the back end use boxes rather than circles, which isn't really a big deal. But you can see here like your stuff has a density your stuff has a friction. It has a restitution. That's restitution. So like that's the shape. And then there's a body definition. See what's in the body definition? I don't even remember. Is that restitution like a bounce? Yeah. How bouncy it is? Yeah, I think so. That's how boxy we are. I'm pretty sure that we don't want ships bouncing off each other and maybe we do, I don't know. One, yeah. One of the reasons, I'm not sure if this is totally the reason, but I feel like we are the reason that the game client and the server don't really play well together is I feel like they should be running the same physics engine. But the client needs no physics because it is merely drawing what is happening. I mean, not if you want to have a good user experience. If you want to do predict the physics and stuff. Yeah. It helps to have the same engine in both. Right. But we're not there yet. That's right. We're not there yet. There is a JavaScript box 2D, I'm pretty sure. Yeah. There is a JavaScript box 2D. It was one of the first things I looked up. Yeah. Yeah. And likewise in the original client, the original client, the C-sharp implementation in Unity was box 2D based. Even though it wasn't identical, they were based upon the same principles and the same structure, right? Yeah. And I mean, we'll get to that for sure. Yeah, we want that because that's what it's going to make the game client feel smooth. If you're only relying on the server updates, like it's going to be very sensitive to any kind of lag or any kind of, you know, because it'll feel janky. That's right. Yeah. And we'll have work to basically polish that experience in a number of ways. So, Roddy, I was thinking about just pulling up the actual box 2D, like docs. Oh, sure. Yeah, I've got that. Is there a box 2D like editor where you can just put in inputs and like just bounce stuff around? There's a number of them over the years, but I don't know that any of them took off as like the official box 2D like that. Oh, like a simulator editor? Yeah. Yeah, where you can just... There's a number of good examples that compile and run out of the box. Like with a spider that walks across the screen and all kinds of stuff. You can easily tweak values and test things out, right? Like what I did when I was developing Gigglewater, I built like a little interface. We could just tweak the values directly and just take the settings from the GUI and just manipulate it on the fly, right? But that's one of the reasons why I think like good dough and unity and unreal and stuff that have GUIs are so powerful, right? So in an ideal world, what would happen with this game server is that it would really become a more generic simulation server where we'd basically write a front. We'd write an integration in the front end in unity or unreal or good dough. Good dough is a great target. And we'd build a little interface there where we showed what was going on like through the idea, through the game development environment even though all the values were being fed from the back end, right? And ideally like you'd have an interface in good dough where we say, hey, I want to launch this thing on OpenShift. We have a little OpenShift interface. Enter your credentials.  You drop your token in, click launch me a box 2D simulation, okay? Off it goes, it launches the simulation. It talks back and forth and starts receiving the updates through the messaging mechanism. And it's all visual to you right there.  And then when it comes time to launching your game, you can check on the status of your world. You can send world updates. And then there's a world format of some sort that the game server runs. And then the game client is just basically saying this player joins and then the back end knows what that means and what to do with regards to the simulation, right? That sounds cool, but also like very far down the road. Yes, that's also correct. That's right. A little ways from now. Yeah, so back to the box 2D docs. So right, so here's the test bed like integrated, right? So this little thing right here is an IAM GUI interface built in. What you're showing us is still C-Lion. Of course it is. I'm sharing my screen, new share. That's okay. All right, this one should be the right one, I think. Right? So yeah, so like it has this little test bed thingy where there's an IAM GUI plugin essentially to run your GUI, which is this awesome little native CC++ GUI implementation, like in a couple of, I think it might even be single header, where you can look at your different shapes and stuff that you have and test them out and test like, hey, what does it mean if I set a force to whatever or what does it mean if I change the mass or change the friction, right? So there kind of isn't like a box 2D world editor per se, at least not that's directly with box 2D as far as I know. There may be some third-party ones out there. Oh, there you go, I see. Derek just dropped one in, right? Sorry, where? Yeah, in the Discord. So like there's a JavaScript web demo of the same thing, right? To test this stuff out. So I don't think you can see it on my screen now because I haven't switched to new share. So this is what Derek was just showing our FoxBox 2D web demo. Be something bouncing around. Yeah, so the key part here that would be different for us is that the simulation happens on the backend. So we need to connect up the messaging as well, right? Cause we're gonna want something like this so that we can rapidly iterate the values that we want to update. Cause what we don't want to have to do is go in and hard code some values in the game server, build a game server, build a container, rerun the game server, and then test the client, right? I think we can drastically, I like what you're saying. I think we can simplify it by like a bajillion times over. Put a flag in the server as an environment variable that says, you can tell me about yourself player. And then put a flag in the web client for a debug mode that allows you to set yourself as whatever. So when you change. So that information has to be sent from the client to the server. Yeah, it's another protobuf or something. That's right, exactly, that's correct. Either way, that still is way simpler than like, to me what you're describing is like almost like building a second client. And it's like, no, just put this debug mode in the main client, you know, and then it's like, okay, like my player's mass is now 10,000 units and not 20,000 units. Right, and that's the simplest form of having a full blown editor built within the client. Right, yeah, like why do an editor when we could just, you have to do almost the same amount of work to do the editor. So just put the editor in the client. Yes. Call it a day. Exactly. And it's worth noting that this is a whole lot of commercial game engines sort of handle it too. And that also introduces kind of that concept of like running a scripting language so you can actually change the game logic as it's running. Right. And not have to, you know, edit core server code. Yeah. Like JavaScript. Or Lua. Or Lua, yes. So that being said, back to the box 2D docs. Where do we put stuff like mass, force, et cetera? So the body gets fine. I'm just trying to remember. So in this case, like you can see, create a dynamic box, which is a polygon shape, set it as a box. It has dimensions one by one. So what is F here? Is that just float because it's C? F is just a float. Yeah, exactly. It's just a unit. Okay, so it's technically unit lists. Yes. And I can't remember the assumptions that box 2D makes, if that means, I think the assumption from box 2D's design point of view, maybe that the 1.0 F here is representation of meter. It says somewhere in it. It does, yep. I'm looking for it. Right. So box 2D is tuned for meters, kilograms and seconds. Right? Yeah. It says it extends to be in meters. And this is it. Well, that's good that we've done everything already in meters and kilograms and seconds. That's right, exactly. Okay, so a position of 1.1 is that a meter? Yes. So it's at one meter from zero and one meter from zero? Yes, in the x-y direction. Cool. So where's like on the dynamic body setting stuff like mass? So there's the body and there's the fixture, I think is how this used to work. Create fixture based on the ground box, which was the polygon shape. Right, but we don't have the ground box because we're in space? Well, relatively speaking, we're still a 2D shape and underneath the 2D shape is a plane. And between the shape and the plane can be friction, for example, which would be one way of handling, slowing things down or maybe if you went through and that'd be all of a sudden, then you could see- Well, that would be two bodies interacting that would cause friction. But yeah, there's no, the ground- Right, but you would simply fake it but you would simply fake it by saying, hey, you just changed the friction of the shape potentially, right? Yes, got it. Yeah, and so by default, like there's a default gravity in the minus y direction that you set, right? Disabled, yeah. But it still doesn't say- Right, and you set that on the world by default and like they use it here, minus 10, for example, right? Which is close enough to 9.8. Right, exactly. Right, so I saw something down below, it mentioned mass, but it didn't actually set mass. Right, so using the fixture definition we can now create the fixture. This automatically updates the mass of the body. You can add as many fixtures as you want, each one contributes to the total mass. So I'm trying to remember how this works. So literally doesn't, you don't set the mass, you set the density and something else and that determines the mass. Yeah, I think that's, this automatically updates, but I don't know if that's the only way to do it because in this case you're saying that a body has a number of fixtures, right? So you have to think in terms of rigid body physics, right? So you might have a square and that square can have a joint and on that joint can be attached a circle. Right, but we're gonna start with one fixture because this is like down. We are, that's right. And I'm just trying to remember because it's been a while since I've set this up, right? So I think you have to look at the created fixture docks or the docks of the fixture. The modules, man, the collision module shapes. Dynamics. Circle polygon in shapes, change shapes. So polygon shapes. Yeah, but I don't think this is. No, this is just having shapes so it works, right? Yeah, I think you want the dynamics module. Right, so bodies and fixtures. Scanning down here. Mass data. It's like two thirds of the way down. See it? Yep. Body has a mass and a center has a mass and a rotational inertia. Yes. Right, so like if we looked in the original code, which I'm not gonna switch back to C-line here now, but what we would see is that the way in which the force is applied is applied to the center, right? So because we just wanted to be handling simple movement at the time by sticks is how it started out. Like there was no separate thrusters or anything like that, right? Whereas if we had a box like this and we attached the thruster to the like the bottom right hand corner, there's a very specific place where that force should be acting on the body, right? Right, because it's literally a physics engine. And so if you apply force at a distance from the center of mass, that influences the rotation with respect to all the other ones. And in fact, if you don't apply the force off center from the mass, off center from the center, I know that sounds weird. If you don't apply force off center from the center, you can't rotate the object. The only way to in this rotation is to apply force off center. Or the other thing you can do in box theory, I'm pretty sure if I remember correctly is turn it set kinematic mode on and then basically animate it yourself, right? Because sometimes exact physics simulation not necessarily desired, right? So you can turn it off and fake it. And then you can reorient it like what its state is with the state that you have induced other ones. So it looks like what we just need to do is if you can actually pull the code up in your browser instead of having to worry about came back to the house. Wasn't expecting a visitor. Okay, so in the place where we create the pod, we would just add a set mass on the body. Or on the fixture, whichever one says is the correct place. It actually doesn't say there's a correct place. It says you can set it on the body or if you want to set it on fixtures, you can also set it on the body. On the body, you set mass data, right? So, right, so that's the thing it can, like the way we're looking forward here, like in the beginning, we just set a mass data, we got a box, we wanted to give a mass, we're trying to figure out the really basics. But what's gonna happen is that over time, when we pick up, let's say we're this box, we're in a skate pod, we're going along, we run into a thruster. The thruster has a mass. So we are now the pod mass plus the thruster mass. And the thruster has been attached to the pod in a given location, right? And so we can physically simulate all that. And at that point, we don't want to calculate the mass and the effect of having a mass in the lower right-hand corner of the pod ourselves. That's what the physics simulation is for. Yeah, for sure. Right? So in the beginning, we'll set the mass data, but then afterwards, once we're starting to join things together and like attach them with a certain amount. We would let it use the derived mass data for the body, which is the sum of all the fixture mass. Right, that's right, exactly. And we may have joints in between like the joint may be able to take a certain amount of force before it breaks.  Makes sense. All that kind of stuff, right? What's a mass data look like? Float mass, the mass of the shape, usually in kilograms. The center of the shape centroid, relative shape origin. Zero. And the rotational inertia of the shape about the local origin. I assume zero for now? We would start out with zero. Cool, all right. So somebody write that down. So it'll become obvious once we go to do this and actually once we get the input connected again to make things move, like we'll need to adjust all these numbers. Yeah, because I had been playing with the JavaScript of like, can we change the force? And it's like, it's still moving at a snail's pace. And I'm like, this doesn't make sense. So kilograms meters seconds. So in this case, the mass of the object is, what should we call it? 20,000. Because we're going with 20 metric tons. Okay, 20 tons, right? Yeah, so can you go back to the game code and find where we're applying force, which is gonna be probably in one of the updated movie things? There's the K position. Yeah, this is, right there. C-882-vec-move-50, bottom, all the way down. Yes, right there. So is that, is this the force that's being applied? Calculating the forces. Five force to center. So I'm assuming that's the force of 50. So, okay, so the 50, I'm just thinking back to when I wrote this. So the 50 is a multiplying factor to the move and the move X and Y is about, right. So the move X and Y is what's handed in from the client, right? And the original client was like, think two sticks, right? So each stick has minus one deposit of one in each direction, right? Well, no longer. Well, no longer. I'm just saying this is how this code was originally written, right? So this is why, so we take in the stick magnitude and multiply by a multiplicative factor. At full stick, it was 50. That's right, exactly. That's correct. Because that's what felt right at the time. Sure, yeah, yeah, right. It's gonna have to be scaled. So we would actually end up, for the sake of simplicity to begin the game, we're doing some kind of WASD control. W is the thrusters on, not W is the thrusters not on. Right, right, it's either one or zero, right? Yeah, you know, suspend disbelief and S is like just as much force but in the opposite direction. Right, that's right. Who knows how it works, that's just how it works. It's the vacuum physics rocket blaster. Right, I mean, in our final implementation, it should be a master touch base, right? It won't be WASD, but it doesn't mean to be deployed. You click somewhere, it goes there and does what you want or... Or it just follows the pointer. Follows the mouse, yeah. Or whatever, yeah. Yeah. Yeah, how far the pointer is away is how much force you're applying or whatever. Maybe a little circle and the max on there. Yeah, so from the numbers and taking notes perspective, the force units are meters per second? Yes, I think that's great. Well, the force units would be newtons. Right, but a newton is just a meter per second, isn't it, a kilogram meter per second? A kilogram meter per second, yeah, I think that's right. So if we have, so we have to actually get this into the real unit. So it's 20,000 times 150, so it's 300,000, right? I'm bad at terrible at small number math, and I'm 20,000. That's one, two, three, one, two, three. So that's three million kilogram meters per second. So that number is probably gonna be three million. Okay. I'm assuming. For our given scale. At the current scale of 100,000 units, 300 units for the ship, or three. Which makes sense, right? Because if you've got something that's 20,000 kilograms, it takes a significant force to apply it to move it, right? Yeah. So, okay, so it's gonna be three million is the force. And then we probably also need to figure out we may actually need to start out with a fix, with a second fixture or something, because in order to induce the rotation, we need a different force for the rotation to get that 180 degrees in four seconds thing. Right, to be able to test that out, you mean? And be able to- Well, just to make it work, like to make it actually function, we're gonna need to be able to apply, because right now this apply force to center quite literally is what it says. Apply force to center. That's right, that's right up down, right? Yeah, yeah, yeah. And so we don't wanna do that because we want the ship to rotate, not to move just sideways, literally. So, do you wanna go back to Box2D and take a look at like where it would go? Right, so you can apply to a point, let's do a search for apply force, or you can apply a rotational force, for example. So apply force in general, need to probably take a vector, right? So you have a vector, which is the force and the point at which it applies to the body, right? So if you've got the square, there's a certain point where the force will apply to it in order to cause the rotation, right? So like, if we pictured a pod with two thrusters, for example, and each thruster was on the bottom of the pod, for example, if you operated the left thruster, there's a force acting here and it's gonna cause a rotation, right? Yeah, I think for the purposes of stupid simplicity, we want to apply rotational force at the central axis at the end of the ship. So 150 meters away from the center of the body. And right on the side. Yeah, so if we think about the sausage is pointed up, the center is here, this is negative 150 Y, we always want to apply rotational force. If they're pressing left, then we apply right force at the end, at the blood end. And if they're pressing right, then we apply it at the... Right, that makes sense. So that would be... So we sort of have to change the, if you go back to the code, we're actually gonna have to add some different logic here because we might have to tweak the move cue basically because now it's gonna be, both of these are for now. Is the thruster on or is it off? That's right, that's correct. Which thruster is on? Okay, the forward-back thruster is on, then we apply force to center of either a positive X along the body or negative X. Right, so essentially we'll check to see which key is down and apply the force to the appropriate location. Well, it could be both, right? It could be both, yeah. We're already sending whatever, and so it's just up to us to decode what that move command actually did. Although, honestly, I'm not even sure it may still be sending it as one key at a time, but it's sending it rapidly in sequence. So it's like up and left and up and left. Yeah, I think that's probably correct. It's like a thousand messages of up and left and then as soon as you let go, it's just the message. Right, that's correct. Well, is that how it would work with a pointer? Like, let me think. With a pointer, no. Like if you had a pointer, we would need to basically figure it out. You need a vector. That's right, exactly. You'd have to figure out the math and tell it where to go and then it just needs to figure out how to get there. Which is why on-screen joystick, even for mobile might be the easiest. Like on-screen, WASD. Right.  Like we can start out simple and make a dance here. Cool. I think we got pretty far with our thoughts and our game behind us. I think we certainly have next steps, right? Which is the most important thing. So one thing I wanted to think back and circle back to, Derek, you had wanted to, or you had an idea or something, like you're never gonna be able to reach the edge of the sector. Cause one of the things is that Fox2D has no concept of size. Like the playing space is theoretically infinite unless you bound it somehow with physical borders. We didn't want to pac-man it in the sense that if you went off the right edge of the screen, you shouldn't magically appear on the left edge of the screen. And so what was your thought there on a design? That all players are going to have an intrinsic force applied to them that has them all moving towards each other. And that will increase as time goes on to help push those players to that, you know? In two minutes I have faced all other players, yeah. And instead of having a battle royale scenario where it's like, oh, the borders are closing in on me, oh no, it's just happening in the background automatically. It's transparent to the player, the forces that are involved in keeping the game active and interesting. Oh, that's okay. So the players are being pulled toward the center. Yeah. Well, towards each other it can be just a center, however you want to handle it. Right, cause if every player is around in a circle and they're all being pulled toward the center, then they're all getting closer to each other. Yeah. Yeah, that sounds like an amazing design idea. It also sounds like it's really hard to implement. Cause it's like, we have to figure out the force to apply to every player, such that they move towards every other player. I mean, or changing. And they don't have the ability to move away from the other player fast enough to ever reach the boundary. It's gravity. It's like, you need gravity, but it needs to be centered on a point. I mean, the physics engine should be able to have that, right? Like, can you have gravity? And you can have a place where the gravity is applied towards. The challenge is, if gravity is greater than the force the ship can exert, if you do nothing, you pull towards the center very fast. Otherwise, you are much like a trout swimming upstream in that at best you can hope to not move in the negative direction of gravity. And so it's like, the way that I would do it is not even touch the physics engine, just adjust the X and Y position of every single player over time very slowly. So, and you would just calculate, what's the distance to the origin, the center of the universe? And you would increase that in a bell curve, essentially that would accelerate over the course of two minutes in an exponentially growing fashion. Yeah, I mean, essentially, yeah. So I think the thing is there, I think we need to, like the physics engine has its own state with regards to what a body's position is, right? Yeah, and you do like body desktop position. We know that, I think you can, right? Yeah, but I think we can just tell it. Like, hey, I know what you thought. You have to feed it back in. It's manually, kinematically updated where things are. No, I'm not, either we're talking past each other or we're talking about different things. So the physics calculation would still apply. All Derek is suggesting is that we do some math to figure out a number, which is an offset. And on every game loop, we just remove that offset from the player's position before the physics calculation occurs. So you were at position 100 comma 100 and physics wise, your position would have moved away 101 comma 100, but because of magic game stuff, you actually didn't even move at all. You're still at 100, 100, because we took one X away from you. Whereas I think that's what Derek's getting at. So if the position changes and we're keeping the position of the physics emulation and the position that we keep for the player character in sync, then like position is an output of physics simulation based on mass forces and velocity and acceleration, right? Physics isn't positions and output. So if we intentionally avoid the simulation and set the position, we have to let the simulation know. Hey, we've forcefully changed this. Go back and recalculate everything. We shouldn't require any recalculation. It will, because you've updated the simulation and changed the position. So where that position- Which it has to do on every frame anyway, depending on what hurts we're running the physics simulation at. Right. I don't know that that's- Normally it's gonna put, I think it's out here because I've done it a few times. So with Box2D, this will be my third game with Box2D as the choice for the physics simulation. So I'm relatively sure. So if after the physics loop, you just give it a new position, it's gonna recalculate the physics? That seems- On the next loop through though. On the next loop through, not on this frame, on the next frame. Right, but it's gonna calculate the physics the same way based on- That's good because all the bodies could be different. Like you could now have two bodies in collision, meaning that physically, like if you have collision-bounding boxes and they were two pixels apart and you've moved the position to be four pixels to the left, they're now two pixels in collision and something forcefully has to happen there. There has to be some resolution- We're actually saying the same thing from different perspectives. Yes. So it's recalculating or it is calculating the physics based on the new information, but that doesn't change Other than collision, it doesn't necessarily change anything about the physics calculation. And so what I mean is like, if you're traveling in a straight line with no friction and no gravity and nothing- Oh, right, that's true, no, that's correct, yes. And we just tell you suddenly that you're two pixels further, nothing changes on the next physics calc, you just start from two- Unless there's some collision of some sort- Right, right, ignoring- Because you can be hard collision or it could be like a friction-type collision where there's a callback and we're applying friction and that means you're slowing down because like maybe- Totally makes sense, yeah. Maybe you moved into a merge if you were like on a- And you moved from like pavement to merge. I don't think that's a problem that it needs to do that. No, it's just something we have to consider. Yeah, right, no, no, no. So Derek, that could work, what you're suggesting, just like a negative exponential decay on pole towards the center that is simply just we move you. That could work, it's worth a shot, right? It's probably the simplest thing we could do, right? And you should always try the simplest thing you can do first. Yeah, we're not changing the play field, we're just moving you. Right, yeah. And this will be transparent to a player because their ship will always be in the center of the screen, right? So to from a player's perspective, all other ships are moving towards them in fashion. Fashion. Yes, we, there's sort of a weird implication of an end state though with this trope because- Well, yeah, they have to kill each other. But what I'm saying is like- At some point, you can no longer allow new players into the sector because if you just keep allowing new players into the sector, but the pole rate to the center increases over time, the last player to join basically like joins and then instantly is like smashed into all the other play. You know what I'm saying? There's gotta be some like, okay, no new players because it's like the last person has joined and then the rate of increase towards the center slowly increases. Yeah, and to me it would be like new players got new players can join in like, rolling window of 30 seconds, right? For 30 seconds, we allow new players to join or whatever and get into that combat within 10 seconds, right? Cause they spun, you know, 10 seconds away from somebody. And after that point, you have to go into a new section. The challenge there though is given the game design trope of every time you destroy a player, you can pick up detritus, which makes you bigger, better, whatever. That means that if somehow I got lucky and smashed like four players in the first 10 seconds, I'm already at a humongous advantage to the player that joins at second number 28. Well, that's where we talked about like, when do we want the upgrades to happen? Like during gameplay or like between sections? And to me, like that's two birds with one stone is like in between sections, while you're warping right into the next section, which is just a cue for, you know, spinning up a new section for you to fight in. That's when you get the drag and drop and add your, you know, new turrets or a new shield generator or a new laser to the front of your ship or something. Yeah, and if it's truly Battle Royale-esque, then only the last player in the sector gets to win anything. So then we don't have to worry about, that makes sense. I wouldn't say so, right? Like anytime, like if you get destroyed, right? You get to win, you know, whatever you have up to that point, right? And go into the next section with it.  Yeah, that makes sense. We just need to figure out a story element that explains why you picked up stuff, but got destroyed, but somehow get to use the stuff that you picked up. Oh yeah, this is what I'm here for. We'll worry about that. Cool, all right. I think that's it for today. Anybody have any parting thoughts? This is really probably another cool one I thought. I think we have a lot of stuff here to do work on before the next session. Yeah, we got to figure out the control sending. Well yeah, so we need to, so it sounds like the issue on the web client is you're just going to figure out why, well, we need to figure out the communication between the client and the server. Why is it not moving the player and the server? Yeah, and then on the server side purely, we just need to change the implementation of forward-backwards thrust, rotational thrust versus the messages that come in and actually apply mass to the players. And then the third piece is implementing that player distribution algorithm of roughly 3,000 units apart in all directions, add-in for an item kind of thing. Some parting thoughts from me are thanks everyone who's watching the stream for joining us and thanks Tony TV for all the commentary in the chat. TV keeping us alive. All right everyone, that is it for today. Thanks so much. We will talk to you again next month. And bye. See you folks. All right, everybody. See ya.